1998-06-18 16:25:41 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-06 03:40:37 +00: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-06-18 16:25:41 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00: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-06-18 16:25:41 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
1999-11-06 03:40:37 +00:00
|
|
|
* Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2000-04-17 14:40:46 +00:00
|
|
|
* Steve Clark <buster@netscape.com>
|
|
|
|
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
2000-09-04 21:44:48 +00:00
|
|
|
* L. David Baron <dbaron@fas.harvard.edu>
|
1998-06-18 16:25:41 +00:00
|
|
|
*/
|
1999-03-19 23:05:56 +00:00
|
|
|
#include "nsCOMPtr.h"
|
1998-11-16 17:11:12 +00:00
|
|
|
#include "nsBlockFrame.h"
|
1998-12-05 16:02:08 +00:00
|
|
|
#include "nsBlockReflowContext.h"
|
1998-12-08 21:43:15 +00:00
|
|
|
#include "nsBlockBandData.h"
|
1998-12-05 16:02:08 +00:00
|
|
|
#include "nsBulletFrame.h"
|
|
|
|
#include "nsLineBox.h"
|
1999-04-20 00:27:43 +00:00
|
|
|
#include "nsInlineFrame.h"
|
1998-09-15 00:19:49 +00:00
|
|
|
#include "nsLineLayout.h"
|
1998-06-18 16:25:41 +00:00
|
|
|
#include "nsPlaceholderFrame.h"
|
|
|
|
#include "nsStyleConsts.h"
|
1998-06-18 23:16:00 +00:00
|
|
|
#include "nsHTMLIIDs.h"
|
1998-06-24 17:52:42 +00:00
|
|
|
#include "nsCSSRendering.h"
|
1999-11-02 23:42:52 +00:00
|
|
|
#include "nsIFrameManager.h"
|
1998-06-18 16:25:41 +00:00
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIReflowCommand.h"
|
1998-09-23 20:10:40 +00:00
|
|
|
#include "nsISpaceManager.h"
|
1998-06-18 16:25:41 +00:00
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsIView.h"
|
1998-07-10 20:30:23 +00:00
|
|
|
#include "nsIFontMetrics.h"
|
1998-09-23 02:25:26 +00:00
|
|
|
#include "nsHTMLParts.h"
|
|
|
|
#include "nsHTMLAtoms.h"
|
|
|
|
#include "nsHTMLValue.h"
|
2000-12-30 19:22:22 +00:00
|
|
|
#include "nsIDOMEvent.h"
|
1998-09-23 20:10:40 +00:00
|
|
|
#include "nsIHTMLContent.h"
|
1998-11-14 21:01:26 +00:00
|
|
|
#include "prprf.h"
|
1998-12-09 05:30:17 +00:00
|
|
|
#include "nsLayoutAtoms.h"
|
1998-11-05 19:33:01 +00:00
|
|
|
#include "nsITextContent.h"
|
1999-07-14 17:26:20 +00:00
|
|
|
#include "nsStyleChangeList.h"
|
1999-08-31 04:32:13 +00:00
|
|
|
#include "nsISizeOfHandler.h"
|
1999-08-24 21:51:47 +00:00
|
|
|
#include "nsIFocusTracker.h"
|
|
|
|
#include "nsIFrameSelection.h"
|
1999-10-06 22:05:23 +00:00
|
|
|
#include "nsSpaceManager.h"
|
1999-10-15 23:35:10 +00:00
|
|
|
#include "prenv.h"
|
|
|
|
#include "plstr.h"
|
1999-01-05 23:01:54 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
1999-10-19 23:04:19 +00:00
|
|
|
static PRBool gLamePaintMetrics;
|
|
|
|
static PRBool gLameReflowMetrics;
|
1999-10-15 23:35:10 +00:00
|
|
|
static PRBool gNoisy;
|
1999-10-19 23:04:19 +00:00
|
|
|
static PRBool gNoisyDamageRepair;
|
1999-10-15 23:35:10 +00:00
|
|
|
static PRBool gNoisyMaxElementSize;
|
1999-10-19 23:04:19 +00:00
|
|
|
static PRBool gNoisyReflow;
|
1999-10-29 14:34:53 +00:00
|
|
|
static PRBool gReallyNoisyReflow;
|
1999-10-15 23:35:10 +00:00
|
|
|
static PRBool gNoisySpaceManager;
|
1999-10-19 23:04:19 +00:00
|
|
|
static PRBool gVerifyLines;
|
1999-10-29 14:34:53 +00:00
|
|
|
static PRBool gDisableResizeOpt;
|
1999-10-15 23:35:10 +00:00
|
|
|
|
|
|
|
struct BlockDebugFlags {
|
|
|
|
const char* name;
|
|
|
|
PRBool* on;
|
|
|
|
};
|
|
|
|
|
|
|
|
static BlockDebugFlags gFlags[] = {
|
|
|
|
{ "reflow", &gNoisyReflow },
|
1999-10-29 14:34:53 +00:00
|
|
|
{ "really-noisy-reflow", &gReallyNoisyReflow },
|
1999-10-15 23:35:10 +00:00
|
|
|
{ "max-element-size", &gNoisyMaxElementSize },
|
|
|
|
{ "space-manager", &gNoisySpaceManager },
|
1999-10-19 23:04:19 +00:00
|
|
|
{ "verify-lines", &gVerifyLines },
|
|
|
|
{ "damage-repair", &gNoisyDamageRepair },
|
|
|
|
{ "lame-paint-metrics", &gLamePaintMetrics },
|
|
|
|
{ "lame-reflow-metrics", &gLameReflowMetrics },
|
1999-10-29 14:34:53 +00:00
|
|
|
{ "disable-resize-opt", &gDisableResizeOpt },
|
1999-10-15 23:35:10 +00:00
|
|
|
};
|
|
|
|
#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
|
|
|
|
|
|
|
|
static void
|
|
|
|
ShowDebugFlags()
|
|
|
|
{
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n");
|
1999-10-15 23:35:10 +00:00
|
|
|
BlockDebugFlags* bdf = gFlags;
|
|
|
|
BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
|
|
|
|
for (; bdf < end; bdf++) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" %s\n", bdf->name);
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma seperated list of flag\n");
|
|
|
|
printf("names (no whitespace)\n");
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
InitDebugFlags()
|
|
|
|
{
|
|
|
|
static PRBool firstTime = PR_TRUE;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = PR_FALSE;
|
|
|
|
char* flags = PR_GetEnv("GECKO_BLOCK_DEBUG_FLAGS");
|
|
|
|
if (flags) {
|
|
|
|
PRBool error = PR_FALSE;
|
|
|
|
for (;;) {
|
|
|
|
char* cm = PL_strchr(flags, ',');
|
|
|
|
if (cm) *cm = '\0';
|
|
|
|
|
|
|
|
PRBool found = PR_FALSE;
|
|
|
|
BlockDebugFlags* bdf = gFlags;
|
|
|
|
BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
|
|
|
|
for (; bdf < end; bdf++) {
|
|
|
|
if (PL_strcasecmp(bdf->name, flags) == 0) {
|
|
|
|
*(bdf->on) = PR_TRUE;
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame: setting %s debug flag on\n", bdf->name);
|
1999-10-15 23:35:10 +00:00
|
|
|
gNoisy = PR_TRUE;
|
|
|
|
found = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
error = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cm) break;
|
|
|
|
*cm = ',';
|
|
|
|
flags = cm + 1;
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
ShowDebugFlags();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-06-11 22:14:33 +00:00
|
|
|
#undef NOISY_FIRST_LINE // enables debug output for first-line specific layout
|
|
|
|
#undef REALLY_NOISY_FIRST_LINE // enables extra debug output for first-line specific layout
|
|
|
|
#undef NOISY_FIRST_LETTER // enables debug output for first-letter specific layout
|
|
|
|
#undef NOISY_MAX_ELEMENT_SIZE // enables debug output for max element size computation
|
|
|
|
#undef NOISY_MAXIMUM_WIDTH // enables debug output for max width computation
|
|
|
|
#undef NOISY_KIDXMOST // enables debug output for aState.mKidXMost computation
|
|
|
|
#undef NOISY_FLOATER // enables debug output for floater reflow (the in/out metrics for the floated block)
|
1998-11-17 22:28:51 +00:00
|
|
|
#undef NOISY_FLOATER_CLEARING
|
2000-06-11 22:14:33 +00:00
|
|
|
#undef NOISY_FINAL_SIZE // enables debug output for desired width/height computation, once all children have been reflowed
|
1999-03-16 19:36:00 +00:00
|
|
|
#undef NOISY_REMOVE_FRAME
|
2000-06-11 22:14:33 +00:00
|
|
|
#undef NOISY_COMBINED_AREA // enables debug output for combined area computation
|
1999-03-27 01:22:14 +00:00
|
|
|
#undef NOISY_VERTICAL_MARGINS
|
2000-06-11 22:14:33 +00:00
|
|
|
#undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested
|
|
|
|
#undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete"
|
|
|
|
#undef NOISY_SPACEMANAGER // enables debug output for space manager use, useful for analysing reflow of floaters and positioned elements
|
2000-10-30 04:10:44 +00:00
|
|
|
#undef NOISY_BLOCK_INVALIDATE // enables debug output for all calls to invalidate
|
2000-09-11 20:46:44 +00:00
|
|
|
#undef REALLY_NOISY_REFLOW // some extra debug info
|
1999-10-15 23:35:10 +00:00
|
|
|
|
1998-11-05 19:33:01 +00:00
|
|
|
#endif
|
|
|
|
|
2000-06-14 23:15:59 +00:00
|
|
|
#define FIX_BUG_38157
|
|
|
|
#define FIX_BUG_37657
|
|
|
|
|
|
|
|
// add in a sanity check for absurdly deep frame trees. See bug 42138
|
|
|
|
// can't just use IsFrameTreeTooDeep() because that method has side effects we don't want
|
|
|
|
#define MAX_DEPTH_FOR_LIST_RENUMBERING 200 // 200 open displayable tags is pretty unrealistic
|
2000-06-11 22:14:33 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//----------------------------------------------------------------------
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Debugging support code
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
1998-12-05 16:02:08 +00:00
|
|
|
static PRInt32 gNoiseIndent;
|
|
|
|
static const char* kReflowCommandType[] = {
|
|
|
|
"ContentChanged",
|
|
|
|
"StyleChanged",
|
|
|
|
"PullupReflow",
|
|
|
|
"PushReflow",
|
|
|
|
"CheckPullupReflow",
|
1999-03-05 04:21:32 +00:00
|
|
|
"ReflowDirty",
|
1998-12-05 16:02:08 +00:00
|
|
|
"UserDefined",
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_FIRST_LINE
|
|
|
|
static void
|
|
|
|
DumpStyleGeneaology(nsIFrame* aFrame, const char* gap)
|
|
|
|
{
|
|
|
|
fputs(gap, stdout);
|
1999-03-05 04:21:32 +00:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": ");
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIStyleContext* sc;
|
1999-03-05 04:21:32 +00:00
|
|
|
aFrame->GetStyleContext(&sc);
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != sc) {
|
|
|
|
nsIStyleContext* psc;
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p ", sc);
|
1998-12-05 16:02:08 +00:00
|
|
|
psc = sc->GetParent();
|
|
|
|
NS_RELEASE(sc);
|
|
|
|
sc = psc;
|
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REFLOW_STATUS_COVERAGE
|
|
|
|
static void
|
1999-02-09 17:31:33 +00:00
|
|
|
RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-02-09 17:31:33 +00:00
|
|
|
static PRUint32 record[2];
|
1998-12-05 16:02:08 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
// 0: child-is-block
|
|
|
|
// 1: child-is-inline
|
1998-12-05 16:02:08 +00:00
|
|
|
PRIntn index = 0;
|
|
|
|
if (!aChildIsBlock) index |= 1;
|
|
|
|
|
|
|
|
// Compute new status
|
|
|
|
PRUint32 newS = record[index];
|
|
|
|
if (NS_INLINE_IS_BREAK(aFrameReflowStatus)) {
|
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
|
|
|
|
newS |= 1;
|
|
|
|
}
|
|
|
|
else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) {
|
|
|
|
newS |= 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newS |= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_FRAME_IS_NOT_COMPLETE(aFrameReflowStatus)) {
|
|
|
|
newS |= 8;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newS |= 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log updates to the status that yield different values
|
|
|
|
if (record[index] != newS) {
|
|
|
|
record[index] = newS;
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("record(%d): %02x %02x\n", index, record[0], record[1]);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1999-03-23 04:28:20 +00:00
|
|
|
inline void CombineRects(const nsRect& r1, nsRect& r2)
|
|
|
|
{
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord xa = r2.x;
|
|
|
|
nscoord ya = r2.y;
|
|
|
|
nscoord xb = xa + r2.width;
|
|
|
|
nscoord yb = ya + r2.height;
|
1999-03-23 04:28:20 +00:00
|
|
|
nscoord x = r1.x;
|
|
|
|
nscoord y = r1.y;
|
|
|
|
nscoord xmost = x + r1.width;
|
|
|
|
nscoord ymost = y + r1.height;
|
1999-05-13 00:55:38 +00:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
r2.x = xa;
|
|
|
|
r2.y = ya;
|
|
|
|
r2.width = xb - xa;
|
|
|
|
r2.height = yb - ya;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
class nsBlockReflowState {
|
1998-12-05 16:02:08 +00:00
|
|
|
public:
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
1999-04-20 00:27:43 +00:00
|
|
|
nsIPresContext* aPresContext,
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockFrame* aFrame,
|
2000-01-03 04:32:13 +00:00
|
|
|
const nsHTMLReflowMetrics& aMetrics,
|
|
|
|
PRBool aBlockMarginRoot);
|
1998-09-23 20:10:40 +00:00
|
|
|
|
|
|
|
~nsBlockReflowState();
|
|
|
|
|
|
|
|
/**
|
1999-04-03 18:59:01 +00:00
|
|
|
* Update our state when aLine is skipped over during incremental
|
|
|
|
* reflow.
|
1998-09-23 20:10:40 +00:00
|
|
|
*/
|
1999-04-03 18:59:01 +00:00
|
|
|
void RecoverStateFrom(nsLineBox* aLine, PRBool aPrevLineWasClean);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the available reflow space for the current y coordinate. The
|
|
|
|
* available space is relative to our coordinate system (0,0) is our
|
|
|
|
* upper left corner.
|
|
|
|
*/
|
|
|
|
void GetAvailableSpace() {
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Verify that the caller setup the coordinate system properly
|
|
|
|
nscoord wx, wy;
|
|
|
|
mSpaceManager->GetTranslation(wx, wy);
|
|
|
|
NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY),
|
|
|
|
"bad coord system");
|
|
|
|
#endif
|
|
|
|
mBand.GetAvailableSpace(mY - BorderPadding().top, mAvailSpaceRect);
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
mAvailSpaceRect.x, mAvailSpaceRect.y,
|
|
|
|
mAvailSpaceRect.width, mAvailSpaceRect.height,
|
|
|
|
mBand.GetTrapezoidCount());
|
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void GetAvailableSpace(nscoord aY) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Verify that the caller setup the coordinate system properly
|
|
|
|
nscoord wx, wy;
|
|
|
|
mSpaceManager->GetTranslation(wx, wy);
|
|
|
|
NS_ASSERTION((wx == mSpaceManagerX) && (wy == mSpaceManagerY),
|
|
|
|
"bad coord system");
|
|
|
|
#endif
|
|
|
|
mBand.GetAvailableSpace(aY - BorderPadding().top, mAvailSpaceRect);
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("GetAvailableSpace: band=%d,%d,%d,%d count=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
mAvailSpaceRect.x, mAvailSpaceRect.y,
|
|
|
|
mAvailSpaceRect.width, mAvailSpaceRect.height,
|
|
|
|
mBand.GetTrapezoidCount());
|
|
|
|
}
|
1999-04-03 18:59:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
void InitFloater(nsLineLayout& aLineLayout,
|
|
|
|
nsPlaceholderFrame* aPlaceholderFrame);
|
1998-11-10 18:03:29 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
void AddFloater(nsLineLayout& aLineLayout,
|
|
|
|
nsPlaceholderFrame* aPlaceholderFrame,
|
1998-12-15 04:20:54 +00:00
|
|
|
PRBool aInitialReflow);
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-03-31 04:10:27 +00:00
|
|
|
PRBool CanPlaceFloater(const nsRect& aFloaterRect, PRUint8 aFloats);
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
void PlaceFloater(nsFloaterCache* aFloaterCache,
|
1999-10-14 23:10:03 +00:00
|
|
|
PRBool* aIsLeftFloater);
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
void PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aFloaters);
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void ClearFloaters(nscoord aY, PRUint8 aBreakType);
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
PRBool ClearPastFloaters(PRUint8 aBreakType);
|
|
|
|
|
2000-01-22 01:16:50 +00:00
|
|
|
PRBool IsLeftMostChild(nsIPresContext* aPresContext, nsIFrame* aFrame);
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool IsAdjacentWithTop() const {
|
1999-03-05 04:21:32 +00:00
|
|
|
return mY == mReflowState.mComputedBorderPadding.top;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsMargin& BorderPadding() const {
|
|
|
|
return mReflowState.mComputedBorderPadding;
|
|
|
|
}
|
|
|
|
|
2000-06-11 22:14:33 +00:00
|
|
|
const nsMargin& Margin() const {
|
|
|
|
return mReflowState.mComputedMargin;
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
void UpdateMaxElementSize(const nsSize& aMaxElementSize) {
|
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
|
|
|
nsSize oldSize = mMaxElementSize;
|
|
|
|
#endif
|
|
|
|
if (aMaxElementSize.width > mMaxElementSize.width) {
|
|
|
|
mMaxElementSize.width = aMaxElementSize.width;
|
|
|
|
}
|
|
|
|
if (aMaxElementSize.height > mMaxElementSize.height) {
|
|
|
|
mMaxElementSize.height = aMaxElementSize.height;
|
|
|
|
}
|
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
|
|
|
if ((mMaxElementSize.width != oldSize.width) ||
|
|
|
|
(mMaxElementSize.height != oldSize.height)) {
|
1999-07-14 17:26:20 +00:00
|
|
|
nsFrame::IndentBy(stdout, mBlock->GetDepth());
|
1999-04-03 18:59:01 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE == mReflowState.availableWidth) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("PASS1 ");
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": old max-element-size=%d,%d new=%d,%d\n",
|
1999-04-03 18:59:01 +00:00
|
|
|
oldSize.width, oldSize.height,
|
|
|
|
mMaxElementSize.width, mMaxElementSize.height);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1999-12-30 04:15:45 +00:00
|
|
|
void UpdateMaximumWidth(nscoord aMaximumWidth) {
|
|
|
|
if (aMaximumWidth > mMaximumWidth) {
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockReflowState::UpdateMaximumWidth block %p caching max width %d\n", mBlock, aMaximumWidth);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-12-30 04:15:45 +00:00
|
|
|
mMaximumWidth = aMaximumWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
void RecoverVerticalMargins(nsLineBox* aLine,
|
|
|
|
PRBool aApplyTopMargin,
|
|
|
|
nscoord* aTopMarginResult,
|
|
|
|
nscoord* aBottomMarginResult);
|
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
void ComputeBlockAvailSpace(nsIFrame* aFrame,
|
|
|
|
nsSplittableType aSplitType,
|
|
|
|
const nsStyleDisplay* aDisplay,
|
|
|
|
nsRect& aResult);
|
1999-04-03 18:59:01 +00:00
|
|
|
|
|
|
|
void RecoverStateFrom(nsLineBox* aLine,
|
|
|
|
PRBool aApplyTopMargin,
|
1999-07-14 15:16:56 +00:00
|
|
|
nscoord aDeltaY,
|
|
|
|
nsRect* aDamageRect);
|
1999-04-03 18:59:01 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
void AdvanceToNextLine() {
|
|
|
|
mLineNumber++;
|
|
|
|
}
|
|
|
|
|
1999-10-14 23:10:03 +00:00
|
|
|
PRBool IsImpactedByFloater() {
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n",
|
2000-03-22 23:19:10 +00:00
|
|
|
this, mBand.GetFloaterCount());
|
|
|
|
#endif
|
1999-10-14 23:10:03 +00:00
|
|
|
return mBand.GetFloaterCount();
|
|
|
|
}
|
|
|
|
|
1999-10-19 23:04:19 +00:00
|
|
|
nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock);
|
|
|
|
|
|
|
|
void FreeLineBox(nsLineBox* aLine);
|
|
|
|
|
1999-10-21 20:43:48 +00:00
|
|
|
void StoreMaxElementSize(nsIFrame* aFloater, const nsSize& aSize) {
|
|
|
|
mBand.StoreMaxElementSize(mPresContext, aFloater, aSize);
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
// This state is the "global" state computed once for the reflow of
|
|
|
|
// the block.
|
|
|
|
|
|
|
|
// The block frame that is using this object
|
|
|
|
nsBlockFrame* mBlock;
|
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
nsIPresContext* mPresContext;
|
1999-04-03 18:59:01 +00:00
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsHTMLReflowState& mReflowState;
|
|
|
|
|
1998-09-23 20:10:40 +00:00
|
|
|
nsISpaceManager* mSpaceManager;
|
1999-04-03 18:59:01 +00:00
|
|
|
|
|
|
|
// The coordinates within the spacemanager where the block is being
|
|
|
|
// placed <b>after</b> taking into account the blocks border and
|
|
|
|
// padding. This, therefore, represents the inner "content area" (in
|
|
|
|
// spacemanager coordinates) where child frames will be placed,
|
|
|
|
// including child blocks and floaters.
|
1998-09-28 18:50:59 +00:00
|
|
|
nscoord mSpaceManagerX, mSpaceManagerY;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// XXX get rid of this
|
1998-12-05 16:02:08 +00:00
|
|
|
nsReflowStatus mReflowStatus;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
nscoord mBottomEdge;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The content area to reflow child frames within. The x/y
|
|
|
|
// coordinates are known to be mBorderPadding.left and
|
|
|
|
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
|
|
|
// if the container reflowing this frame has given the frame an
|
|
|
|
// unconstrained area.
|
|
|
|
nsSize mContentArea;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
//----------------------------------------
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// This state is "running" state updated by the reflow of each line
|
|
|
|
// in the block. This same state is "recovered" when a line is not
|
|
|
|
// dirty and is passed over during incremental reflow.
|
|
|
|
|
|
|
|
// The current line being reflowed
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* mCurrentLine;
|
1999-04-03 18:59:01 +00:00
|
|
|
|
|
|
|
// The previous line just reflowed
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* mPrevLine;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The current Y coordinate in the block
|
|
|
|
nscoord mY;
|
|
|
|
|
|
|
|
// The available space within the current band.
|
1998-12-08 21:43:15 +00:00
|
|
|
nsRect mAvailSpaceRect;
|
1999-02-23 19:32:00 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The maximum x-most of each line
|
|
|
|
nscoord mKidXMost;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The combined area of all floaters placed so far
|
|
|
|
nsRect mFloaterCombinedArea;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-10-14 23:10:03 +00:00
|
|
|
// For unconstained-width reflow, we keep the right floaters
|
|
|
|
// combined area stored seperately.
|
|
|
|
PRBool mHaveRightFloaters;
|
|
|
|
nsRect mRightFloaterCombinedArea;
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
nsFloaterCacheFreeList mFloaterCacheFreeList;
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// Previous child. This is used when pulling up a frame to update
|
|
|
|
// the sibling list.
|
|
|
|
nsIFrame* mPrevChild;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The next immediate child frame that is the target of an
|
|
|
|
// incremental reflow command. Once that child has been reflowed we
|
|
|
|
// null this slot out.
|
|
|
|
nsIFrame* mNextRCFrame;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
|
|
|
// The previous child frames collapsed bottom margin value.
|
|
|
|
nscoord mPrevBottomMargin;
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The current next-in-flow for the block. When lines are pulled
|
|
|
|
// from a next-in-flow, this is used to know which next-in-flow to
|
|
|
|
// pull from. When a next-in-flow is emptied of lines, we advance
|
|
|
|
// this to the next next-in-flow.
|
|
|
|
nsBlockFrame* mNextInFlow;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The current band data for the current Y coordinate
|
|
|
|
nsBlockBandData mBand;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
// Temporary line-reflow state. This state is used during the reflow
|
|
|
|
// of a given line, but doesn't have meaning before or after.
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// The list of floaters that are "current-line" floaters. These are
|
|
|
|
// added to the line after the line has been reflowed, to keep the
|
|
|
|
// list fiddling from being N^2.
|
|
|
|
nsFloaterCacheFreeList mCurrentLineFloaters;
|
|
|
|
|
|
|
|
// The list of floaters which are "below current-line"
|
|
|
|
// floaters. These are reflowed/placed after the line is reflowed
|
|
|
|
// and placed. Again, this is done to keep the list fiddling from
|
|
|
|
// being N^2.
|
|
|
|
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
1999-04-03 18:59:01 +00:00
|
|
|
|
|
|
|
nsSize mMaxElementSize;
|
1999-12-30 04:15:45 +00:00
|
|
|
nscoord mMaximumWidth;
|
1999-08-27 21:45:37 +00:00
|
|
|
|
|
|
|
nscoord mMinLineHeight;
|
|
|
|
|
|
|
|
PRInt32 mLineNumber;
|
2000-04-17 14:40:46 +00:00
|
|
|
|
|
|
|
// block reflow state flags
|
|
|
|
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
|
|
|
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
|
|
|
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
|
|
|
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
|
|
|
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
|
|
|
#define BRS_NOWRAP 0x00000020
|
|
|
|
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
|
|
|
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
|
|
|
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
|
|
|
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
|
|
|
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
|
|
|
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
|
|
|
|
|
|
|
PRInt16 mFlags;
|
|
|
|
|
|
|
|
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
|
|
|
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
|
|
|
if (aValue) { // set flag
|
|
|
|
mFlags |= aFlag;
|
|
|
|
}
|
|
|
|
else { // unset flag
|
|
|
|
mFlags &= ~aFlag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool GetFlag(PRUint32 aFlag) const
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
|
|
|
PRBool result = (mFlags & aFlag);
|
|
|
|
if (result) return PR_TRUE;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// XXX This is vile. Make it go away
|
|
|
|
void
|
1998-11-10 18:03:29 +00:00
|
|
|
nsLineLayout::InitFloater(nsPlaceholderFrame* aFrame)
|
|
|
|
{
|
1999-08-27 21:45:37 +00:00
|
|
|
mBlockRS->InitFloater(*this, aFrame);
|
1998-11-10 18:03:29 +00:00
|
|
|
}
|
|
|
|
void
|
1998-09-23 20:10:40 +00:00
|
|
|
nsLineLayout::AddFloater(nsPlaceholderFrame* aFrame)
|
|
|
|
{
|
1999-08-27 21:45:37 +00:00
|
|
|
mBlockRS->AddFloater(*this, aFrame, PR_FALSE);
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
1999-04-20 00:27:43 +00:00
|
|
|
nsIPresContext* aPresContext,
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockFrame* aFrame,
|
2000-01-03 04:32:13 +00:00
|
|
|
const nsHTMLReflowMetrics& aMetrics,
|
|
|
|
PRBool aBlockMarginRoot)
|
1999-04-03 18:59:01 +00:00
|
|
|
: mBlock(aFrame),
|
|
|
|
mPresContext(aPresContext),
|
1999-03-05 04:21:32 +00:00
|
|
|
mReflowState(aReflowState),
|
1999-04-03 18:59:01 +00:00
|
|
|
mNextRCFrame(nsnull),
|
1999-08-27 21:45:37 +00:00
|
|
|
mPrevBottomMargin(0),
|
2000-04-17 14:40:46 +00:00
|
|
|
mLineNumber(0),
|
|
|
|
mFlags(0)
|
1998-11-14 21:01:26 +00:00
|
|
|
{
|
2000-01-18 15:36:36 +00:00
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
|
|
|
|
2000-01-03 04:32:13 +00:00
|
|
|
if (aBlockMarginRoot) {
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
|
|
|
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
2000-01-13 02:05:31 +00:00
|
|
|
if (0 != aReflowState.mComputedBorderPadding.top) {
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
2000-01-13 02:05:31 +00:00
|
|
|
}
|
|
|
|
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
2000-01-13 02:05:31 +00:00
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
|
|
|
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 03:41:03 +00:00
|
|
|
mSpaceManager = aReflowState.mSpaceManager;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
2000-01-18 15:36:36 +00:00
|
|
|
NS_ASSERTION( nsnull != mSpaceManager, "SpaceManager should be set in nsBlockReflowState" );
|
|
|
|
if( nsnull != mSpaceManager ) {
|
|
|
|
// Translate into our content area and then save the
|
|
|
|
// coordinate system origin for later.
|
|
|
|
mSpaceManager->Translate(borderPadding.left, borderPadding.top);
|
|
|
|
mSpaceManager->GetTranslation(mSpaceManagerX, mSpaceManagerY);
|
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
mReflowStatus = NS_FRAME_COMPLETE;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
mPresContext = aPresContext;
|
1999-02-24 04:48:08 +00:00
|
|
|
mBlock->GetNextInFlow((nsIFrame**)&mNextInFlow);
|
1998-12-05 16:02:08 +00:00
|
|
|
mKidXMost = 0;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
// Compute content area width (the content area is inside the border
|
|
|
|
// and padding)
|
1999-07-20 03:41:03 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
|
|
|
mContentArea.width = aReflowState.mComputedWidth;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-03-05 04:21:32 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
1998-12-05 16:02:08 +00:00
|
|
|
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
|
|
|
// Choose a width based on the content (shrink wrap width) up
|
|
|
|
// to the maximum width
|
2000-06-11 22:14:33 +00:00
|
|
|
// Part 2 of a possible fix for 38157
|
|
|
|
#ifdef FIX_BUG_38157
|
|
|
|
const nsMargin& margin = Margin();
|
|
|
|
nscoord availContentWidth = aReflowState.availableWidth;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != availContentWidth) {
|
|
|
|
availContentWidth -= (borderPadding.left + borderPadding.right) +
|
|
|
|
(margin.left + margin.right);
|
|
|
|
}
|
|
|
|
mContentArea.width = PR_MIN(aReflowState.mComputedMaxWidth, availContentWidth);
|
|
|
|
#else
|
2000-01-03 04:32:13 +00:00
|
|
|
mContentArea.width = aReflowState.mComputedMaxWidth;
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
1999-03-05 04:21:32 +00:00
|
|
|
nscoord lr = borderPadding.left + borderPadding.right;
|
|
|
|
mContentArea.width = aReflowState.availableWidth - lr;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
mHaveRightFloaters = PR_FALSE;
|
1998-12-30 17:50:00 +00:00
|
|
|
|
1999-03-05 04:21:32 +00:00
|
|
|
// Compute content area height. Unlike the width, if we have a
|
|
|
|
// specified style height we ignore it since extra content is
|
|
|
|
// managed by the "overflow" property. When we don't have a
|
|
|
|
// specified style height then we may end up limiting our height if
|
|
|
|
// the availableHeight is constrained (this situation occurs when we
|
|
|
|
// are paginated).
|
1999-03-23 04:28:20 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
1999-04-03 18:59:01 +00:00
|
|
|
// We are in a paginated situation. The bottom edge is just inside
|
|
|
|
// the bottom border and padding. The content area height doesn't
|
|
|
|
// include either border or padding edge.
|
|
|
|
mBottomEdge = aReflowState.availableHeight - borderPadding.bottom;
|
|
|
|
mContentArea.height = mBottomEdge - borderPadding.top;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// When we are not in a paginated situation then we always use
|
|
|
|
// an constrained height.
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
1999-04-03 18:59:01 +00:00
|
|
|
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
1999-03-05 04:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mY = borderPadding.top;
|
1999-04-03 18:59:01 +00:00
|
|
|
mBand.Init(mSpaceManager, mContentArea);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
mPrevChild = nsnull;
|
1999-02-09 17:31:33 +00:00
|
|
|
mCurrentLine = nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
mPrevLine = nsnull;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
|
|
|
const nsStyleText* styleText;
|
|
|
|
mBlock->GetStyleData(eStyleStruct_Text,
|
|
|
|
(const nsStyleStruct*&) styleText);
|
|
|
|
switch (styleText->mWhiteSpace) {
|
|
|
|
case NS_STYLE_WHITESPACE_PRE:
|
|
|
|
case NS_STYLE_WHITESPACE_NOWRAP:
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_NOWRAP, PR_TRUE);
|
1999-03-05 04:21:32 +00:00
|
|
|
break;
|
|
|
|
default:
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_NOWRAP, PR_FALSE);
|
1999-03-05 04:21:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("BRS: setting compute-MES to %d\n", (nsnull != aMetrics.maxElementSize));
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-03-05 04:21:32 +00:00
|
|
|
mMaxElementSize.SizeTo(0, 0);
|
2000-04-17 14:40:46 +00:00
|
|
|
SetFlag(BRS_COMPUTEMAXWIDTH,
|
|
|
|
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
1999-12-30 04:15:45 +00:00
|
|
|
mMaximumWidth = 0;
|
1999-03-05 04:21:32 +00:00
|
|
|
|
1999-11-24 06:03:41 +00:00
|
|
|
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
1999-09-09 20:53:32 +00:00
|
|
|
aReflowState.rendContext,
|
1999-08-27 21:45:37 +00:00
|
|
|
aReflowState.frame);
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsBlockReflowState::~nsBlockReflowState()
|
1998-09-23 20:10:40 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
// Restore the coordinate system
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
|
|
|
mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsLineBox*
|
|
|
|
nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
|
|
|
|
PRInt32 aCount,
|
|
|
|
PRBool aIsBlock)
|
|
|
|
{
|
2000-03-12 03:00:51 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
mPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
|
|
|
|
return NS_NewLineBox(shell, aFrame, aCount, aIsBlock);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
|
|
|
|
{
|
|
|
|
if (aLine) {
|
2000-03-12 03:00:51 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
mPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
|
|
|
aLine->Destroy(presShell);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// Compute the amount of available space for reflowing a block frame
|
|
|
|
// at the current Y coordinate. This method assumes that
|
|
|
|
// GetAvailableSpace has already been called.
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-08-27 21:45:37 +00:00
|
|
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
|
|
|
nsSplittableType aSplitType,
|
|
|
|
const nsStyleDisplay* aDisplay,
|
1999-04-03 18:59:01 +00:00
|
|
|
nsRect& aResult)
|
1998-09-23 20:10:40 +00:00
|
|
|
{
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
2000-04-17 14:40:46 +00:00
|
|
|
mBand.List();
|
|
|
|
#endif
|
1999-09-16 19:56:36 +00:00
|
|
|
aResult.y = mY;
|
2000-04-17 14:40:46 +00:00
|
|
|
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
1999-04-03 18:59:01 +00:00
|
|
|
? NS_UNCONSTRAINEDSIZE
|
|
|
|
: mBottomEdge - mY;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
1999-08-27 21:45:37 +00:00
|
|
|
|
2000-09-15 06:20:07 +00:00
|
|
|
/* bug 18445: treat elements mapped to display: block such as text controls
|
|
|
|
* just like normal blocks */
|
|
|
|
PRBool treatAsNotSplittable=PR_FALSE;
|
|
|
|
nsCOMPtr<nsIAtom>frameType;
|
|
|
|
aFrame->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
if (frameType)
|
|
|
|
{ // text controls are splittable, so make a special case here
|
|
|
|
if (nsLayoutAtoms::textInputFrame == frameType.get())
|
|
|
|
treatAsNotSplittable = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FRAME_SPLITTABLE_NON_RECTANGULAR == aSplitType || // normal blocks
|
|
|
|
NS_FRAME_NOT_SPLITTABLE == aSplitType || // things like images mapped to display: block
|
|
|
|
PR_TRUE == treatAsNotSplittable) // text input controls mapped to display: block (special case)
|
2000-09-11 20:46:44 +00:00
|
|
|
{
|
1999-09-16 19:56:36 +00:00
|
|
|
if (mBand.GetFloaterCount()) {
|
|
|
|
// Use the float-edge property to determine how the child block
|
|
|
|
// will interact with the floater.
|
2001-01-25 02:58:12 +00:00
|
|
|
const nsStyleSpacing* spacing;
|
|
|
|
aFrame->GetStyleData(eStyleStruct_Spacing,
|
|
|
|
(const nsStyleStruct*&) spacing);
|
|
|
|
switch (spacing->mFloatEdge) {
|
1999-09-16 19:56:36 +00:00
|
|
|
default:
|
2000-03-22 23:19:10 +00:00
|
|
|
case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters
|
1999-09-16 19:56:36 +00:00
|
|
|
// The child block will flow around the floater. Therefore
|
|
|
|
// give it all of the available space.
|
|
|
|
aResult.x = borderPadding.left;
|
2000-04-17 14:40:46 +00:00
|
|
|
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
1999-09-16 19:56:36 +00:00
|
|
|
? NS_UNCONSTRAINEDSIZE
|
|
|
|
: mContentArea.width;
|
2000-03-22 23:19:10 +00:00
|
|
|
break;
|
|
|
|
case NS_STYLE_FLOAT_EDGE_BORDER:
|
1999-09-16 19:56:36 +00:00
|
|
|
case NS_STYLE_FLOAT_EDGE_PADDING:
|
|
|
|
{
|
|
|
|
// The child block's border should be placed adjacent to,
|
|
|
|
// but not overlap the floater(s).
|
|
|
|
nsMargin m(0, 0, 0, 0);
|
2001-01-25 02:58:12 +00:00
|
|
|
spacing->GetMargin(m); // XXX percentage margins
|
|
|
|
if (NS_STYLE_FLOAT_EDGE_PADDING == spacing->mFloatEdge) {
|
1999-09-16 19:56:36 +00:00
|
|
|
// Add in border too
|
|
|
|
nsMargin b;
|
2001-01-25 02:58:12 +00:00
|
|
|
spacing->GetBorder(b);
|
1999-09-16 19:56:36 +00:00
|
|
|
m += b;
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine left edge
|
|
|
|
if (mBand.GetLeftFloaterCount()) {
|
|
|
|
aResult.x = mAvailSpaceRect.x + borderPadding.left - m.left;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aResult.x = borderPadding.left;
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine width
|
2000-04-17 14:40:46 +00:00
|
|
|
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
1999-09-16 19:56:36 +00:00
|
|
|
aResult.width = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (mBand.GetRightFloaterCount()) {
|
|
|
|
if (mBand.GetLeftFloaterCount()) {
|
|
|
|
aResult.width = mAvailSpaceRect.width + m.left + m.right;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aResult.width = mAvailSpaceRect.width + m.right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aResult.width = mAvailSpaceRect.width + m.left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_STYLE_FLOAT_EDGE_MARGIN:
|
|
|
|
{
|
|
|
|
// The child block's margins should be placed adjacent to,
|
|
|
|
// but not overlap the floater.
|
|
|
|
aResult.x = mAvailSpaceRect.x + borderPadding.left;
|
|
|
|
aResult.width = mAvailSpaceRect.width;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Since there are no floaters present the float-edge property
|
|
|
|
// doesn't matter therefore give the block element all of the
|
|
|
|
// available space since it will flow around the floater itself.
|
|
|
|
aResult.x = borderPadding.left;
|
2000-04-17 14:40:46 +00:00
|
|
|
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
1999-09-16 19:56:36 +00:00
|
|
|
? NS_UNCONSTRAINEDSIZE
|
|
|
|
: mContentArea.width;
|
|
|
|
}
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-09-16 19:56:36 +00:00
|
|
|
// The frame is clueless about the space manager and therefore we
|
|
|
|
// only give it free space. An example is a table frame - the
|
|
|
|
// tables do not flow around floaters.
|
|
|
|
aResult.x = mAvailSpaceRect.x + borderPadding.left;
|
|
|
|
aResult.width = mAvailSpaceRect.width;
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
PRBool
|
|
|
|
nsBlockReflowState::ClearPastFloaters(PRUint8 aBreakType)
|
|
|
|
{
|
|
|
|
nscoord saveY, deltaY;
|
|
|
|
|
|
|
|
PRBool applyTopMargin = PR_FALSE;
|
|
|
|
switch (aBreakType) {
|
|
|
|
case NS_STYLE_CLEAR_LEFT:
|
|
|
|
case NS_STYLE_CLEAR_RIGHT:
|
|
|
|
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
|
|
|
// Apply the previous margin before clearing
|
|
|
|
saveY = mY + mPrevBottomMargin;
|
|
|
|
ClearFloaters(saveY, aBreakType);
|
1999-09-16 19:56:36 +00:00
|
|
|
#ifdef NOISY_FLOATER_CLEARING
|
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": ClearPastFloaters: mPrevBottomMargin=%d saveY=%d oldY=%d newY=%d deltaY=%d\n",
|
1999-09-16 19:56:36 +00:00
|
|
|
mPrevBottomMargin, saveY, saveY - mPrevBottomMargin, mY,
|
|
|
|
mY - saveY);
|
|
|
|
#endif
|
1999-04-03 18:59:01 +00:00
|
|
|
|
|
|
|
// Determine how far we just moved. If we didn't move then there
|
|
|
|
// was nothing to clear to don't mess with the normal margin
|
|
|
|
// collapsing behavior. In either case we need to restore the Y
|
|
|
|
// coordinate to what it was before the clear.
|
|
|
|
deltaY = mY - saveY;
|
|
|
|
if (0 != deltaY) {
|
|
|
|
// Pretend that the distance we just moved is a previous
|
|
|
|
// blocks bottom margin. Note that GetAvailableSpace has been
|
|
|
|
// done so that the available space calculations will be done
|
|
|
|
// after clearing the appropriate floaters.
|
|
|
|
//
|
|
|
|
// What we are doing here is applying CSS2 section 9.5.2's
|
|
|
|
// rules for clearing - "The top margin of the generated box
|
|
|
|
// is increased enough that the top border edge is below the
|
|
|
|
// bottom outer edge of the floating boxes..."
|
|
|
|
//
|
|
|
|
// What this will do is cause the top-margin of the block
|
|
|
|
// frame we are about to reflow to be collapsed with that
|
|
|
|
// distance.
|
|
|
|
mPrevBottomMargin = deltaY;
|
|
|
|
mY = saveY;
|
|
|
|
|
|
|
|
// Force margin to be applied in this circumstance
|
|
|
|
applyTopMargin = PR_TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Put aState.mY back to its original value since no clearing
|
|
|
|
// happened. That way the previous blocks bottom margin will
|
|
|
|
// be applied properly.
|
|
|
|
mY = saveY - mPrevBottomMargin;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return applyTopMargin;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recover the collapsed vertical margin values for aLine. Note that
|
|
|
|
// the values are not collapsed with aState.mPrevBottomMargin, nor are
|
|
|
|
// they collapsed with each other when the line height is zero.
|
|
|
|
void
|
|
|
|
nsBlockReflowState::RecoverVerticalMargins(nsLineBox* aLine,
|
|
|
|
PRBool aApplyTopMargin,
|
|
|
|
nscoord* aTopMarginResult,
|
|
|
|
nscoord* aBottomMarginResult)
|
|
|
|
{
|
|
|
|
if (aLine->IsBlock()) {
|
|
|
|
// Update band data
|
|
|
|
GetAvailableSpace();
|
|
|
|
|
|
|
|
// Setup reflow state to compute the block childs top and bottom
|
|
|
|
// margins
|
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
1999-08-27 21:45:37 +00:00
|
|
|
nsRect availSpaceRect;
|
|
|
|
const nsStyleDisplay* display;
|
|
|
|
frame->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&) display);
|
1999-04-03 18:59:01 +00:00
|
|
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
|
|
|
frame->IsSplittable(splitType);
|
1999-08-27 21:45:37 +00:00
|
|
|
ComputeBlockAvailSpace(frame, splitType, display, availSpaceRect);
|
1999-04-03 18:59:01 +00:00
|
|
|
nsSize availSpace(availSpaceRect.width, availSpaceRect.height);
|
1999-11-24 06:03:41 +00:00
|
|
|
nsHTMLReflowState reflowState(mPresContext, mReflowState,
|
1999-04-03 18:59:01 +00:00
|
|
|
frame, availSpace);
|
|
|
|
|
|
|
|
// Compute collapsed top margin
|
|
|
|
nscoord topMargin = 0;
|
|
|
|
if (aApplyTopMargin) {
|
|
|
|
topMargin =
|
|
|
|
nsBlockReflowContext::ComputeCollapsedTopMargin(mPresContext,
|
|
|
|
reflowState);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute collapsed bottom margin
|
1999-07-20 03:41:03 +00:00
|
|
|
nscoord bottomMargin = reflowState.mComputedMargin.bottom;
|
1999-04-03 18:59:01 +00:00
|
|
|
bottomMargin =
|
|
|
|
nsBlockReflowContext::MaxMargin(bottomMargin,
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->GetCarriedOutBottomMargin());
|
1999-04-03 18:59:01 +00:00
|
|
|
*aTopMarginResult = topMargin;
|
|
|
|
*aBottomMarginResult = bottomMargin;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// XXX_ib
|
|
|
|
*aTopMarginResult = 0;
|
|
|
|
*aBottomMarginResult = 0;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
|
|
|
PRBool aApplyTopMargin,
|
1999-07-14 15:16:56 +00:00
|
|
|
nscoord aDeltaY,
|
|
|
|
nsRect* aDamageRect)
|
1999-04-03 18:59:01 +00:00
|
|
|
{
|
|
|
|
// Make the line being recovered the current line
|
|
|
|
mCurrentLine = aLine;
|
|
|
|
|
|
|
|
// Update aState.mPrevChild as if we had reflowed all of the frames
|
|
|
|
// in this line.
|
|
|
|
mPrevChild = aLine->LastChild();
|
|
|
|
|
1999-12-30 04:15:45 +00:00
|
|
|
// Recover mKidXMost and mMaxElementSize
|
1999-04-03 18:59:01 +00:00
|
|
|
nscoord xmost = aLine->mBounds.XMost();
|
|
|
|
if (xmost > mKidXMost) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (CRAZY_WIDTH(xmost)) {
|
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": WARNING: xmost:%d\n", xmost);
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
2000-06-11 22:14:33 +00:00
|
|
|
#ifdef NOISY_KIDXMOST
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p RecoverState block %p aState.mKidXMost=%d\n", this, mBlock, xmost);
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
1999-04-03 18:59:01 +00:00
|
|
|
mKidXMost = xmost;
|
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaxElementWidth);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-08-28 00:39:55 +00:00
|
|
|
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
|
|
|
}
|
1999-04-03 18:59:01 +00:00
|
|
|
|
1999-12-30 04:15:45 +00:00
|
|
|
// If computing the maximum width, then update mMaximumWidth
|
2000-04-17 14:40:46 +00:00
|
|
|
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockReflowState::RecoverStateFrom block %p caching max width %d\n", mBlock, aLine->mMaximumWidth);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-12-30 04:15:45 +00:00
|
|
|
UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// The line may have clear before semantics.
|
1999-10-12 23:24:22 +00:00
|
|
|
if (aLine->IsBlock() && aLine->HasBreak()) {
|
1999-04-03 18:59:01 +00:00
|
|
|
// Clear past floaters before the block if the clear style is not none
|
1999-10-12 23:24:22 +00:00
|
|
|
aApplyTopMargin = ClearPastFloaters(aLine->GetBreakType());
|
1999-09-16 19:56:36 +00:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": RecoverStateFrom: y=%d child ", mY);
|
1999-09-16 19:56:36 +00:00
|
|
|
nsFrame::ListTag(stdout, aLine->mFirstChild);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" has clear of %d => %s, mPrevBottomMargin=%d\n", aLine->mBreakType,
|
1999-09-16 19:56:36 +00:00
|
|
|
aApplyTopMargin ? "applyTopMargin" : "nope", mPrevBottomMargin);
|
|
|
|
#endif
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recover mPrevBottomMargin and calculate the line's new Y
|
1999-04-03 21:54:00 +00:00
|
|
|
// coordinate (newLineY)
|
|
|
|
nscoord newLineY = mY;
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
1999-10-15 23:35:10 +00:00
|
|
|
if (aLine->IsBlock()) {
|
|
|
|
if ((0 == aLine->mBounds.height) && (0 == lineCombinedArea.height)) {
|
2000-06-29 22:03:42 +00:00
|
|
|
// The line's top and bottom margin values need to be collapsed
|
|
|
|
// with the mPrevBottomMargin to determine a new
|
|
|
|
// mPrevBottomMargin value.
|
|
|
|
nscoord topMargin, bottomMargin;
|
|
|
|
RecoverVerticalMargins(aLine, aApplyTopMargin,
|
|
|
|
&topMargin, &bottomMargin);
|
|
|
|
nscoord m = nsBlockReflowContext::MaxMargin(bottomMargin,
|
|
|
|
mPrevBottomMargin);
|
|
|
|
m = nsBlockReflowContext::MaxMargin(m, topMargin);
|
|
|
|
mPrevBottomMargin = m;
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-10-15 23:35:10 +00:00
|
|
|
// Recover the top and bottom margins for this line
|
1999-04-03 18:59:01 +00:00
|
|
|
nscoord topMargin, bottomMargin;
|
|
|
|
RecoverVerticalMargins(aLine, aApplyTopMargin,
|
|
|
|
&topMargin, &bottomMargin);
|
1999-10-15 23:35:10 +00:00
|
|
|
|
|
|
|
// Compute the collapsed top margin value
|
|
|
|
nscoord collapsedTopMargin =
|
|
|
|
nsBlockReflowContext::MaxMargin(topMargin, mPrevBottomMargin);
|
|
|
|
|
|
|
|
// The lineY is just below the collapsed top margin value. The
|
|
|
|
// mPrevBottomMargin gets set to the bottom margin value for the
|
|
|
|
// line.
|
|
|
|
newLineY += collapsedTopMargin;
|
|
|
|
mPrevBottomMargin = bottomMargin;
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-15 23:35:10 +00:00
|
|
|
else if (0 == aLine->GetHeight()) {
|
|
|
|
// For empty inline lines we leave the previous bottom margin
|
|
|
|
// alone so that it's collpased with the next line.
|
|
|
|
}
|
1999-04-03 18:59:01 +00:00
|
|
|
else {
|
1999-10-15 23:35:10 +00:00
|
|
|
// For non-empty inline lines the previous margin is applied
|
|
|
|
// before the line. Therefore apply it now and zero it out.
|
|
|
|
newLineY += mPrevBottomMargin;
|
|
|
|
mPrevBottomMargin = 0;
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// Save away the old combined area for later
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect oldCombinedArea = lineCombinedArea;
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// Slide the frames in the line by the computed delta. This also
|
|
|
|
// updates the lines Y coordinate and the combined area's Y
|
|
|
|
// coordinate.
|
1999-04-03 21:54:00 +00:00
|
|
|
nscoord finalDeltaY = newLineY - aLine->mBounds.y;
|
1999-09-16 19:56:36 +00:00
|
|
|
mBlock->SlideLine(*this, aLine, finalDeltaY);
|
2000-06-05 08:24:18 +00:00
|
|
|
// aLine has been slided, but...
|
|
|
|
// XXX it is not necessary to worry about the ascent of mBlock here, right?
|
|
|
|
// Indeed, depending on the status of the first line of mBlock, we can either have:
|
|
|
|
// case first line of mBlock is dirty : it will be reflowed by mBlock and so
|
|
|
|
// mBlock->mAscent will be recomputed by the block frame, and we will
|
|
|
|
// never enter into this RecoverStateFrom(aLine) function.
|
|
|
|
// case first line of mBlock is clean : it is untouched by the incremental reflow.
|
|
|
|
// In other words, aLine is never equals to mBlock->mLines in this function.
|
|
|
|
// so mBlock->mAscent will remain unchanged.
|
1999-04-03 18:59:01 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Place floaters for this line into the space manager
|
1999-10-14 23:10:03 +00:00
|
|
|
if (aLine->HasFloaters()) {
|
1999-09-16 19:56:36 +00:00
|
|
|
// Undo border/padding translation since the nsFloaterCache's
|
|
|
|
// coordinates are relative to the frame not relative to the
|
|
|
|
// border/padding.
|
|
|
|
const nsMargin& bp = BorderPadding();
|
|
|
|
mSpaceManager->Translate(-bp.left, -bp.top);
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Place the floaters into the space-manager again. Also slide
|
|
|
|
// them, just like the regular frames on the line.
|
|
|
|
nsRect r;
|
1999-10-14 23:10:03 +00:00
|
|
|
nsFloaterCache* fc = aLine->GetFirstFloater();
|
1999-09-15 00:28:10 +00:00
|
|
|
while (fc) {
|
|
|
|
fc->mRegion.y += finalDeltaY;
|
|
|
|
fc->mCombinedArea.y += finalDeltaY;
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
|
|
|
floater->GetRect(r);
|
1999-10-26 04:44:41 +00:00
|
|
|
floater->MoveTo(mPresContext, r.x, r.y + finalDeltaY);
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow || gNoisySpaceManager) {
|
|
|
|
nscoord tx, ty;
|
|
|
|
mSpaceManager->GetTranslation(tx, ty);
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("RecoverState: txy=%d,%d (%d,%d) ",
|
1999-10-15 23:35:10 +00:00
|
|
|
tx, ty, mSpaceManagerX, mSpaceManagerY);
|
|
|
|
nsFrame::ListTag(stdout, floater);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" r.y=%d finalDeltaY=%d (sum=%d) region={%d,%d,%d,%d}\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
r.y, finalDeltaY, r.y + finalDeltaY,
|
|
|
|
fc->mRegion.x, fc->mRegion.y,
|
|
|
|
fc->mRegion.width, fc->mRegion.height);
|
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
#endif
|
|
|
|
mSpaceManager->AddRectRegion(floater, fc->mRegion);
|
|
|
|
fc = fc->Next();
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow || gNoisySpaceManager) {
|
|
|
|
mSpaceManager->List(stdout);
|
|
|
|
}
|
|
|
|
#endif
|
1999-09-16 19:56:36 +00:00
|
|
|
// And then put the translation back again
|
|
|
|
mSpaceManager->Translate(bp.left, bp.top);
|
1999-04-03 18:59:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recover mY
|
|
|
|
mY = aLine->mBounds.YMost();
|
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
// Compute the damage area
|
|
|
|
if (aDamageRect) {
|
|
|
|
if (0 == finalDeltaY) {
|
|
|
|
aDamageRect->Empty();
|
|
|
|
} else {
|
1999-12-09 21:40:37 +00:00
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
1999-10-14 23:10:03 +00:00
|
|
|
aDamageRect->UnionRect(oldCombinedArea, lineCombinedArea);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-04 21:44:48 +00:00
|
|
|
// XXX Does this do anything? It doesn't seem to work.... (bug 29413)
|
1999-04-03 18:59:01 +00:00
|
|
|
// It's possible that the line has clear after semantics
|
1999-10-12 23:24:22 +00:00
|
|
|
if (!aLine->IsBlock() && aLine->HasBreak()) {
|
|
|
|
PRUint8 breakType = aLine->GetBreakType();
|
|
|
|
switch (breakType) {
|
1999-04-03 18:59:01 +00:00
|
|
|
case NS_STYLE_CLEAR_LEFT:
|
|
|
|
case NS_STYLE_CLEAR_RIGHT:
|
|
|
|
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
1999-10-12 23:24:22 +00:00
|
|
|
ClearFloaters(mY, breakType);
|
1999-04-03 18:59:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//----------------------------------------------------------------------
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-03-27 01:22:14 +00:00
|
|
|
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
nsresult
|
1999-12-04 23:49:50 +00:00
|
|
|
NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags)
|
1999-02-09 17:31:33 +00:00
|
|
|
{
|
1999-05-11 22:03:29 +00:00
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
1999-12-04 23:49:50 +00:00
|
|
|
nsBlockFrame* it = new (aPresShell) nsBlockFrame;
|
1999-02-09 17:31:33 +00:00
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
1999-10-08 04:32:46 +00:00
|
|
|
it->SetFlags(aFlags);
|
1999-05-11 22:03:29 +00:00
|
|
|
*aNewFrame = it;
|
1999-02-09 17:31:33 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsBlockFrame::nsBlockFrame()
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
InitDebugFlags();
|
|
|
|
#endif
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::~nsBlockFrame()
|
1998-09-23 20:10:40 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::Destroy(nsIPresContext* aPresContext)
|
1998-09-23 20:10:40 +00:00
|
|
|
{
|
2000-05-09 05:06:16 +00:00
|
|
|
mAbsoluteContainer.DestroyFrames(this, aPresContext);
|
1999-02-18 22:22:55 +00:00
|
|
|
// Outside bullets are not in our child-list so check for them here
|
|
|
|
// and delete them when present.
|
|
|
|
if (HaveOutsideBullet()) {
|
1999-07-22 02:24:52 +00:00
|
|
|
mBullet->Destroy(aPresContext);
|
1999-02-09 17:31:33 +00:00
|
|
|
mBullet = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-07-22 04:00:57 +00:00
|
|
|
mFloaters.DestroyFrames(aPresContext);
|
1999-06-15 06:16:29 +00:00
|
|
|
|
1999-11-24 06:03:41 +00:00
|
|
|
nsLineBox::DeleteLineList(aPresContext, mLines);
|
1999-02-10 18:12:24 +00:00
|
|
|
|
1999-07-22 02:24:52 +00:00
|
|
|
return nsBlockFrameSuper::Destroy(aPresContext);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-26 20:05:09 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
if (NULL == aInstancePtr) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
1999-02-09 17:31:33 +00:00
|
|
|
if (aIID.Equals(kBlockFrameCID)) {
|
|
|
|
nsBlockFrame* tmp = this;
|
|
|
|
*aInstancePtr = (void*) tmp;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-16 08:11:14 +00:00
|
|
|
if ( aIID.Equals(NS_GET_IID(nsILineIterator)) || aIID.Equals(NS_GET_IID(nsILineIteratorNavigator)) )
|
|
|
|
{
|
1999-05-13 00:55:38 +00:00
|
|
|
nsLineIterator* it = new nsLineIterator;
|
|
|
|
if (!it) {
|
|
|
|
*aInstancePtr = nsnull;
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
const nsStyleDisplay* display;
|
|
|
|
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) display);
|
|
|
|
nsresult rv = it->Init(mLines,
|
|
|
|
display->mDirection == NS_STYLE_DIRECTION_RTL);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
delete it;
|
|
|
|
return rv;
|
|
|
|
}
|
2000-05-16 08:11:14 +00:00
|
|
|
NS_ADDREF((nsILineIterator *) (*aInstancePtr = (void *) it));
|
|
|
|
return NS_OK;
|
1999-05-13 00:55:38 +00:00
|
|
|
}
|
1999-02-09 17:31:33 +00:00
|
|
|
return nsBlockFrameSuper::QueryInterface(aIID, aInstancePtr);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const
|
1998-09-23 20:10:40 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR;
|
1998-10-03 04:28:05 +00:00
|
|
|
return NS_OK;
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
|
|
|
|
1999-11-01 22:12:45 +00:00
|
|
|
#ifdef DEBUG
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_METHOD
|
1999-10-26 04:44:41 +00:00
|
|
|
nsBlockFrame::List(nsIPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-03-05 04:21:32 +00:00
|
|
|
IndentBy(out, aIndent);
|
1999-01-16 00:00:50 +00:00
|
|
|
ListTag(out);
|
2000-07-27 05:16:08 +00:00
|
|
|
#ifdef DEBUG_waterson
|
2000-10-28 22:17:53 +00:00
|
|
|
fprintf(out, " [parent=%p]", mParent);
|
2000-07-27 05:16:08 +00:00
|
|
|
#endif
|
1999-01-16 00:00:50 +00:00
|
|
|
nsIView* view;
|
1999-10-26 04:44:41 +00:00
|
|
|
GetView(aPresContext, &view);
|
1999-01-16 00:00:50 +00:00
|
|
|
if (nsnull != view) {
|
|
|
|
fprintf(out, " [view=%p]", view);
|
|
|
|
}
|
1999-04-27 22:10:51 +00:00
|
|
|
if (nsnull != mNextSibling) {
|
|
|
|
fprintf(out, " next=%p", mNextSibling);
|
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-01-16 00:00:50 +00:00
|
|
|
// Output the flow linkage
|
|
|
|
if (nsnull != mPrevInFlow) {
|
|
|
|
fprintf(out, " prev-in-flow=%p", mPrevInFlow);
|
|
|
|
}
|
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
fprintf(out, " next-in-flow=%p", mNextInFlow);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output the rect and state
|
1999-03-05 04:21:32 +00:00
|
|
|
fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
|
1999-01-16 00:00:50 +00:00
|
|
|
if (0 != mState) {
|
|
|
|
fprintf(out, " [state=%08x]", mState);
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1999-09-01 01:02:16 +00:00
|
|
|
PRInt32 numInlineLines = 0;
|
|
|
|
PRInt32 numBlockLines = 0;
|
|
|
|
if (nsnull != mLines) {
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
|
|
|
if (line->IsBlock()) {
|
|
|
|
numBlockLines++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
numInlineLines++;
|
|
|
|
}
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fprintf(out, " sc=%p(i=%d,b=%d)<\n", mStyleContext, numInlineLines, numBlockLines);
|
1999-01-16 00:00:50 +00:00
|
|
|
aIndent++;
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Output the lines
|
|
|
|
if (nsnull != mLines) {
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
1999-10-26 04:44:41 +00:00
|
|
|
line->List(aPresContext, out, aIndent);
|
1998-12-05 16:02:08 +00:00
|
|
|
line = line->mNext;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-01-16 00:19:10 +00:00
|
|
|
nsIAtom* listName = nsnull;
|
|
|
|
PRInt32 listIndex = 0;
|
|
|
|
for (;;) {
|
|
|
|
nsIFrame* kid;
|
1999-02-10 02:25:01 +00:00
|
|
|
GetAdditionalChildListName(listIndex++, &listName);
|
1999-01-16 00:19:10 +00:00
|
|
|
if (nsnull == listName) {
|
|
|
|
break;
|
|
|
|
}
|
2000-01-22 01:16:50 +00:00
|
|
|
FirstChild(aPresContext, listName, &kid);
|
1999-01-16 00:19:10 +00:00
|
|
|
if (nsnull != kid) {
|
|
|
|
IndentBy(out, aIndent);
|
|
|
|
nsAutoString tmp;
|
|
|
|
if (nsnull != listName) {
|
|
|
|
listName->ToString(tmp);
|
|
|
|
fputs(tmp, out);
|
|
|
|
}
|
|
|
|
fputs("<\n", out);
|
|
|
|
while (nsnull != kid) {
|
1999-11-01 22:12:45 +00:00
|
|
|
nsIFrameDebug* frameDebug;
|
|
|
|
|
2000-02-02 22:24:56 +00:00
|
|
|
if (NS_SUCCEEDED(kid->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) {
|
1999-11-01 22:12:45 +00:00
|
|
|
frameDebug->List(aPresContext, out, aIndent + 1);
|
|
|
|
}
|
1999-02-10 06:13:38 +00:00
|
|
|
kid->GetNextSibling(&kid);
|
1999-01-16 00:19:10 +00:00
|
|
|
}
|
|
|
|
IndentBy(out, aIndent);
|
|
|
|
fputs(">\n", out);
|
|
|
|
}
|
|
|
|
NS_IF_RELEASE(listName);
|
|
|
|
}
|
|
|
|
|
1999-01-16 00:00:50 +00:00
|
|
|
aIndent--;
|
1999-03-05 04:21:32 +00:00
|
|
|
IndentBy(out, aIndent);
|
1999-01-16 00:00:50 +00:00
|
|
|
fputs(">\n", out);
|
1998-06-30 23:51:26 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-06-30 23:51:26 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::GetFrameName(nsString& aResult) const
|
|
|
|
{
|
|
|
|
return MakeFrameName("Block", aResult);
|
|
|
|
}
|
1999-11-01 22:12:45 +00:00
|
|
|
#endif
|
1999-02-09 17:31:33 +00:00
|
|
|
|
1999-02-12 17:45:58 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::GetFrameType(nsIAtom** aType) const
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
|
1999-04-20 18:22:28 +00:00
|
|
|
*aType = nsLayoutAtoms::blockFrame;
|
1999-02-12 17:45:58 +00:00
|
|
|
NS_ADDREF(*aType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Child frame enumeration
|
1998-08-03 17:07:44 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockFrame::FirstChild(nsIPresContext* aPresContext,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame** aFirstChild) const
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-02-10 02:25:01 +00:00
|
|
|
NS_PRECONDITION(nsnull != aFirstChild, "null OUT parameter pointer");
|
2000-05-09 05:06:16 +00:00
|
|
|
if (aListName == nsLayoutAtoms::absoluteList) {
|
|
|
|
return mAbsoluteContainer.FirstChild(this, aListName, aFirstChild);
|
|
|
|
}
|
|
|
|
else if (nsnull == aListName) {
|
1999-02-10 02:25:01 +00:00
|
|
|
*aFirstChild = (nsnull != mLines) ? mLines->mFirstChild : nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
1998-08-03 17:07:44 +00:00
|
|
|
}
|
2000-01-22 01:16:50 +00:00
|
|
|
else if (aListName == nsLayoutAtoms::overflowList) {
|
|
|
|
nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
|
|
|
*aFirstChild = overflowLines ? overflowLines->mFirstChild : nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-02-09 17:31:33 +00:00
|
|
|
else if (aListName == nsLayoutAtoms::floaterList) {
|
1999-02-10 02:25:01 +00:00
|
|
|
*aFirstChild = mFloaters.FirstChild();
|
1999-02-09 17:31:33 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (aListName == nsLayoutAtoms::bulletList) {
|
1999-04-20 03:42:32 +00:00
|
|
|
if (HaveOutsideBullet()) {
|
|
|
|
*aFirstChild = mBullet;
|
|
|
|
}
|
1999-04-20 21:51:39 +00:00
|
|
|
else {
|
|
|
|
*aFirstChild = nsnull;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
1999-02-10 02:25:01 +00:00
|
|
|
*aFirstChild = nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
1998-08-03 17:07:44 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::GetAdditionalChildListName(PRInt32 aIndex,
|
1999-02-10 02:25:01 +00:00
|
|
|
nsIAtom** aListName) const
|
1999-02-09 17:31:33 +00:00
|
|
|
{
|
1999-02-10 02:25:01 +00:00
|
|
|
NS_PRECONDITION(nsnull != aListName, "null OUT parameter pointer");
|
1999-02-09 17:31:33 +00:00
|
|
|
if (aIndex < 0) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
1999-02-10 02:25:01 +00:00
|
|
|
*aListName = nsnull;
|
1999-02-09 17:31:33 +00:00
|
|
|
switch (aIndex) {
|
|
|
|
case NS_BLOCK_FRAME_FLOATER_LIST_INDEX:
|
1999-02-10 02:25:01 +00:00
|
|
|
*aListName = nsLayoutAtoms::floaterList;
|
|
|
|
NS_ADDREF(*aListName);
|
1999-02-09 17:31:33 +00:00
|
|
|
break;
|
|
|
|
case NS_BLOCK_FRAME_BULLET_LIST_INDEX:
|
1999-04-20 21:51:39 +00:00
|
|
|
*aListName = nsLayoutAtoms::bulletList;
|
|
|
|
NS_ADDREF(*aListName);
|
1999-02-09 17:31:33 +00:00
|
|
|
break;
|
2000-05-09 05:06:16 +00:00
|
|
|
case NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX:
|
|
|
|
*aListName = nsLayoutAtoms::absoluteList;
|
|
|
|
NS_ADDREF(*aListName);
|
|
|
|
break;
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|
|
|
{
|
|
|
|
aBase = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-01-12 16:42:03 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Frame structure methods
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Reflow methods
|
1998-08-03 17:07:44 +00:00
|
|
|
|
2000-06-05 08:24:18 +00:00
|
|
|
inline nscoord
|
|
|
|
nsBlockFrame::GetAscent() const
|
|
|
|
{
|
|
|
|
return mAscent;
|
|
|
|
}
|
|
|
|
|
2000-05-09 05:06:16 +00:00
|
|
|
static void
|
|
|
|
CalculateContainingBlock(const nsHTMLReflowState& aReflowState,
|
|
|
|
nscoord aFrameWidth,
|
|
|
|
nscoord aFrameHeight,
|
|
|
|
nscoord& aContainingBlockWidth,
|
|
|
|
nscoord& aContainingBlockHeight)
|
|
|
|
{
|
|
|
|
aContainingBlockWidth = -1; // have reflow state calculate
|
|
|
|
aContainingBlockHeight = -1; // have reflow state calculate
|
|
|
|
|
|
|
|
// The issue there is that for a 'height' of 'auto' the reflow state code
|
|
|
|
// won't know how to calculate the containing block height because it's
|
|
|
|
// calculated bottom up. We don't really want to do this for the initial
|
|
|
|
// containing block so that's why we have the check for if the element
|
|
|
|
// is absolutely or relatively positioned
|
|
|
|
if (aReflowState.mStylePosition->IsAbsolutelyPositioned() ||
|
|
|
|
(NS_STYLE_POSITION_RELATIVE == aReflowState.mStylePosition->mPosition)) {
|
|
|
|
aContainingBlockWidth = aFrameWidth;
|
|
|
|
aContainingBlockHeight = aFrameHeight;
|
|
|
|
|
|
|
|
// Containing block is relative to the padding edge
|
|
|
|
nsMargin border;
|
2001-01-25 02:58:12 +00:00
|
|
|
if (!aReflowState.mStyleSpacing->GetBorder(border)) {
|
2000-05-09 05:06:16 +00:00
|
|
|
NS_NOTYETIMPLEMENTED("percentage border");
|
|
|
|
}
|
|
|
|
aContainingBlockWidth -= border.left + border.right;
|
|
|
|
aContainingBlockHeight -= border.top + border.bottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
1999-03-05 04:21:32 +00:00
|
|
|
nsHTMLReflowMetrics& aMetrics,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
2000-04-21 14:59:47 +00:00
|
|
|
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame", aReflowState.reason);
|
2000-05-09 05:06:16 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gNoisyReflow) {
|
1999-10-15 23:35:10 +00:00
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n",
|
2000-03-22 23:19:10 +00:00
|
|
|
aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight,
|
1999-10-15 23:35:10 +00:00
|
|
|
aReflowState.mComputedWidth, aReflowState.mComputedHeight);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
|
|
|
if (gNoisy) {
|
1999-10-15 23:35:10 +00:00
|
|
|
gNoiseIndent++;
|
|
|
|
}
|
2000-11-27 23:23:28 +00:00
|
|
|
PRTime start = LL_ZERO; // Initialize these variablies to silence the compiler.
|
|
|
|
PRInt32 ctc = 0; // We only use these if they are set (gLameReflowMetrics).
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gLameReflowMetrics) {
|
|
|
|
start = PR_Now();
|
|
|
|
ctc = nsLineBox::GetCtorCount();
|
|
|
|
}
|
1999-10-15 23:35:10 +00:00
|
|
|
#endif
|
|
|
|
|
2000-05-09 05:06:16 +00:00
|
|
|
// See if it's an incremental reflow command
|
|
|
|
if (eReflowReason_Incremental == aReflowState.reason) {
|
|
|
|
// Give the absolute positioning code a chance to handle it
|
|
|
|
nscoord containingBlockWidth;
|
|
|
|
nscoord containingBlockHeight;
|
|
|
|
PRBool handled;
|
|
|
|
nsRect childBounds;
|
|
|
|
|
|
|
|
CalculateContainingBlock(aReflowState, mRect.width, mRect.height,
|
|
|
|
containingBlockWidth, containingBlockHeight);
|
|
|
|
|
|
|
|
mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
|
|
|
|
containingBlockWidth, containingBlockHeight,
|
|
|
|
handled, childBounds);
|
|
|
|
|
|
|
|
// If the incremental reflow command was handled by the absolute positioning
|
|
|
|
// code, then we're all done
|
|
|
|
if (handled) {
|
|
|
|
// Just return our current size as our desired size.
|
|
|
|
// XXX We need to know the overflow area for the flowed content, and
|
|
|
|
// we don't have a way to get that currently so for the time being pretend
|
|
|
|
// a resize reflow occured
|
|
|
|
#if 0
|
|
|
|
aMetrics.width = mRect.width;
|
|
|
|
aMetrics.height = mRect.height;
|
|
|
|
aMetrics.ascent = mRect.height;
|
|
|
|
aMetrics.descent = 0;
|
|
|
|
|
|
|
|
// Whether or not we're complete hasn't changed
|
|
|
|
aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE;
|
|
|
|
#else
|
|
|
|
nsHTMLReflowState reflowState(aReflowState);
|
|
|
|
reflowState.reason = eReflowReason_Resize;
|
|
|
|
reflowState.reflowCommand = nsnull;
|
|
|
|
nsBlockFrame::Reflow(aPresContext, aMetrics, reflowState, aStatus);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Factor the absolutely positioned child bounds into the overflow area
|
|
|
|
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds);
|
|
|
|
|
|
|
|
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
|
|
|
|
if ((aMetrics.mOverflowArea.x < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.y < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
|
|
|
|
(aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
|
|
|
|
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
} else {
|
|
|
|
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
|
|
|
#ifdef DEBUG_kipp
|
|
|
|
{
|
|
|
|
extern char* nsPresShell_ReflowStackPointerTop;
|
|
|
|
char marker;
|
|
|
|
char* newsp = (char*) ▮
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
1999-08-27 21:45:37 +00:00
|
|
|
nsPresShell_ReflowStackPointerTop - newsp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-10-06 22:05:23 +00:00
|
|
|
// Should we create a space manager?
|
|
|
|
nsCOMPtr<nsISpaceManager> spaceManager;
|
1999-11-11 06:00:41 +00:00
|
|
|
nsISpaceManager* oldSpaceManager = aReflowState.mSpaceManager;
|
1999-11-03 00:42:12 +00:00
|
|
|
if (NS_BLOCK_SPACE_MGR & mState) {
|
1999-10-06 22:05:23 +00:00
|
|
|
nsSpaceManager* rawPtr = new nsSpaceManager(this);
|
|
|
|
if (!rawPtr) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
spaceManager = do_QueryInterface(rawPtr);
|
|
|
|
|
|
|
|
// Set the space manager in the existing reflow state
|
|
|
|
nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState;
|
|
|
|
reflowState.mSpaceManager = spaceManager.get();
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef NOISY_SPACEMANAGER
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("constructed new space manager %p\n", reflowState.mSpaceManager);
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
1999-10-06 22:05:23 +00:00
|
|
|
}
|
|
|
|
|
2000-01-03 04:32:13 +00:00
|
|
|
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
|
|
|
NS_BLOCK_MARGIN_ROOT & mState);
|
1999-02-23 19:32:00 +00:00
|
|
|
|
1999-03-05 19:25:44 +00:00
|
|
|
if (eReflowReason_Resize != aReflowState.reason) {
|
2000-10-30 04:48:53 +00:00
|
|
|
RenumberLists(aPresContext);
|
1999-03-05 19:25:44 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult rv = NS_OK;
|
1999-08-25 23:15:36 +00:00
|
|
|
PRBool isStyleChange = PR_FALSE;
|
2000-04-17 14:40:46 +00:00
|
|
|
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* target;
|
1999-03-05 04:21:32 +00:00
|
|
|
switch (aReflowState.reason) {
|
1998-12-05 16:02:08 +00:00
|
|
|
case eReflowReason_Initial:
|
1999-04-20 00:27:43 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow=initial\n");
|
1999-04-20 00:27:43 +00:00
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
DrainOverflowLines(aPresContext);
|
1998-12-05 16:02:08 +00:00
|
|
|
rv = PrepareInitialReflow(state);
|
|
|
|
mState &= ~NS_FRAME_FIRST_REFLOW;
|
2000-01-12 08:28:24 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case eReflowReason_Dirty:
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
1998-07-02 00:04:12 +00:00
|
|
|
|
2000-02-14 01:52:22 +00:00
|
|
|
case eReflowReason_Incremental: // should call GetNext() ?
|
1999-03-05 04:21:32 +00:00
|
|
|
aReflowState.reflowCommand->GetTarget(target);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (this == target) {
|
|
|
|
nsIReflowCommand::ReflowType type;
|
1999-03-05 04:21:32 +00:00
|
|
|
aReflowState.reflowCommand->GetType(type);
|
1999-04-20 00:27:43 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow=incremental type=%d\n", type);
|
1999-04-20 00:27:43 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
switch (type) {
|
|
|
|
case nsIReflowCommand::StyleChanged:
|
|
|
|
rv = PrepareStyleChangedReflow(state);
|
1999-08-25 23:15:36 +00:00
|
|
|
isStyleChange = PR_TRUE;
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
1999-02-03 19:09:24 +00:00
|
|
|
case nsIReflowCommand::ReflowDirty:
|
|
|
|
break;
|
1998-12-05 16:02:08 +00:00
|
|
|
default:
|
|
|
|
// Map any other incremental operations into full reflows
|
|
|
|
rv = PrepareResizeReflow(state);
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 00:38:56 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
// Get next frame in reflow command chain
|
1999-03-05 04:21:32 +00:00
|
|
|
aReflowState.reflowCommand->GetNext(state.mNextRCFrame);
|
1999-04-20 00:27:43 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow=incremental");
|
1999-04-20 00:27:43 +00:00
|
|
|
if (state.mNextRCFrame) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" next=");
|
1999-04-20 00:27:43 +00:00
|
|
|
nsFrame::ListTag(stdout, state.mNextRCFrame);
|
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-04-20 00:27:43 +00:00
|
|
|
#endif
|
1998-10-06 00:38:56 +00:00
|
|
|
|
2000-02-14 01:52:22 +00:00
|
|
|
// this code does a correct job of propogating incremental reflows (bug 25510)
|
|
|
|
// and has the potential to be very efficient. we should be able to
|
|
|
|
// terminate reflow after the incremental reflow if we can detect that
|
|
|
|
// nothing significant has changed.
|
|
|
|
PRBool isFloater;
|
|
|
|
nsLineBox* prevLine;
|
|
|
|
nsLineBox* line = FindLineFor(state.mNextRCFrame, &prevLine, &isFloater);
|
|
|
|
if (line && (PR_FALSE==line->IsBlock()))
|
|
|
|
{
|
2000-02-16 00:50:06 +00:00
|
|
|
if (!isFloater) // punt if isFloater!
|
|
|
|
{
|
2000-02-22 22:06:19 +00:00
|
|
|
// reflow the line containing the target of the incr. reflow
|
|
|
|
// first mark the line dirty and set up the state object
|
|
|
|
rv = PrepareChildIncrementalReflow(state);
|
2000-04-17 14:40:46 +00:00
|
|
|
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
2000-02-22 22:06:19 +00:00
|
|
|
state.mPrevLine = prevLine;
|
|
|
|
state.mCurrentLine = line;
|
|
|
|
state.mNextRCFrame = state.mNextRCFrame;
|
|
|
|
// let ReflowDirtyLines do all the work
|
|
|
|
rv = ReflowDirtyLines(state);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ASSERTION(0, "Reflow failed\n");
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
// compute the final size
|
|
|
|
ComputeFinalSize(aReflowState, state, aMetrics);
|
|
|
|
|
|
|
|
// finally, mark this block frame as having a dirty child and return
|
|
|
|
// XXX: we should be able to optimize this so we only call ReflowDirtyChild
|
|
|
|
// if it's absolutely necessary: something on the line changed size.
|
2000-06-11 22:14:33 +00:00
|
|
|
if (!IsIncrementalDamageConstrained(state))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
rv = ReflowDirtyChild(shell, state.mNextRCFrame);
|
|
|
|
//XXX: it's possible we need to do some work regarding incremental painting
|
|
|
|
// here, see code below "ReflowDirtyLines() after this switch statement.
|
|
|
|
// It might be right to factor the tail end of this method into a new method
|
|
|
|
// and call that here before calling ReflowDirtyChild().
|
|
|
|
}
|
2000-02-22 22:06:19 +00:00
|
|
|
return rv;
|
2000-02-16 00:50:06 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
rv = PrepareChildIncrementalReflow(state);
|
1998-10-16 20:22:39 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
|
|
|
|
2000-03-15 15:16:03 +00:00
|
|
|
case eReflowReason_StyleChange:
|
|
|
|
rv = PrepareStyleChangedReflow(state);
|
|
|
|
break;
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
case eReflowReason_Resize:
|
|
|
|
default:
|
1999-04-20 00:27:43 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow=resize (%d)\n", aReflowState.reason);
|
1999-04-20 00:27:43 +00:00
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
DrainOverflowLines(aPresContext);
|
1998-12-05 16:02:08 +00:00
|
|
|
rv = PrepareResizeReflow(state);
|
|
|
|
break;
|
1998-10-16 20:22:39 +00:00
|
|
|
}
|
|
|
|
|
2000-02-22 22:06:19 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ASSERTION(0, "setting up reflow failed.\n");
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Now reflow...
|
|
|
|
rv = ReflowDirtyLines(state);
|
2000-02-22 22:06:19 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ASSERTION(0, "reflow dirty lines failed.\n");
|
|
|
|
return rv;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
aStatus = state.mReflowStatus;
|
1999-02-12 17:45:58 +00:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
1999-03-05 04:21:32 +00:00
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
}
|
|
|
|
else {
|
1999-03-05 19:25:44 +00:00
|
|
|
#ifdef DEBUG_kipp
|
2000-10-28 22:17:53 +00:00
|
|
|
ListTag(stdout); printf(": block is not complete\n");
|
1999-03-05 19:25:44 +00:00
|
|
|
#endif
|
1999-03-05 04:21:32 +00:00
|
|
|
}
|
1999-02-12 17:45:58 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
2000-01-12 08:28:24 +00:00
|
|
|
// XXX_pref get rid of this!
|
1999-02-09 17:31:33 +00:00
|
|
|
BuildFloaterList();
|
2000-01-12 08:28:24 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Compute our final size
|
1999-03-05 04:21:32 +00:00
|
|
|
ComputeFinalSize(aReflowState, state, aMetrics);
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-11-03 00:42:12 +00:00
|
|
|
if (NS_BLOCK_WRAP_SIZE & mState) {
|
1999-10-08 04:32:46 +00:00
|
|
|
// When the area frame is supposed to wrap around all in-flow
|
|
|
|
// children, make sure its big enough to include those that stick
|
|
|
|
// outside the box.
|
|
|
|
if (NS_FRAME_OUTSIDE_CHILDREN & mState) {
|
1999-12-06 15:49:53 +00:00
|
|
|
nscoord xMost = aMetrics.mOverflowArea.XMost();
|
1999-10-08 04:32:46 +00:00
|
|
|
if (xMost > aMetrics.width) {
|
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": changing desired width from %d to %d\n", aMetrics.width, xMost);
|
1999-10-08 04:32:46 +00:00
|
|
|
#endif
|
|
|
|
aMetrics.width = xMost;
|
|
|
|
}
|
1999-12-06 15:49:53 +00:00
|
|
|
nscoord yMost = aMetrics.mOverflowArea.YMost();
|
1999-10-08 04:32:46 +00:00
|
|
|
if (yMost > aMetrics.height) {
|
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": changing desired height from %d to %d\n", aMetrics.height, yMost);
|
1999-10-08 04:32:46 +00:00
|
|
|
#endif
|
|
|
|
aMetrics.height = yMost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-10-08 04:45:12 +00:00
|
|
|
|
2000-03-22 23:19:10 +00:00
|
|
|
// see if verifyReflow is enabled, and if so store off the space manager pointer
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags();
|
|
|
|
if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags)
|
|
|
|
{
|
|
|
|
// this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
if (shell) {
|
|
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
|
|
shell->GetFrameManager(getter_AddRefs(frameManager));
|
|
|
|
if (frameManager) {
|
|
|
|
nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState;
|
2000-03-30 03:21:26 +00:00
|
|
|
NS_ADDREF(reflowState.mSpaceManager);
|
2000-03-22 23:19:10 +00:00
|
|
|
rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty,
|
|
|
|
reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-11-11 06:00:41 +00:00
|
|
|
// If we set the space manager, then restore the old space manager now that we're
|
|
|
|
// going out of scope
|
|
|
|
if (NS_BLOCK_SPACE_MGR & mState) {
|
|
|
|
nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState;
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef NOISY_SPACEMANAGER
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("restoring old space manager %p\n", oldSpaceManager);
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
1999-11-11 06:00:41 +00:00
|
|
|
reflowState.mSpaceManager = oldSpaceManager;
|
|
|
|
}
|
|
|
|
|
1999-10-08 04:45:12 +00:00
|
|
|
#ifdef NOISY_SPACEMANAGER
|
2000-03-22 23:19:10 +00:00
|
|
|
nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState;
|
|
|
|
if (reflowState.mSpaceManager) {
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": space-manager %p after reflow\n", reflowState.mSpaceManager);
|
2000-03-22 23:19:10 +00:00
|
|
|
reflowState.mSpaceManager->List(stdout);
|
1999-10-08 04:45:12 +00:00
|
|
|
}
|
|
|
|
#endif
|
1999-10-08 04:32:46 +00:00
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
// If this is an incremental reflow and we changed size, then make sure our
|
|
|
|
// border is repainted if necessary
|
2000-01-12 08:28:24 +00:00
|
|
|
if (eReflowReason_Incremental == aReflowState.reason ||
|
|
|
|
eReflowReason_Dirty == aReflowState.reason) {
|
1999-08-25 23:15:36 +00:00
|
|
|
if (isStyleChange) {
|
|
|
|
// Lots of things could have changed so damage our entire
|
|
|
|
// bounds
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, 0, 0, mRect.width, mRect.height);
|
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
1999-07-14 15:16:56 +00:00
|
|
|
|
1999-08-25 23:15:36 +00:00
|
|
|
} else {
|
|
|
|
nsMargin border = aReflowState.mComputedBorderPadding -
|
|
|
|
aReflowState.mComputedPadding;
|
|
|
|
|
|
|
|
// See if our width changed
|
|
|
|
if ((aMetrics.width != mRect.width) && (border.right > 0)) {
|
|
|
|
nsRect damageRect;
|
|
|
|
|
|
|
|
if (aMetrics.width < mRect.width) {
|
|
|
|
// Our new width is smaller, so we need to make sure that
|
|
|
|
// we paint our border in its new position
|
|
|
|
damageRect.x = aMetrics.width - border.right;
|
|
|
|
damageRect.width = border.right;
|
|
|
|
damageRect.y = 0;
|
|
|
|
damageRect.height = aMetrics.height;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Our new width is larger, so we need to erase our border in its
|
|
|
|
// old position
|
|
|
|
damageRect.x = mRect.width - border.right;
|
|
|
|
damageRect.width = border.right;
|
|
|
|
damageRect.y = 0;
|
|
|
|
damageRect.height = mRect.height;
|
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
Invalidate(aPresContext, damageRect);
|
1999-08-25 23:15:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if our height changed
|
|
|
|
if ((aMetrics.height != mRect.height) && (border.bottom > 0)) {
|
|
|
|
nsRect damageRect;
|
|
|
|
|
|
|
|
if (aMetrics.height < mRect.height) {
|
|
|
|
// Our new height is smaller, so we need to make sure that
|
|
|
|
// we paint our border in its new position
|
|
|
|
damageRect.x = 0;
|
|
|
|
damageRect.width = aMetrics.width;
|
|
|
|
damageRect.y = aMetrics.height - border.bottom;
|
|
|
|
damageRect.height = border.bottom;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Our new height is larger, so we need to erase our border in its
|
|
|
|
// old position
|
|
|
|
damageRect.x = 0;
|
|
|
|
damageRect.width = mRect.width;
|
|
|
|
damageRect.y = mRect.height - border.bottom;
|
|
|
|
damageRect.height = border.bottom;
|
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
Invalidate(aPresContext, damageRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-09 05:06:16 +00:00
|
|
|
// Let the absolutely positioned container reflow any absolutely positioned
|
|
|
|
// child frames that need to be reflowed, e.g., elements with a percentage
|
|
|
|
// based width/height
|
|
|
|
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) {
|
|
|
|
nscoord containingBlockWidth;
|
|
|
|
nscoord containingBlockHeight;
|
|
|
|
nsRect childBounds;
|
|
|
|
|
|
|
|
CalculateContainingBlock(aReflowState, aMetrics.width, aMetrics.height,
|
|
|
|
containingBlockWidth, containingBlockHeight);
|
|
|
|
|
|
|
|
rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
|
|
|
|
containingBlockWidth, containingBlockHeight,
|
|
|
|
childBounds);
|
|
|
|
|
|
|
|
// Factor the absolutely positioned child bounds into the overflow area
|
|
|
|
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds);
|
|
|
|
|
|
|
|
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly
|
|
|
|
if ((aMetrics.mOverflowArea.x < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.y < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
|
|
|
|
(aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
|
|
|
|
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
} else {
|
|
|
|
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisy) {
|
|
|
|
gNoiseIndent--;
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
|
|
|
if (gNoisyReflow) {
|
1999-10-15 23:35:10 +00:00
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d",
|
1999-10-15 23:35:10 +00:00
|
|
|
aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ",
|
|
|
|
aMetrics.width, aMetrics.height,
|
|
|
|
aMetrics.mCarriedOutBottomMargin);
|
|
|
|
if (mState & NS_FRAME_OUTSIDE_CHILDREN) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" combinedArea={%d,%d,%d,%d}",
|
1999-12-06 15:49:53 +00:00
|
|
|
aMetrics.mOverflowArea.x,
|
|
|
|
aMetrics.mOverflowArea.y,
|
|
|
|
aMetrics.mOverflowArea.width,
|
|
|
|
aMetrics.mOverflowArea.height);
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
|
|
|
if (aMetrics.maxElementSize) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" maxElementSize=%d,%d",
|
1999-10-15 23:35:10 +00:00
|
|
|
aMetrics.maxElementSize->width,
|
|
|
|
aMetrics.maxElementSize->height);
|
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-10-14 23:10:03 +00:00
|
|
|
}
|
1999-10-19 23:04:19 +00:00
|
|
|
|
|
|
|
if (gLameReflowMetrics) {
|
|
|
|
PRTime end = PR_Now();
|
|
|
|
|
|
|
|
PRInt32 ectc = nsLineBox::GetCtorCount();
|
|
|
|
PRInt32 numLines = nsLineBox::ListLength(mLines);
|
|
|
|
if (!numLines) numLines = 1;
|
|
|
|
PRTime delta, perLineDelta, lines;
|
|
|
|
LL_I2L(lines, numLines);
|
|
|
|
LL_SUB(delta, end, start);
|
|
|
|
LL_DIV(perLineDelta, delta, lines);
|
|
|
|
|
|
|
|
ListTag(stdout);
|
|
|
|
char buf[400];
|
|
|
|
PR_snprintf(buf, sizeof(buf),
|
|
|
|
": %lld elapsed (%lld per line) (%d lines; %d new lines)",
|
|
|
|
delta, perLineDelta, numLines, ectc - ctc);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%s\n", buf);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
1999-03-08 19:24:07 +00:00
|
|
|
#endif
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-05-09 05:06:16 +00:00
|
|
|
if (aMetrics.maxElementSize) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("block %p returning with maxElementSize=%d,%d\n", this,
|
2000-05-09 05:06:16 +00:00
|
|
|
aMetrics.maxElementSize->width,
|
|
|
|
aMetrics.maxElementSize->height);
|
|
|
|
}
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
|
1999-07-07 02:33:17 +00:00
|
|
|
static PRBool
|
|
|
|
HaveAutoWidth(const nsHTMLReflowState& aReflowState)
|
|
|
|
{
|
1999-09-09 20:53:32 +00:00
|
|
|
const nsHTMLReflowState* rs = &aReflowState;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == rs->mComputedWidth) {
|
1999-07-07 02:33:17 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-09-09 20:53:32 +00:00
|
|
|
const nsStylePosition* pos = rs->mStylePosition;
|
|
|
|
|
1999-07-07 02:33:17 +00:00
|
|
|
for (;;) {
|
1999-09-09 20:53:32 +00:00
|
|
|
if (!pos) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-07-07 02:33:17 +00:00
|
|
|
nsStyleUnit widthUnit = pos->mWidth.GetUnit();
|
|
|
|
if (eStyleUnit_Auto == widthUnit) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
if (eStyleUnit_Inherit != widthUnit) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const nsHTMLReflowState* prs = (const nsHTMLReflowState*)
|
1999-09-09 20:53:32 +00:00
|
|
|
rs->parentReflowState;
|
1999-07-07 02:33:17 +00:00
|
|
|
if (!prs) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-09-09 20:53:32 +00:00
|
|
|
rs = prs;
|
1999-07-07 02:33:17 +00:00
|
|
|
pos = prs->mStylePosition;
|
|
|
|
}
|
1999-09-09 20:53:32 +00:00
|
|
|
|
1999-07-07 02:33:17 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2000-02-14 01:52:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
IsPercentageAwareChild(const nsIFrame* aFrame)
|
|
|
|
{
|
2001-01-25 02:58:12 +00:00
|
|
|
const nsStyleSpacing* space;
|
|
|
|
nsresult rv = aFrame->GetStyleData(eStyleStruct_Spacing,(const nsStyleStruct*&) space);
|
2000-02-14 01:52:22 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return PR_TRUE; // just to be on the safe side
|
|
|
|
}
|
|
|
|
|
2001-01-25 02:58:12 +00:00
|
|
|
if (nsLineLayout::IsPercentageUnitSides(&space->mMargin)
|
|
|
|
|| nsLineLayout::IsPercentageUnitSides(&space->mPadding)
|
|
|
|
|| nsLineLayout::IsPercentageUnitSides(&space->mBorderRadius)) {
|
2000-02-14 01:52:22 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsStylePosition* pos;
|
|
|
|
rv = aFrame->GetStyleData(eStyleStruct_Position,(const nsStyleStruct*&) pos);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return PR_TRUE; // just to be on the safe side
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
2000-09-11 20:46:44 +00:00
|
|
|
|| nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!!
|
2000-02-14 01:52:22 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-07-07 02:33:17 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|
|
|
nsBlockReflowState& aState,
|
|
|
|
nsHTMLReflowMetrics& aMetrics)
|
1998-06-25 16:33:10 +00:00
|
|
|
{
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsMargin& borderPadding = aState.BorderPadding();
|
1999-09-15 00:28:10 +00:00
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
1999-09-15 00:28:10 +00:00
|
|
|
aState.mPrevBottomMargin,
|
|
|
|
borderPadding.top, borderPadding.bottom);
|
|
|
|
#endif
|
1999-03-19 23:05:56 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// Compute final width
|
|
|
|
nscoord maxWidth = 0, maxHeight = 0;
|
|
|
|
#ifdef NOISY_KIDXMOST
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p aState.mKidXMost=%d\n", this, aState.mKidXMost);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
2000-06-29 22:03:42 +00:00
|
|
|
nscoord minWidth = aState.mKidXMost + borderPadding.right;
|
|
|
|
if (!HaveAutoWidth(aReflowState)) {
|
|
|
|
// Use style defined width
|
|
|
|
aMetrics.width = borderPadding.left + aReflowState.mComputedWidth +
|
|
|
|
borderPadding.right;
|
|
|
|
// XXX quote css1 section here
|
|
|
|
if ((0 == aReflowState.mComputedWidth) && (aMetrics.width < minWidth)) {
|
|
|
|
aMetrics.width = minWidth;
|
1999-03-19 23:05:56 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
|
|
|
|
// When style defines the width use it for the max-element-size
|
|
|
|
// because we can't shrink any smaller.
|
|
|
|
maxWidth = aMetrics.width;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
2000-06-29 22:03:42 +00:00
|
|
|
nscoord computedWidth = minWidth;
|
|
|
|
PRBool compact = PR_FALSE;
|
|
|
|
#if 0
|
|
|
|
if (NS_STYLE_DISPLAY_COMPACT == aReflowState.mStyleDisplay->mDisplay) {
|
|
|
|
// If we are display: compact AND we have no lines or we have
|
|
|
|
// exactly one line and that line is not a block line AND that
|
|
|
|
// line doesn't end in a BR of any sort THEN we remain a compact
|
|
|
|
// frame.
|
|
|
|
if ((nsnull == mLines) ||
|
|
|
|
((nsnull == mLines->mNext) && !mLines->IsBlock() &&
|
|
|
|
(NS_STYLE_CLEAR_NONE == mLines->GetBreakType())
|
|
|
|
/*XXX && (computedWidth <= aState.mCompactMarginWidth) */
|
|
|
|
)) {
|
|
|
|
compact = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// There are two options here. We either shrink wrap around our
|
|
|
|
// contents or we fluff out to the maximum block width. Note:
|
|
|
|
// We always shrink wrap when given an unconstrained width.
|
|
|
|
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
|
|
|
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
|
|
|
!compact) {
|
|
|
|
// Set our width to the max width if we aren't already that
|
|
|
|
// wide. Note that the max-width has nothing to do with our
|
|
|
|
// contents (CSS2 section XXX)
|
|
|
|
computedWidth = borderPadding.left + aState.mContentArea.width +
|
1999-03-22 22:42:30 +00:00
|
|
|
borderPadding.right;
|
|
|
|
}
|
1999-08-28 00:39:55 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// See if we should compute our max element size
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
// Adjust the computedWidth
|
|
|
|
if (aState.GetFlag(BRS_NOWRAP)) {
|
|
|
|
// When no-wrap is true the max-element-size.width is the
|
|
|
|
// width of the widest line plus the right border. Note that
|
|
|
|
// aState.mKidXMost already has the left border factored in
|
|
|
|
//maxWidth = aState.mKidXMost + borderPadding.right;
|
|
|
|
maxWidth = aState.mMaxElementSize.width +
|
1999-03-22 22:42:30 +00:00
|
|
|
borderPadding.left + borderPadding.right;
|
1999-03-20 19:40:13 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
else {
|
|
|
|
// Add in border and padding dimensions to already computed
|
|
|
|
// max-element-size values.
|
|
|
|
maxWidth = aState.mMaxElementSize.width +
|
1999-03-22 22:42:30 +00:00
|
|
|
borderPadding.left + borderPadding.right;
|
1999-03-18 21:03:25 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
if (computedWidth < maxWidth) {
|
|
|
|
computedWidth = maxWidth;
|
|
|
|
}
|
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// Apply min/max values
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
|
|
|
nscoord computedMaxWidth = aReflowState.mComputedMaxWidth +
|
|
|
|
borderPadding.left + borderPadding.right;
|
|
|
|
if (computedWidth > computedMaxWidth) {
|
|
|
|
computedWidth = computedMaxWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinWidth) {
|
|
|
|
nscoord computedMinWidth = aReflowState.mComputedMinWidth +
|
|
|
|
borderPadding.left + borderPadding.right;
|
|
|
|
if (computedWidth < computedMinWidth) {
|
|
|
|
computedWidth = computedMinWidth;
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
aMetrics.width = computedWidth;
|
2000-01-03 04:32:13 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// If we're shrink wrapping, then now that we know our final width we
|
|
|
|
// need to do horizontal alignment of the inline lines and make sure
|
|
|
|
// blocks are correctly sized and positioned. Any lines that need
|
|
|
|
// final adjustment will have been marked as dirty
|
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
|
|
|
// If the parent reflow state is also shrink wrap width, then
|
|
|
|
// we don't need to do this, because it will reflow us after it
|
|
|
|
// calculates the final width
|
2000-01-03 04:32:13 +00:00
|
|
|
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
|
|
|
if (aReflowState.parentReflowState) {
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
|
|
|
parentIsShrinkWrapWidth = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
if (!parentIsShrinkWrapWidth) {
|
|
|
|
nsHTMLReflowState reflowState(aReflowState);
|
1999-03-20 19:40:13 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
|
|
|
|
borderPadding.right;
|
|
|
|
reflowState.reason = eReflowReason_Resize;
|
|
|
|
reflowState.mSpaceManager->ClearRegions();
|
1999-09-15 00:28:10 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
nscoord oldDesiredWidth = aMetrics.width;
|
|
|
|
nsBlockReflowState state(reflowState, aState.mPresContext, this, aMetrics,
|
|
|
|
NS_BLOCK_MARGIN_ROOT & mState);
|
|
|
|
ReflowDirtyLines(state);
|
|
|
|
aState.mY = state.mY;
|
|
|
|
NS_ASSERTION(oldDesiredWidth == aMetrics.width, "bad desired width");
|
1999-09-15 00:28:10 +00:00
|
|
|
}
|
1999-03-20 19:40:13 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
|
|
|
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
|
|
|
if (aReflowState.parentReflowState) {
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
|
|
|
parentIsShrinkWrapWidth = PR_TRUE;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// Compute final height
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
|
|
|
|
// Use style defined height
|
|
|
|
aMetrics.height = borderPadding.top + aReflowState.mComputedHeight +
|
|
|
|
borderPadding.bottom;
|
|
|
|
|
|
|
|
// When style defines the height use it for the max-element-size
|
|
|
|
// because we can't shrink any smaller.
|
|
|
|
maxHeight = aMetrics.height;
|
|
|
|
|
|
|
|
// Don't carry out a bottom margin when our height is fixed
|
|
|
|
// unless the bottom of the last line adjoins the bottom of our
|
|
|
|
// content area.
|
|
|
|
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
|
|
|
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
|
|
|
aState.mPrevBottomMargin = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nscoord autoHeight = aState.mY;
|
|
|
|
|
|
|
|
// Shrink wrap our height around our contents.
|
|
|
|
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
|
|
|
// When we are a bottom-margin root make sure that our last
|
|
|
|
// childs bottom margin is fully applied.
|
|
|
|
// XXX check for a fit
|
|
|
|
autoHeight += aState.mPrevBottomMargin;
|
|
|
|
}
|
|
|
|
autoHeight += borderPadding.bottom;
|
|
|
|
|
|
|
|
// Apply min/max values
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) {
|
|
|
|
nscoord computedMaxHeight = aReflowState.mComputedMaxHeight +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
|
|
|
if (autoHeight > computedMaxHeight) {
|
|
|
|
autoHeight = computedMaxHeight;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) {
|
|
|
|
nscoord computedMinHeight = aReflowState.mComputedMinHeight +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
|
|
|
if (autoHeight < computedMinHeight) {
|
|
|
|
autoHeight = computedMinHeight;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
aMetrics.height = autoHeight;
|
1999-03-22 22:42:30 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
maxHeight = aState.mMaxElementSize.height +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
1999-03-20 19:40:13 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
1999-03-20 19:40:13 +00:00
|
|
|
|
2000-07-28 09:18:15 +00:00
|
|
|
// Set our desired ascent and descent.
|
|
|
|
// We need to check for special cases where mAscent is not yet properly set.
|
|
|
|
// There are two cases to consider: when the first line is a block, or
|
|
|
|
// when the first line is empty and is followed by a second line that
|
|
|
|
// is a block (e.g., <td>\n<div>). We need to fetch the ascent of the
|
|
|
|
// first child of the first non-empty line.
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
// see if this first line is empty. if so, move on to the second line
|
|
|
|
if (line && (0 == line->GetHeight())) {
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
// see if the line contains a block. if so, fetch the ascent of the block
|
|
|
|
if (line && line->mFirstChild && line->IsBlock()) {
|
2000-06-29 22:03:42 +00:00
|
|
|
nsBlockFrame* bf;
|
2000-07-28 09:18:15 +00:00
|
|
|
nsresult res = line->mFirstChild->QueryInterface(kBlockFrameCID, (void**)&bf);
|
2000-06-29 22:03:42 +00:00
|
|
|
if (NS_SUCCEEDED(res) && bf) {
|
|
|
|
mAscent = bf->GetAscent();
|
2000-06-05 08:24:18 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
aMetrics.ascent = mAscent;
|
|
|
|
aMetrics.descent = aMetrics.height - aMetrics.ascent;
|
2000-07-28 09:18:15 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
// Store away the final value
|
|
|
|
aMetrics.maxElementSize->width = maxWidth;
|
|
|
|
aMetrics.maxElementSize->height = maxHeight;
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf ("nsBlockFrame::CFS: %p returning MES %d\n",
|
|
|
|
this, aMetrics.maxElementSize->width);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
1999-03-20 19:40:13 +00:00
|
|
|
|
2000-06-29 22:03:42 +00:00
|
|
|
// Return bottom margin information
|
|
|
|
aMetrics.mCarriedOutBottomMargin =
|
|
|
|
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
1998-06-24 17:52:42 +00:00
|
|
|
|
2000-06-04 09:44:08 +00:00
|
|
|
#ifdef DEBUG_blocks
|
2000-06-29 22:03:42 +00:00
|
|
|
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
2000-06-29 22:03:42 +00:00
|
|
|
}
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
|
|
|
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
2000-06-29 22:03:42 +00:00
|
|
|
maxWidth, maxHeight, aMetrics.width, aMetrics.height,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
aState.mReflowState.availableHeight);
|
|
|
|
}
|
1999-03-20 19:40:13 +00:00
|
|
|
#endif
|
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-06-29 22:03:42 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
IndentBy(stdout, GetDepth());
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("PASS1 ");
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
2000-06-29 22:03:42 +00:00
|
|
|
maxWidth, maxHeight, aMetrics.width, aMetrics.height,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
aState.mReflowState.availableHeight);
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-06-29 22:03:42 +00:00
|
|
|
#endif
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-12-30 04:15:45 +00:00
|
|
|
// If we're requested to update our maximum width, then compute it
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
1999-12-30 04:15:45 +00:00
|
|
|
// We need to add in for the right border/padding
|
|
|
|
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::ComputeFinalSize block %p setting aMetrics.mMaximumWidth to %d\n", this, aMetrics.mMaximumWidth);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-12-30 04:15:45 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Compute the combined area of our children
|
1999-04-03 18:59:01 +00:00
|
|
|
// XXX_perf: This can be done incrementally
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord xa = 0, ya = 0, xb = aMetrics.width, yb = aMetrics.height;
|
1999-09-01 20:57:37 +00:00
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN != aReflowState.mStyleDisplay->mOverflow) {
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
|
|
|
// Compute min and max x/y values for the reflowed frame's
|
|
|
|
// combined areas
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
|
|
|
nscoord x = lineCombinedArea.x;
|
|
|
|
nscoord y = lineCombinedArea.y;
|
|
|
|
nscoord xmost = x + lineCombinedArea.width;
|
|
|
|
nscoord ymost = y + lineCombinedArea.height;
|
1999-09-01 20:57:37 +00:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
|
|
|
}
|
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
|
|
|
}
|
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
|
|
|
}
|
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
|
|
|
}
|
|
|
|
line = line->mNext;
|
1999-05-03 20:51:02 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// Factor the bullet in; normally the bullet will be factored into
|
|
|
|
// the line-box's combined area. However, if the line is a block
|
|
|
|
// line then it won't; if there are no lines, it won't. So just
|
|
|
|
// factor it in anyway (it can't hurt if it was already done).
|
|
|
|
if (mBullet) {
|
1999-09-01 20:57:37 +00:00
|
|
|
nsRect r;
|
|
|
|
mBullet->GetRect(r);
|
1999-09-15 00:28:10 +00:00
|
|
|
if (r.x < xa) xa = r.x;
|
|
|
|
if (r.y < ya) ya = r.y;
|
|
|
|
nscoord xmost = r.XMost();
|
|
|
|
if (xmost > xb) xb = xmost;
|
|
|
|
nscoord ymost = r.YMost();
|
|
|
|
if (ymost > yb) yb = ymost;
|
1999-03-20 21:57:03 +00:00
|
|
|
}
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
#ifdef NOISY_COMBINED_AREA
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya);
|
1999-03-22 22:42:30 +00:00
|
|
|
#endif
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// If the combined area of our children exceeds our bounding box
|
|
|
|
// then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it.
|
1999-12-06 15:49:53 +00:00
|
|
|
aMetrics.mOverflowArea.x = xa;
|
|
|
|
aMetrics.mOverflowArea.y = ya;
|
|
|
|
aMetrics.mOverflowArea.width = xb - xa;
|
|
|
|
aMetrics.mOverflowArea.height = yb - ya;
|
|
|
|
if ((aMetrics.mOverflowArea.x < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.y < 0) ||
|
|
|
|
(aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
|
|
|
|
(aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
|
1998-12-05 16:02:08 +00:00
|
|
|
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
|
|
|
|
}
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1999-02-09 17:31:33 +00:00
|
|
|
PrepareResizeReflow(aState);
|
|
|
|
return NS_OK;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-08-04 21:18:16 +00:00
|
|
|
|
1998-06-24 17:52:42 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
// Determine the line being impacted
|
|
|
|
PRBool isFloater;
|
1999-04-21 19:58:38 +00:00
|
|
|
nsLineBox* prevLine;
|
|
|
|
nsLineBox* line = FindLineFor(aState.mNextRCFrame, &prevLine, &isFloater);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull == line) {
|
|
|
|
// This can't happen, but just in case it does...
|
|
|
|
return PrepareResizeReflow(aState);
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// XXX: temporary: If the child frame is a floater then punt
|
|
|
|
if (isFloater) {
|
|
|
|
return PrepareResizeReflow(aState);
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
2000-01-12 08:28:24 +00:00
|
|
|
// Figure out which line to mark dirty.
|
|
|
|
MarkLineDirty(line, prevLine);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::MarkLineDirty(nsLineBox* aLine, nsLineBox* aPrevLine)
|
|
|
|
{
|
2000-02-07 15:36:08 +00:00
|
|
|
// Mark aLine dirty
|
|
|
|
aLine->MarkDirty();
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": mark line %p dirty\n", aLine);
|
2000-02-07 15:36:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Mark previous line dirty if its an inline line so that it can
|
|
|
|
// maybe pullup something from the line just affected.
|
|
|
|
// XXX We don't need to do this if aPrevLine ends in a break-after...
|
|
|
|
if (aPrevLine && !aPrevLine->IsBlock()) {
|
|
|
|
aPrevLine->MarkDirty();
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": mark prev-line %p dirty\n", aPrevLine);
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
1999-04-21 19:58:38 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-04-21 19:58:38 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1999-10-12 23:24:22 +00:00
|
|
|
nsresult
|
1999-10-19 23:04:19 +00:00
|
|
|
nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState)
|
1999-03-05 04:21:32 +00:00
|
|
|
{
|
1999-03-05 19:25:44 +00:00
|
|
|
if (nsnull == mBullet) {
|
|
|
|
// Don't bother if there is no bullet
|
1999-10-12 23:24:22 +00:00
|
|
|
return NS_OK;
|
1999-03-05 19:25:44 +00:00
|
|
|
}
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsStyleList* styleList;
|
|
|
|
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
|
|
|
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
|
|
|
if (HaveOutsideBullet()) {
|
|
|
|
// We now have an inside bullet, but used to have an outside
|
1999-10-14 23:10:03 +00:00
|
|
|
// bullet. Adjust the frame line list
|
1999-10-19 23:04:19 +00:00
|
|
|
nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE);
|
1999-10-14 23:10:03 +00:00
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1999-03-05 04:21:32 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
line->mNext = mLines;
|
|
|
|
mLines = line;
|
1999-03-05 04:21:32 +00:00
|
|
|
}
|
|
|
|
mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!HaveOutsideBullet()) {
|
|
|
|
// We now have an outside bullet, but used to have an inside
|
|
|
|
// bullet. Take the bullet frame out of the first lines frame
|
|
|
|
// list.
|
|
|
|
if ((nsnull != mLines) && (mBullet == mLines->mFirstChild)) {
|
|
|
|
nsIFrame* next;
|
|
|
|
mBullet->GetNextSibling(&next);
|
|
|
|
mBullet->SetNextSibling(nsnull);
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 count = mLines->GetChildCount() - 1;
|
|
|
|
NS_ASSERTION(count >= 0, "empty line w/o bullet");
|
|
|
|
mLines->SetChildCount(count);
|
|
|
|
if (0 == count) {
|
1999-03-05 04:21:32 +00:00
|
|
|
nsLineBox* nextLine = mLines->mNext;
|
1999-10-19 23:04:19 +00:00
|
|
|
aState.FreeLineBox(mLines);
|
1999-03-05 04:21:32 +00:00
|
|
|
mLines = nextLine;
|
|
|
|
if (nsnull != nextLine) {
|
|
|
|
nextLine->MarkDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mLines->mFirstChild = next;
|
|
|
|
mLines->MarkDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1999-10-12 23:24:22 +00:00
|
|
|
return NS_OK;
|
1999-03-05 04:21:32 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState)
|
1998-11-12 16:32:56 +00:00
|
|
|
{
|
1999-10-19 23:04:19 +00:00
|
|
|
nsresult rv = UpdateBulletPosition(aState);
|
1999-04-27 22:10:51 +00:00
|
|
|
|
|
|
|
// Mark everything dirty
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
|
|
|
line->MarkDirty();
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
1999-10-12 23:24:22 +00:00
|
|
|
return rv;
|
1998-11-12 16:32:56 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
1998-11-05 19:33:01 +00:00
|
|
|
{
|
1999-09-25 16:50:45 +00:00
|
|
|
// See if we can try and avoid marking all the lines as dirty
|
|
|
|
PRBool tryAndSkipLines = PR_FALSE;
|
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
// we need to calculate if any part of then block itself
|
|
|
|
// is impacted by a floater (bug 19579)
|
|
|
|
aState.GetAvailableSpace();
|
|
|
|
|
|
|
|
// See if this is this a constrained resize reflow that is not impacted by floaters
|
|
|
|
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
|
|
|
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
1999-09-25 16:50:45 +00:00
|
|
|
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
|
|
|
|
|
|
|
// If the text is left-aligned, then we try and avoid reflowing the lines
|
1999-10-29 14:34:53 +00:00
|
|
|
const nsStyleText* styleText = (const nsStyleText*)
|
1999-09-25 16:50:45 +00:00
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
|
1999-10-29 14:34:53 +00:00
|
|
|
if ((NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign) ||
|
|
|
|
((NS_STYLE_TEXT_ALIGN_DEFAULT == styleText->mTextAlign) &&
|
|
|
|
(NS_STYLE_DIRECTION_LTR == aState.mReflowState.mStyleDisplay->mDirection))) {
|
1999-09-25 16:50:45 +00:00
|
|
|
tryAndSkipLines = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
1999-10-29 14:34:53 +00:00
|
|
|
if (gDisableResizeOpt) {
|
|
|
|
tryAndSkipLines = PR_FALSE;
|
|
|
|
}
|
1999-10-15 23:35:10 +00:00
|
|
|
if (gNoisyReflow) {
|
|
|
|
if (!tryAndSkipLines) {
|
|
|
|
const nsStyleText* mStyleText = (const nsStyleText*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": marking all lines dirty: reason=%d availWidth=%d textAlign=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
aState.mReflowState.reason,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
mStyleText->mTextAlign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* line = mLines;
|
1999-09-25 16:50:45 +00:00
|
|
|
if (tryAndSkipLines) {
|
2000-01-03 04:32:13 +00:00
|
|
|
nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
|
|
|
|
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
|
2000-10-09 21:19:36 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedMaxWidth) {
|
|
|
|
newAvailWidth += aState.mReflowState.mComputedMaxWidth;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newAvailWidth += aState.mReflowState.availableWidth;
|
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
} else {
|
2000-10-09 21:19:36 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedMaxWidth) {
|
|
|
|
newAvailWidth += aState.mReflowState.mComputedWidth;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newAvailWidth += aState.mReflowState.availableWidth;
|
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
2000-10-09 21:19:36 +00:00
|
|
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != newAvailWidth, "bad math, newAvailWidth is infinite");
|
2000-01-03 04:32:13 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": trying to avoid marking all lines dirty\n");
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
|
|
|
#endif
|
1999-09-25 16:50:45 +00:00
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
1999-09-25 16:50:45 +00:00
|
|
|
while (nsnull != line) {
|
1999-10-29 14:34:53 +00:00
|
|
|
|
|
|
|
if (line->IsBlock()) {
|
|
|
|
// We have to let child blocks make their own decisions.
|
|
|
|
line->MarkDirty();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We can avoid reflowing *some* inline lines in some cases.
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
|
|
|
line, line->IsImpactedByFloater() ? "" : "not ");
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
1999-10-29 14:34:53 +00:00
|
|
|
if (notWrapping) {
|
|
|
|
// When no-wrap is set then the only line-breaking that
|
|
|
|
// occurs for inline lines is triggered by BR elements or by
|
|
|
|
// newlines. Therefore, we don't need to reflow the line.
|
|
|
|
}
|
|
|
|
else if ((line->mNext && !line->HasBreak()) ||
|
2000-09-11 20:46:44 +00:00
|
|
|
line->ResizeReflowOptimizationDisabled() ||
|
1999-10-29 14:34:53 +00:00
|
|
|
line->HasFloaters() || line->IsImpactedByFloater() ||
|
|
|
|
line->HasPercentageChild() ||
|
|
|
|
(line->mBounds.XMost() > newAvailWidth)) {
|
|
|
|
// When an inline line has:
|
|
|
|
//
|
|
|
|
// - a next line and it doesn't end in a break, or
|
|
|
|
// - floaters, or
|
|
|
|
// - is impacted by a floater, or
|
|
|
|
// - is wider than the new available space
|
|
|
|
//
|
|
|
|
// Then we must reflow it.
|
|
|
|
line->MarkDirty();
|
|
|
|
}
|
1999-09-25 16:50:45 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
1999-10-29 14:34:53 +00:00
|
|
|
if (gNoisyReflow && !line->IsDirty() && !notWrapping) {
|
1999-10-15 23:35:10 +00:00
|
|
|
IndentBy(stdout, gNoiseIndent + 1);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
line, line->mNext,
|
|
|
|
line->IsBlock() ? "block" : "inline",
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
1999-10-15 23:35:10 +00:00
|
|
|
line->HasBreak() ? "has-break " : "",
|
|
|
|
line->HasFloaters() ? "has-floaters " : "",
|
|
|
|
line->IsImpactedByFloater() ? "impacted " : "",
|
1999-10-29 14:34:53 +00:00
|
|
|
line->GetBreakType(),
|
1999-10-15 23:35:10 +00:00
|
|
|
line->mBounds.XMost());
|
|
|
|
}
|
|
|
|
#endif
|
1999-09-25 16:50:45 +00:00
|
|
|
}
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Mark everything dirty
|
|
|
|
while (nsnull != line) {
|
|
|
|
line->MarkDirty();
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//----------------------------------------
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox*
|
1999-04-21 19:58:38 +00:00
|
|
|
nsBlockFrame::FindLineFor(nsIFrame* aFrame,
|
|
|
|
nsLineBox** aPrevLineResult,
|
|
|
|
PRBool* aIsFloaterResult)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-04-21 19:58:38 +00:00
|
|
|
nsLineBox* prevLine = nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* line = mLines;
|
1999-04-21 19:58:38 +00:00
|
|
|
PRBool isFloater = PR_FALSE;
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != line) {
|
|
|
|
if (line->Contains(aFrame)) {
|
1999-04-21 19:58:38 +00:00
|
|
|
break;
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
if (line->HasFloaters()) {
|
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 00:28:10 +00:00
|
|
|
while (fc) {
|
|
|
|
if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame()) {
|
1999-04-21 19:58:38 +00:00
|
|
|
isFloater = PR_TRUE;
|
|
|
|
goto done;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
fc = fc->Next();
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
|
|
|
}
|
1999-04-21 19:58:38 +00:00
|
|
|
prevLine = line;
|
1998-12-05 16:02:08 +00:00
|
|
|
line = line->mNext;
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
|
1999-04-21 19:58:38 +00:00
|
|
|
done:
|
|
|
|
*aIsFloaterResult = isFloater;
|
|
|
|
*aPrevLineResult = prevLine;
|
1998-12-05 16:02:08 +00:00
|
|
|
return line;
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
|
|
|
|
2000-08-24 04:26:43 +00:00
|
|
|
// SEC: added GetCurrentLine() for bug 45152
|
|
|
|
// we need a way for line layout to know what line is being reflowed,
|
|
|
|
// but we don't want to expose the innards of nsBlockReflowState.
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::GetCurrentLine(nsBlockReflowState *aState, nsLineBox ** aOutCurrentLine)
|
|
|
|
{
|
|
|
|
if (!aState || !aOutCurrentLine) return NS_ERROR_FAILURE;
|
|
|
|
*aOutCurrentLine = aState->mCurrentLine;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::RecoverStateFrom(nsBlockReflowState& aState,
|
1999-04-03 18:59:01 +00:00
|
|
|
nsLineBox* aLine,
|
1999-07-14 15:16:56 +00:00
|
|
|
nscoord aDeltaY,
|
|
|
|
nsRect* aDamageRect)
|
1998-09-10 19:32:14 +00:00
|
|
|
{
|
1999-04-03 18:59:01 +00:00
|
|
|
PRBool applyTopMargin = PR_FALSE;
|
1998-12-05 16:02:08 +00:00
|
|
|
if (aLine->IsBlock()) {
|
1999-04-03 18:59:01 +00:00
|
|
|
nsIFrame* framePrevInFlow;
|
|
|
|
aLine->mFirstChild->GetPrevInFlow(&framePrevInFlow);
|
|
|
|
if (nsnull == framePrevInFlow) {
|
|
|
|
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
1998-11-12 16:32:56 +00:00
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
aState.RecoverStateFrom(aLine, applyTopMargin, aDeltaY, aDamageRect);
|
1998-09-10 19:32:14 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Propogate reflow "damage" from the just reflowed line (aLine) to
|
|
|
|
* any subsequent lines that were affected. The only thing that causes
|
|
|
|
* damage is a change to the impact that floaters make.
|
|
|
|
*/
|
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState,
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* aLine,
|
1999-09-15 00:28:10 +00:00
|
|
|
const nsRect& aOldCombinedArea,
|
1998-12-05 16:02:08 +00:00
|
|
|
nscoord aDeltaY)
|
1998-08-28 03:02:39 +00:00
|
|
|
{
|
1999-09-15 00:28:10 +00:00
|
|
|
// See if the line has a relevant combined area, and if it does if
|
|
|
|
// the combined area has changed.
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
if (lineCombinedArea != aLine->mBounds) {
|
|
|
|
if (lineCombinedArea != aOldCombinedArea) {
|
1999-09-15 00:28:10 +00:00
|
|
|
// The line's combined-area changed. Therefore we need to damage
|
|
|
|
// the lines below that were previously (or are now) impacted by
|
|
|
|
// the change. It's possible that a floater shrunk or grew so
|
|
|
|
// use the larger of the impacted area.
|
1999-10-14 23:10:03 +00:00
|
|
|
nscoord newYMost = lineCombinedArea.YMost();
|
1999-09-15 00:28:10 +00:00
|
|
|
nscoord oldYMost = aOldCombinedArea.YMost();
|
|
|
|
nscoord impactYB = newYMost < oldYMost ? oldYMost : newYMost;
|
1999-10-14 23:10:03 +00:00
|
|
|
nscoord impactYA = lineCombinedArea.y;
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// Loop over each subsequent line and mark them dirty if they
|
|
|
|
// intersect the impacted area. Note: we cannot stop after the
|
|
|
|
// first non-intersecting line because lines might be
|
|
|
|
// overlapping because of negative margins.
|
|
|
|
nsLineBox* next = aLine->mNext;
|
|
|
|
while (nsnull != next) {
|
|
|
|
nscoord lineYA = next->mBounds.y + aDeltaY;
|
|
|
|
nscoord lineYB = lineYA + next->mBounds.height;
|
|
|
|
if ((lineYB >= impactYA) && (lineYA < impactYB)) {
|
|
|
|
next->MarkDirty();
|
|
|
|
}
|
|
|
|
next = next->mNext;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
else {
|
|
|
|
// The line's combined area didn't change from last
|
|
|
|
// time. Therefore just sliding subsequent lines will work.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1998-08-28 03:02:39 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
if (aDeltaY) {
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* next = aLine->mNext;
|
|
|
|
while (nsnull != next) {
|
1999-09-15 00:28:10 +00:00
|
|
|
if (!next->IsDirty()) {
|
|
|
|
// Cases we need to find:
|
|
|
|
//
|
|
|
|
// 1. the line was impacted by a floater and now isn't
|
|
|
|
// 2. the line wasn't impacted by a floater and now is
|
|
|
|
//
|
|
|
|
//XXXPerf: An optimization: if the line was and is completely
|
|
|
|
//impacted by a floater and the floater hasn't changed size,
|
|
|
|
//then we don't need to mark the line dirty.
|
|
|
|
aState.GetAvailableSpace(next->mBounds.y + aDeltaY);
|
|
|
|
PRBool wasImpactedByFloater = next->IsImpactedByFloater();
|
2000-03-22 23:19:10 +00:00
|
|
|
PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE;
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n",
|
|
|
|
this, wasImpactedByFloater, isImpactedByFloater);
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
1999-09-15 00:28:10 +00:00
|
|
|
if (wasImpactedByFloater != isImpactedByFloater) {
|
|
|
|
next->MarkDirty();
|
|
|
|
}
|
|
|
|
else if (isImpactedByFloater) {
|
|
|
|
//XXX: Maybe the floater itself changed size?
|
|
|
|
if (next->IsBlock()) {
|
|
|
|
//XXXPerf
|
|
|
|
// Case:
|
|
|
|
// It's possible that more/less of the line is impacted by
|
|
|
|
// the floater than last time. So reflow.
|
|
|
|
next->MarkDirty();
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
next = next->mNext;
|
|
|
|
}
|
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
2000-01-08 03:58:27 +00:00
|
|
|
static PRBool
|
|
|
|
WrappedLinesAreDirty(nsLineBox* aLine)
|
|
|
|
{
|
|
|
|
if (aLine->IsInline()) {
|
|
|
|
while (aLine->IsLineWrapped()) {
|
|
|
|
aLine = aLine->mNext;
|
|
|
|
if (!aLine) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(!aLine->IsBlock(), "didn't expect a block line");
|
|
|
|
if (aLine->IsDirty()) {
|
|
|
|
// we found a continuing line that is dirty
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2000-06-11 22:14:33 +00:00
|
|
|
PRBool nsBlockFrame::IsIncrementalDamageConstrained(const nsBlockReflowState& aState) const
|
|
|
|
{
|
|
|
|
// see if the reflow will go through a text control. if so, we can optimize
|
|
|
|
// because we know the text control won't change size.
|
|
|
|
if (aState.mReflowState.reflowCommand)
|
|
|
|
{
|
|
|
|
nsIFrame *target;
|
|
|
|
aState.mReflowState.reflowCommand->GetTarget(target);
|
|
|
|
while (target)
|
|
|
|
{ // starting with the target's parent, scan for a text control
|
|
|
|
nsIFrame *parent;
|
|
|
|
target->GetParent(&parent);
|
|
|
|
if ((nsIFrame*)this==parent || !parent) // the null check is paranoia, it should never happen
|
|
|
|
break; // we found ourself, so we know there's no text control between us and target
|
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
parent->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
if (frameType)
|
|
|
|
{
|
|
|
|
if (nsLayoutAtoms::textInputFrame == frameType.get())
|
|
|
|
return PR_TRUE; // damage is constrained to the text control innards
|
|
|
|
}
|
|
|
|
target = parent; // advance the loop up the frame tree
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE; // default case, damage is not constrained (or unknown)
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Reflow the dirty lines
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
1998-06-24 17:52:42 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
PRBool keepGoing = PR_TRUE;
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
|
|
|
nsIReflowCommand::ReflowType type;
|
|
|
|
aState.mReflowState.reflowCommand->GetType(type);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
2000-02-22 22:06:19 +00:00
|
|
|
kReflowCommandType[type], type,
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflowing dirty lines");
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" computedWidth=%d\n", aState.mReflowState.mComputedWidth);
|
1999-10-15 23:35:10 +00:00
|
|
|
gNoiseIndent++;
|
1999-09-17 23:16:43 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-11-14 19:28:11 +00:00
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
// Check whether this is an incremental reflow
|
|
|
|
PRBool incrementalReflow = aState.mReflowState.reason ==
|
2000-01-12 08:28:24 +00:00
|
|
|
eReflowReason_Incremental ||
|
|
|
|
aState.mReflowState.reason ==
|
|
|
|
eReflowReason_Dirty;
|
1999-07-14 15:16:56 +00:00
|
|
|
|
2000-02-22 22:06:19 +00:00
|
|
|
nscoord deltaY = 0;
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Reflow the lines that are already ours
|
|
|
|
aState.mPrevLine = nsnull;
|
|
|
|
nsLineBox* line = mLines;
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
2000-02-22 22:06:19 +00:00
|
|
|
{
|
|
|
|
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
|
|
|
aState.mCurrentLine = line;
|
|
|
|
aState.mPrevLine = nsnull;
|
|
|
|
while (line && (line != incrTargetLine))
|
|
|
|
{
|
|
|
|
nsRect damageRect;
|
|
|
|
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
|
|
|
&damageRect : 0);
|
|
|
|
if (incrementalReflow && !damageRect.IsEmpty()) {
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
|
|
|
#endif
|
2000-02-22 22:06:19 +00:00
|
|
|
Invalidate(aState.mPresContext, damageRect);
|
|
|
|
}
|
|
|
|
aState.mPrevLine = line;
|
|
|
|
line = line->mNext;
|
|
|
|
aState.AdvanceToNextLine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != line) {
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsRect lca;
|
|
|
|
line->GetCombinedArea(&lca);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
line, aState.mY, line->IsDirty() ? "yes" : "no",
|
|
|
|
line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
|
|
|
lca.x, lca.y, lca.width, lca.height,
|
|
|
|
deltaY, aState.mPrevBottomMargin);
|
|
|
|
gNoiseIndent++;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1999-10-15 23:35:10 +00:00
|
|
|
|
2000-01-08 03:58:27 +00:00
|
|
|
// If we're supposed to update our maximum width, then we'll also need to
|
|
|
|
// reflow this line if it's line wrapped and any of the continuing lines
|
|
|
|
// are dirty
|
2000-04-17 14:40:46 +00:00
|
|
|
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// Compute the dirty lines "before" YMost, after factoring in
|
|
|
|
// the running deltaY value - the running value is implicit in
|
|
|
|
// aState.mY.
|
|
|
|
nscoord oldHeight = line->mBounds.height;
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect oldCombinedArea;
|
|
|
|
line->GetCombinedArea(&oldCombinedArea);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
2000-06-11 22:14:33 +00:00
|
|
|
// Reflow the dirty line. If it's an incremental reflow, then force
|
|
|
|
// it to invalidate the dirty area if necessary
|
|
|
|
PRBool forceInvalidate = PR_FALSE;
|
|
|
|
if (incrementalReflow) {
|
|
|
|
forceInvalidate = !IsIncrementalDamageConstrained(aState);
|
|
|
|
}
|
|
|
|
rv = ReflowLine(aState, line, &keepGoing, forceInvalidate);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!keepGoing) {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (0 == line->GetChildCount()) {
|
1998-12-07 22:28:55 +00:00
|
|
|
DeleteLine(aState, line);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
nscoord newHeight = line->mBounds.height;
|
|
|
|
deltaY += newHeight - oldHeight;
|
|
|
|
|
|
|
|
// If the next line is clean then check and see if reflowing the
|
|
|
|
// current line "damaged" the next line. Damage occurs when the
|
|
|
|
// current line contains floaters that intrude upon the
|
|
|
|
// subsequent lines.
|
|
|
|
nsLineBox* next = line->mNext;
|
|
|
|
if ((nsnull != next) && !next->IsDirty()) {
|
1999-09-15 00:28:10 +00:00
|
|
|
PropogateReflowDamage(aState, line, oldCombinedArea, deltaY);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-02 21:59:54 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
// XXX what if the slid line doesn't fit because we are in a
|
|
|
|
// vertically constrained situation?
|
|
|
|
// Recover state as if we reflowed this line
|
1999-07-14 15:16:56 +00:00
|
|
|
nsRect damageRect;
|
|
|
|
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
|
|
|
&damageRect : 0);
|
|
|
|
if (incrementalReflow && !damageRect.IsEmpty()) {
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aState.mPresContext, damageRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
1998-09-02 21:59:54 +00:00
|
|
|
}
|
1999-10-15 23:35:10 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
gNoiseIndent--;
|
|
|
|
nsRect lca;
|
|
|
|
line->GetCombinedArea(&lca);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
line, aState.mY,
|
|
|
|
line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
|
|
|
lca.x, lca.y, lca.width, lca.height,
|
|
|
|
deltaY, aState.mPrevBottomMargin);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// If this is an inline frame then its time to stop
|
|
|
|
aState.mPrevLine = line;
|
|
|
|
line = line->mNext;
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.AdvanceToNextLine();
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Pull data from a next-in-flow if we can
|
|
|
|
while (keepGoing && (nsnull != aState.mNextInFlow)) {
|
|
|
|
// Grab first line from our next-in-flow
|
|
|
|
line = aState.mNextInFlow->mLines;
|
|
|
|
if (nsnull == line) {
|
1999-02-09 17:31:33 +00:00
|
|
|
aState.mNextInFlow = (nsBlockFrame*) aState.mNextInFlow->mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
continue;
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX See if the line is not dirty; if it's not maybe we can
|
|
|
|
// avoid the pullup if it can't fit?
|
|
|
|
aState.mNextInFlow->mLines = line->mNext;
|
|
|
|
line->mNext = nsnull;
|
1999-10-14 23:10:03 +00:00
|
|
|
if (0 == line->GetChildCount()) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// The line is empty. Try the next one.
|
|
|
|
NS_ASSERTION(nsnull == line->mFirstChild, "bad empty line");
|
1999-10-19 23:04:19 +00:00
|
|
|
aState.FreeLineBox(line);
|
1998-12-05 16:02:08 +00:00
|
|
|
continue;
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX move to a subroutine: run-in, overflow, pullframe and this do this
|
|
|
|
// Make the children in the line ours.
|
|
|
|
nsIFrame* frame = line->mFirstChild;
|
|
|
|
nsIFrame* lastFrame = nsnull;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1998-12-05 16:02:08 +00:00
|
|
|
while (--n >= 0) {
|
1999-01-14 05:16:23 +00:00
|
|
|
frame->SetParent(this);
|
1999-04-11 04:22:00 +00:00
|
|
|
// When pushing and pulling frames we need to check for whether any
|
|
|
|
// views need to be reparented
|
1999-10-26 04:44:41 +00:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, mNextInFlow, this);
|
1998-12-05 16:02:08 +00:00
|
|
|
lastFrame = frame;
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
lastFrame->SetNextSibling(nsnull);
|
1998-11-14 19:28:11 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Add line to our line list
|
|
|
|
if (nsnull == aState.mPrevLine) {
|
|
|
|
NS_ASSERTION(nsnull == mLines, "bad aState.mPrevLine");
|
|
|
|
mLines = line;
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
NS_ASSERTION(nsnull == aState.mPrevLine->mNext, "bad aState.mPrevLine");
|
|
|
|
aState.mPrevLine->mNext = line;
|
|
|
|
aState.mPrevChild->SetNextSibling(line->mFirstChild);
|
1998-09-02 21:59:54 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Now reflow it and any lines that it makes during it's reflow
|
|
|
|
// (we have to loop here because reflowing the line may case a new
|
|
|
|
// line to be created; see SplitLine's callers for examples of
|
|
|
|
// when this happens).
|
|
|
|
while (nsnull != line) {
|
1999-07-14 15:16:56 +00:00
|
|
|
rv = ReflowLine(aState, line, &keepGoing, incrementalReflow ?
|
1999-08-01 16:50:52 +00:00
|
|
|
PR_TRUE : PR_FALSE);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!keepGoing) {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (0 == line->GetChildCount()) {
|
1998-12-07 22:28:55 +00:00
|
|
|
DeleteLine(aState, line);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
|
|
|
}
|
1998-11-14 19:28:11 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// If this is an inline frame then its time to stop
|
|
|
|
aState.mPrevLine = line;
|
|
|
|
line = line->mNext;
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.AdvanceToNextLine();
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
1998-11-14 19:28:11 +00:00
|
|
|
|
1999-07-14 17:26:20 +00:00
|
|
|
// Handle an odd-ball case: a list-item with no lines
|
|
|
|
if (mBullet && HaveOutsideBullet() && !mLines) {
|
1999-08-27 21:45:37 +00:00
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
|
|
|
ReflowBullet(aState, metrics);
|
|
|
|
|
|
|
|
// There are no lines so we have to fake up some y motion so that
|
|
|
|
// we end up with *some* height.
|
|
|
|
aState.mY += metrics.height;
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
gNoiseIndent--;
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": done reflowing dirty lines (status=%x)\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
aState.mReflowStatus);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-06-27 22:56:09 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-07 22:28:55 +00:00
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
|
1999-02-12 17:45:58 +00:00
|
|
|
nsLineBox* aLine)
|
1998-12-07 22:28:55 +00:00
|
|
|
{
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
|
|
|
|
if (0 == aLine->GetChildCount()) {
|
1998-12-07 22:28:55 +00:00
|
|
|
if (nsnull == aState.mPrevLine) {
|
|
|
|
NS_ASSERTION(aLine == mLines, "huh");
|
|
|
|
mLines = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ASSERTION(aState.mPrevLine->mNext == aLine, "bad prev-line");
|
|
|
|
aState.mPrevLine->mNext = aLine->mNext;
|
|
|
|
}
|
1999-10-19 23:04:19 +00:00
|
|
|
aState.FreeLineBox(aLine);
|
1998-12-07 22:28:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Reflow a line. The line will either contain a single block frame
|
2000-03-22 23:19:10 +00:00
|
|
|
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
1998-12-05 16:02:08 +00:00
|
|
|
* whether or not the caller should continue to reflow more lines.
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
1999-03-18 21:03:25 +00:00
|
|
|
nsLineBox* aLine,
|
1999-07-14 15:16:56 +00:00
|
|
|
PRBool* aKeepReflowGoing,
|
1999-08-01 16:50:52 +00:00
|
|
|
PRBool aDamageDirtyArea)
|
1998-11-19 18:09:57 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult rv = NS_OK;
|
1998-11-11 03:55:55 +00:00
|
|
|
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ABORT_IF_FALSE(aLine->GetChildCount(), "reflowing empty line");
|
1998-11-11 03:55:55 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
// Setup the line-layout for the new line
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mCurrentLine = aLine;
|
|
|
|
aLine->ClearDirty();
|
1998-11-11 03:55:55 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Now that we know what kind of line we have, reflow it
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect oldCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&oldCombinedArea);
|
1999-07-14 15:16:56 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
if (aLine->IsBlock()) {
|
1999-03-18 21:03:25 +00:00
|
|
|
rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
|
1999-07-14 15:16:56 +00:00
|
|
|
|
|
|
|
// We expect blocks to damage any area inside their bounds that is
|
|
|
|
// dirty; however, if the frame changes size or position then we
|
|
|
|
// need to do some repainting
|
1999-08-01 16:50:52 +00:00
|
|
|
if (aDamageDirtyArea) {
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
if ((oldCombinedArea.x != lineCombinedArea.x) ||
|
|
|
|
(oldCombinedArea.y != lineCombinedArea.y)) {
|
2000-06-11 22:14:33 +00:00
|
|
|
// The block has moved, and so to be safe we need to repaint
|
1999-07-14 15:16:56 +00:00
|
|
|
// XXX We need to improve on this...
|
1999-08-01 16:50:52 +00:00
|
|
|
nsRect dirtyRect;
|
1999-10-14 23:10:03 +00:00
|
|
|
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
|
|
|
|
} else {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (oldCombinedArea.width != lineCombinedArea.width) {
|
1999-08-01 16:50:52 +00:00
|
|
|
nsRect dirtyRect;
|
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
// Just damage the vertical strip that was either added or went
|
|
|
|
// away
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.x = PR_MIN(oldCombinedArea.XMost(),
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.XMost());
|
|
|
|
dirtyRect.y = lineCombinedArea.y;
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.width = PR_MAX(oldCombinedArea.XMost(),
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.XMost()) -
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.x;
|
|
|
|
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.height);
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
if (oldCombinedArea.height != lineCombinedArea.height) {
|
1999-08-01 16:50:52 +00:00
|
|
|
nsRect dirtyRect;
|
|
|
|
|
1999-07-14 15:16:56 +00:00
|
|
|
// Just damage the horizontal strip that was either added or went
|
|
|
|
// away
|
1999-10-14 23:10:03 +00:00
|
|
|
dirtyRect.x = lineCombinedArea.x;
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.y = PR_MIN(oldCombinedArea.YMost(),
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.YMost());
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.width = PR_MAX(oldCombinedArea.width,
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.width);
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.YMost()) -
|
1999-08-01 16:50:52 +00:00
|
|
|
dirtyRect.y;
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2000-01-03 04:32:13 +00:00
|
|
|
aLine->SetLineWrapped(PR_FALSE);
|
2000-01-08 03:58:27 +00:00
|
|
|
|
|
|
|
// If we're supposed to update the maximum width, then we'll need to reflow
|
|
|
|
// the line with an unconstrained width (which will give us the new maximum
|
|
|
|
// width), then we'll reflow it again with the constrained width.
|
|
|
|
// We only do this if this is a beginning line, i.e., don't do this for
|
|
|
|
// lines associated with content that line wrapped (see ReflowDirtyLines()
|
|
|
|
// for details).
|
|
|
|
// XXX This approach doesn't work when floaters are involved in which case
|
|
|
|
// we'll either need to recover the floater state that applies to the
|
|
|
|
// unconstrained reflow or keep it around in a separate space manager...
|
2000-01-10 05:14:47 +00:00
|
|
|
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
2000-01-08 03:58:27 +00:00
|
|
|
nscoord oldY = aState.mY;
|
|
|
|
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
2000-04-17 14:40:46 +00:00
|
|
|
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
2000-01-30 18:42:23 +00:00
|
|
|
|
|
|
|
// First reflow the line with an unconstrained width. When doing this
|
|
|
|
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
|
|
|
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
|
|
|
// associated floater we don't end up resetting the line's right edge and
|
|
|
|
// have it think the width is unconstrained...
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
2000-04-19 03:12:13 +00:00
|
|
|
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
2000-01-30 18:42:23 +00:00
|
|
|
aState.mY = oldY;
|
|
|
|
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
2000-01-08 03:58:27 +00:00
|
|
|
|
|
|
|
// Update the line's maximum width
|
|
|
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n",
|
2000-05-14 04:56:25 +00:00
|
|
|
this, aLine, aLine->mMaximumWidth);
|
|
|
|
#endif
|
2000-01-08 03:58:27 +00:00
|
|
|
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
|
|
|
|
// Remove any floaters associated with the line from the space
|
|
|
|
// manager
|
|
|
|
aLine->RemoveFloatersFromSpaceManager(aState.mSpaceManager);
|
|
|
|
|
|
|
|
// Now reflow the line again this time without having it compute
|
2000-01-28 03:12:30 +00:00
|
|
|
// the maximum width or max-element-size.
|
|
|
|
// Note: we need to reset both member variables, because the inline
|
|
|
|
// code examines mComputeMaxElementSize and if there is a placeholder
|
|
|
|
// on this line the code to reflow the floater looks at both...
|
2000-04-17 14:40:46 +00:00
|
|
|
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
|
|
|
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
2000-05-14 04:56:25 +00:00
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
|
|
|
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
2000-04-19 03:12:13 +00:00
|
|
|
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea);
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
|
|
|
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
2000-01-08 03:58:27 +00:00
|
|
|
|
|
|
|
} else {
|
2000-04-19 03:12:13 +00:00
|
|
|
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea);
|
2000-05-14 04:56:25 +00:00
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH))
|
|
|
|
{
|
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n",
|
2000-05-14 04:56:25 +00:00
|
|
|
this, aLine, aLine->mMaximumWidth);
|
|
|
|
#endif
|
|
|
|
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
}
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE))
|
|
|
|
{
|
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaxElementWidth to %d\n",
|
2000-05-14 04:56:25 +00:00
|
|
|
this, aLine, aLine->mMaxElementWidth);
|
|
|
|
#endif
|
|
|
|
aState.UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
|
|
|
}
|
|
|
|
}
|
2000-01-08 03:58:27 +00:00
|
|
|
}
|
1999-07-14 15:16:56 +00:00
|
|
|
|
|
|
|
// We don't really know what changed in the line, so use the union
|
|
|
|
// of the old and new combined areas
|
2000-08-24 04:26:43 +00:00
|
|
|
// SEC: added "aLine->IsForceInvalidate()" for bug 45152
|
|
|
|
if (aDamageDirtyArea || aLine->IsForceInvalidate()) {
|
|
|
|
aLine->SetForceInvalidate(PR_FALSE); // doing the invalidate now, force flag to off
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect combinedArea;
|
|
|
|
aLine->GetCombinedArea(&combinedArea);
|
1999-08-01 16:50:52 +00:00
|
|
|
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect dirtyRect;
|
|
|
|
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate because %s is true (%d, %d, %d, %d)\n",
|
2000-09-15 06:20:07 +00:00
|
|
|
this, aDamageDirtyArea ? "aDamageDirtyArea" : "aLine->IsForceInvalidate",
|
|
|
|
dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
2000-10-27 14:14:36 +00:00
|
|
|
if (aLine->IsForceInvalidate())
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" dirty line is %p\n");
|
2000-04-17 14:40:46 +00:00
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
1999-07-14 15:16:56 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-11-14 19:28:11 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Pull frame from the next available location (one of our lines or
|
|
|
|
* one of our next-in-flows lines).
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
1999-03-16 19:36:00 +00:00
|
|
|
nsLineBox* aLine,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aDamageDeletedLines,
|
1999-03-16 19:36:00 +00:00
|
|
|
nsIFrame*& aFrameResult)
|
1998-11-14 19:28:11 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
PRBool stopPulling;
|
|
|
|
aFrameResult = nsnull;
|
|
|
|
|
|
|
|
// First check our remaining lines
|
|
|
|
while (nsnull != aLine->mNext) {
|
2000-04-19 03:12:13 +00:00
|
|
|
rv = PullFrame(aState, aLine, &aLine->mNext, PR_FALSE, aDamageDeletedLines,
|
1998-12-05 16:02:08 +00:00
|
|
|
aFrameResult, stopPulling);
|
|
|
|
if (NS_FAILED(rv) || stopPulling) {
|
|
|
|
return rv;
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
|
|
|
}
|
1998-11-17 01:04:45 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Pull frames from the next-in-flow(s) until we can't
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame* nextInFlow = aState.mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != nextInFlow) {
|
|
|
|
nsLineBox* line = nextInFlow->mLines;
|
|
|
|
if (nsnull == line) {
|
1999-02-09 17:31:33 +00:00
|
|
|
nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mNextInFlow = nextInFlow;
|
|
|
|
continue;
|
|
|
|
}
|
2000-04-19 03:12:13 +00:00
|
|
|
rv = PullFrame(aState, aLine, &nextInFlow->mLines, PR_TRUE, aDamageDeletedLines,
|
1998-12-05 16:02:08 +00:00
|
|
|
aFrameResult, stopPulling);
|
|
|
|
if (NS_FAILED(rv) || stopPulling) {
|
|
|
|
return rv;
|
|
|
|
}
|
1998-11-17 01:04:45 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
1998-11-14 19:28:11 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
1999-03-24 15:42:19 +00:00
|
|
|
* Try to pull a frame out of a line pointed at by aFromList. If a
|
|
|
|
* frame is pulled then aPulled will be set to PR_TRUE. In addition,
|
|
|
|
* if aUpdateGeometricParent is set then the pulled frames geometric
|
1998-12-05 16:02:08 +00:00
|
|
|
* parent will be updated (e.g. when pulling from a next-in-flows line
|
|
|
|
* list).
|
|
|
|
*
|
|
|
|
* Note: pulling a frame from a line that is a place-holder frame
|
|
|
|
* doesn't automatically remove the corresponding floater from the
|
|
|
|
* line's floater array. This happens indirectly: either the line gets
|
|
|
|
* emptied (and destroyed) or the line gets reflowed (because we mark
|
|
|
|
* it dirty) and the code at the top of ReflowLine empties the
|
|
|
|
* array. So eventually, it will be removed, just not right away.
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
1999-02-18 18:25:45 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsLineBox** aFromList,
|
|
|
|
PRBool aUpdateGeometricParent,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aDamageDeletedLines,
|
1999-02-18 18:25:45 +00:00
|
|
|
nsIFrame*& aFrameResult,
|
|
|
|
PRBool& aStopPulling)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* fromLine = *aFromList;
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ABORT_IF_FALSE(fromLine, "bad line to pull from");
|
|
|
|
NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line");
|
|
|
|
NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line");
|
|
|
|
|
|
|
|
if (fromLine->IsBlock()) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// If our line is not empty and the child in aFromLine is a block
|
|
|
|
// then we cannot pull up the frame into this line. In this case
|
|
|
|
// we stop pulling.
|
|
|
|
aStopPulling = PR_TRUE;
|
|
|
|
aFrameResult = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Take frame from fromLine
|
|
|
|
nsIFrame* frame = fromLine->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
|
|
|
|
|
|
|
PRInt32 fromLineChildCount = fromLine->GetChildCount();
|
|
|
|
if (0 != --fromLineChildCount) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// Mark line dirty now that we pulled a child
|
1999-10-14 23:10:03 +00:00
|
|
|
fromLine->SetChildCount(fromLineChildCount);
|
1998-12-05 16:02:08 +00:00
|
|
|
fromLine->MarkDirty();
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Free up the fromLine now that it's empty
|
2000-04-19 03:12:13 +00:00
|
|
|
// Its bounds might need to be redrawn, though.
|
|
|
|
if (aDamageDeletedLines) {
|
|
|
|
Invalidate(aState.mPresContext, fromLine->mBounds);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
*aFromList = fromLine->mNext;
|
1999-10-19 23:04:19 +00:00
|
|
|
aState.FreeLineBox(fromLine);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Change geometric parents
|
|
|
|
if (aUpdateGeometricParent) {
|
1999-04-11 04:22:00 +00:00
|
|
|
// Before we set the new parent frame get the current parent
|
|
|
|
nsIFrame* oldParentFrame;
|
|
|
|
frame->GetParent(&oldParentFrame);
|
1999-01-14 05:16:23 +00:00
|
|
|
frame->SetParent(this);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
1999-04-11 04:22:00 +00:00
|
|
|
// When pushing and pulling frames we need to check for whether any
|
|
|
|
// views need to be reparented
|
|
|
|
NS_ASSERTION(oldParentFrame != this, "unexpected parent frame");
|
1999-10-26 04:44:41 +00:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, oldParentFrame, this);
|
1999-04-11 04:22:00 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// The frame is being pulled from a next-in-flow; therefore we
|
|
|
|
// need to add it to our sibling list.
|
|
|
|
if (nsnull != aState.mPrevChild) {
|
|
|
|
aState.mPrevChild->SetNextSibling(frame);
|
|
|
|
}
|
|
|
|
frame->SetNextSibling(nsnull);
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Stop pulling because we found a frame to pull
|
|
|
|
aStopPulling = PR_TRUE;
|
|
|
|
aFrameResult = frame;
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-09-23 20:10:40 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-09-23 20:10:40 +00:00
|
|
|
|
1999-11-19 15:33:29 +00:00
|
|
|
static void
|
|
|
|
PlaceFrameView(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsIView* view;
|
|
|
|
aFrame->GetView(aPresContext, &view);
|
|
|
|
if (view) {
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
nsContainerFrame::PositionChildViews(aPresContext, aFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-06-18 16:25:41 +00:00
|
|
|
void
|
1999-09-16 19:56:36 +00:00
|
|
|
nsBlockFrame::SlideLine(nsBlockReflowState& aState,
|
1999-04-03 18:59:01 +00:00
|
|
|
nsLineBox* aLine, nscoord aDY)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1999-09-15 00:28:10 +00:00
|
|
|
// Adjust line state
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SlideBy(aDY);
|
1999-09-15 00:28:10 +00:00
|
|
|
|
|
|
|
// Adjust the frames in the line
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* kid = aLine->mFirstChild;
|
1999-09-15 00:28:10 +00:00
|
|
|
if (!kid) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aLine->IsBlock()) {
|
|
|
|
nsRect r;
|
1998-12-05 16:02:08 +00:00
|
|
|
kid->GetRect(r);
|
1999-09-16 19:56:36 +00:00
|
|
|
if (aDY) {
|
|
|
|
r.y += aDY;
|
1999-10-26 04:44:41 +00:00
|
|
|
kid->SetRect(aState.mPresContext, r);
|
1999-09-16 19:56:36 +00:00
|
|
|
}
|
1998-11-20 22:24:20 +00:00
|
|
|
|
1999-11-19 15:33:29 +00:00
|
|
|
// Make sure the frame's view and any child views are updated
|
|
|
|
::PlaceFrameView(aState.mPresContext, kid);
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// If the child has any floaters that impact the space-manager,
|
|
|
|
// place them now so that they are present in the space-manager
|
|
|
|
// again (they were removed by the space-manager's frame when
|
|
|
|
// the reflow began).
|
|
|
|
nsBlockFrame* bf;
|
|
|
|
nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &bf);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
1999-09-16 19:56:36 +00:00
|
|
|
// Translate spacemanager to the child blocks upper-left corner
|
|
|
|
// so that when it places its floaters (which are relative to
|
|
|
|
// it) the right coordinates are used. Note that we have already
|
|
|
|
// been translated by our border+padding so factor that in to
|
|
|
|
// get the right translation.
|
|
|
|
const nsMargin& bp = aState.BorderPadding();
|
|
|
|
nscoord dx = r.x - bp.left;
|
|
|
|
nscoord dy = r.y - bp.top;
|
|
|
|
aState.mSpaceManager->Translate(dx, dy);
|
|
|
|
bf->UpdateSpaceManager(aState.mPresContext, aState.mSpaceManager);
|
|
|
|
aState.mSpaceManager->Translate(-dx, -dy);
|
1998-11-12 16:32:56 +00:00
|
|
|
}
|
1998-09-23 02:25:26 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
else {
|
1999-11-19 15:33:29 +00:00
|
|
|
// Adjust the Y coordinate of the frames in the line.
|
|
|
|
// Note: we need to re-position views even if aDY is 0, because
|
|
|
|
// one of our parent frames may have moved and so the view's position
|
|
|
|
// relative to its parent may have changed
|
|
|
|
nsRect r;
|
|
|
|
PRInt32 n = aLine->GetChildCount();
|
|
|
|
while (--n >= 0) {
|
|
|
|
if (aDY) {
|
1999-09-15 00:28:10 +00:00
|
|
|
kid->GetRect(r);
|
|
|
|
r.y += aDY;
|
1999-10-26 04:44:41 +00:00
|
|
|
kid->SetRect(aState.mPresContext, r);
|
1999-09-15 00:28:10 +00:00
|
|
|
}
|
1999-11-19 15:33:29 +00:00
|
|
|
// Make sure the frame's view and any child views are updated
|
|
|
|
::PlaceFrameView(aState.mPresContext, kid);
|
|
|
|
kid->GetNextSibling(&kid);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-23 02:25:26 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::UpdateSpaceManager(nsIPresContext* aPresContext,
|
|
|
|
nsISpaceManager* aSpaceManager)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
1999-09-15 00:28:10 +00:00
|
|
|
// Place the floaters in the spacemanager
|
1999-10-14 23:10:03 +00:00
|
|
|
if (line->HasFloaters()) {
|
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 00:28:10 +00:00
|
|
|
while (fc) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
|
|
|
aSpaceManager->AddRectRegion(floater, fc->mRegion);
|
|
|
|
#ifdef NOISY_SPACEMANAGER
|
|
|
|
nscoord tx, ty;
|
|
|
|
aSpaceManager->GetTranslation(tx, ty);
|
|
|
|
nsFrame::ListTag(stdout, this);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": UpdateSpaceManager: AddRectRegion: txy=%d,%d {%d,%d,%d,%d}\n",
|
1999-09-15 00:28:10 +00:00
|
|
|
tx, ty,
|
|
|
|
fc->mRegion.x, fc->mRegion.y,
|
|
|
|
fc->mRegion.width, fc->mRegion.height);
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1999-09-15 00:28:10 +00:00
|
|
|
fc = fc->Next();
|
1998-10-06 00:38:56 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tell kids about the move too
|
1999-09-15 00:28:10 +00:00
|
|
|
if (line->mFirstChild && line->IsBlock()) {
|
|
|
|
// If the child has any floaters that impact the space-manager,
|
|
|
|
// place them now so that they are present in the space-manager
|
|
|
|
// again (they were removed by the space-manager's frame when
|
|
|
|
// the reflow began).
|
|
|
|
nsBlockFrame* bf;
|
|
|
|
nsresult rv = line->mFirstChild->QueryInterface(kBlockFrameCID,
|
|
|
|
(void**) &bf);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsPoint origin;
|
|
|
|
bf->GetOrigin(origin);
|
|
|
|
|
|
|
|
// Translate spacemanager to the child blocks upper-left
|
|
|
|
// corner so that when it places its floaters (which are
|
|
|
|
// relative to it) the right coordinates are used.
|
|
|
|
aSpaceManager->Translate(origin.x, origin.y);
|
|
|
|
bf->UpdateSpaceManager(aPresContext, aSpaceManager);
|
|
|
|
aSpaceManager->Translate(-origin.x, -origin.y);
|
1998-10-06 00:38:56 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
line = line->mNext;
|
1998-09-23 02:25:26 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-02-23 19:18:12 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::AttributeChanged(nsIPresContext* aPresContext,
|
|
|
|
nsIContent* aChild,
|
1999-10-15 23:16:45 +00:00
|
|
|
PRInt32 aNameSpaceID,
|
1999-02-23 19:18:12 +00:00
|
|
|
nsIAtom* aAttribute,
|
|
|
|
PRInt32 aHint)
|
|
|
|
{
|
|
|
|
nsresult rv = nsBlockFrameSuper::AttributeChanged(aPresContext, aChild,
|
1999-10-15 23:16:45 +00:00
|
|
|
aNameSpaceID, aAttribute, aHint);
|
1999-02-23 19:18:12 +00:00
|
|
|
|
|
|
|
if (NS_OK != rv) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (nsHTMLAtoms::start == aAttribute) {
|
1999-03-05 19:25:44 +00:00
|
|
|
// XXX Not sure if this is necessary anymore
|
2000-01-22 01:16:50 +00:00
|
|
|
RenumberLists(aPresContext);
|
1999-02-23 19:18:12 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
|
|
|
|
nsIReflowCommand* reflowCmd;
|
|
|
|
rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
|
|
|
|
nsIReflowCommand::ContentChanged,
|
|
|
|
nsnull,
|
|
|
|
aAttribute);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
shell->AppendReflowCommand(reflowCmd);
|
|
|
|
NS_RELEASE(reflowCmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (nsHTMLAtoms::value == aAttribute) {
|
|
|
|
const nsStyleDisplay* styleDisplay;
|
|
|
|
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
|
|
|
if (NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) {
|
|
|
|
nsIFrame* nextAncestor = mParent;
|
|
|
|
nsBlockFrame* blockParent = nsnull;
|
|
|
|
|
|
|
|
// Search for the closest ancestor that's a block frame. We
|
|
|
|
// make the assumption that all related list items share a
|
|
|
|
// common block parent.
|
|
|
|
while (nextAncestor != nsnull) {
|
|
|
|
if (NS_OK == nextAncestor->QueryInterface(kBlockFrameCID,
|
|
|
|
(void**)&blockParent)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nextAncestor->GetParent(&nextAncestor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tell the enclosing block frame to renumber list items within
|
|
|
|
// itself
|
|
|
|
if (nsnull != blockParent) {
|
1999-03-05 19:25:44 +00:00
|
|
|
// XXX Not sure if this is necessary anymore
|
2000-01-22 01:16:50 +00:00
|
|
|
blockParent->RenumberLists(aPresContext);
|
1999-02-23 19:18:12 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
|
|
|
|
nsIReflowCommand* reflowCmd;
|
|
|
|
rv = NS_NewHTMLReflowCommand(&reflowCmd, blockParent,
|
|
|
|
nsIReflowCommand::ContentChanged,
|
|
|
|
nsnull,
|
|
|
|
aAttribute);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
shell->AppendReflowCommand(reflowCmd);
|
|
|
|
NS_RELEASE(reflowCmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame*
|
|
|
|
nsBlockFrame::FindFollowingBlockFrame(nsIFrame* aFrame)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame* followingBlockFrame = nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* frame = aFrame;
|
|
|
|
for (;;) {
|
|
|
|
nsIFrame* nextFrame;
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&nextFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull != nextFrame) {
|
|
|
|
const nsStyleDisplay* display;
|
|
|
|
nextFrame->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&) display);
|
|
|
|
if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) {
|
1999-02-09 17:31:33 +00:00
|
|
|
followingBlockFrame = (nsBlockFrame*) nextFrame;
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) {
|
|
|
|
// If it's a text-frame and it's just whitespace and we are
|
|
|
|
// in a normal whitespace situation THEN skip it and keep
|
|
|
|
// going...
|
|
|
|
// XXX WRITE ME!
|
|
|
|
}
|
|
|
|
frame = nextFrame;
|
1998-10-06 00:38:56 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else
|
|
|
|
break;
|
1998-10-02 21:50:53 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return followingBlockFrame;
|
|
|
|
}
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1999-03-27 01:22:14 +00:00
|
|
|
PRBool
|
|
|
|
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine)
|
|
|
|
{
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
1999-03-27 01:22:14 +00:00
|
|
|
// Apply short-circuit check to avoid searching the line list
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aState.IsAdjacentWithTop()) {
|
|
|
|
// If we aren't at the top Y coordinate then something of non-zero
|
|
|
|
// height must have been placed. Therefore the childs top-margin
|
|
|
|
// applies.
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
1999-03-27 01:22:14 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if this line is "essentially" the first line
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (line != aLine) {
|
|
|
|
if (line->IsBlock()) {
|
|
|
|
// A line which preceeds aLine contains a block; therefore the
|
|
|
|
// top margin applies.
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
1999-03-27 01:22:14 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-09-04 21:44:48 +00:00
|
|
|
// No need to apply the top margin if the line has floaters. We
|
|
|
|
// should collapse anyway (bug 44419)
|
1999-03-27 01:22:14 +00:00
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The line being reflowed is "essentially" the first line in the
|
|
|
|
// block. Therefore its top-margin will be collapsed by the
|
|
|
|
// generational collapsing logic with its parent (us).
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsBlockFrame::GetTopBlockChild()
|
|
|
|
{
|
|
|
|
nsIFrame* firstChild = mLines ? mLines->mFirstChild : nsnull;
|
|
|
|
if (firstChild) {
|
|
|
|
if (mLines->IsBlock()) {
|
|
|
|
// Winner
|
|
|
|
return firstChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the first line is not a block line then the second line must
|
|
|
|
// be a block line otherwise the top child can't be a block.
|
|
|
|
nsLineBox* next = mLines->mNext;
|
|
|
|
if ((nsnull == next) || !next->IsBlock()) {
|
|
|
|
// There is no line after the first line or its not a block so
|
|
|
|
// don't bother trying to skip over the first line.
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The only time we can skip over the first line and pretend its
|
|
|
|
// not there is if the line contains only compressed
|
|
|
|
// whitespace. If white-space is significant to this frame then we
|
|
|
|
// can't skip over the line.
|
|
|
|
const nsStyleText* styleText;
|
|
|
|
GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText);
|
1999-03-31 04:10:27 +00:00
|
|
|
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
|
|
|
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
1999-03-27 01:22:14 +00:00
|
|
|
// Whitespace is significant
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if each frame is a text frame that contains nothing but
|
|
|
|
// whitespace.
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = mLines->GetChildCount();
|
1999-03-27 01:22:14 +00:00
|
|
|
while (--n >= 0) {
|
|
|
|
nsIContent* content;
|
|
|
|
nsresult rv = firstChild->GetContent(&content);
|
|
|
|
if (NS_FAILED(rv) || (nsnull == content)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
nsITextContent* tc;
|
|
|
|
rv = content->QueryInterface(kITextContentIID, (void**) &tc);
|
|
|
|
NS_RELEASE(content);
|
|
|
|
if (NS_FAILED(rv) || (nsnull == tc)) {
|
1999-03-27 02:56:52 +00:00
|
|
|
return nsnull;
|
1999-03-27 01:22:14 +00:00
|
|
|
}
|
|
|
|
PRBool isws = PR_FALSE;
|
|
|
|
tc->IsOnlyWhitespace(&isws);
|
|
|
|
NS_RELEASE(tc);
|
|
|
|
if (!isws) {
|
1999-03-27 02:56:52 +00:00
|
|
|
return nsnull;
|
1999-03-27 01:22:14 +00:00
|
|
|
}
|
|
|
|
firstChild->GetNextSibling(&firstChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we make it to this point then every frame on the first line
|
|
|
|
// was compressible white-space. Since we already know that the
|
|
|
|
// second line contains a block, that block is the
|
|
|
|
// top-block-child.
|
|
|
|
return next->mFirstChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
1999-02-12 17:45:58 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
PRBool* aKeepReflowGoing)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-02-12 17:45:58 +00:00
|
|
|
NS_PRECONDITION(*aKeepReflowGoing, "bad caller");
|
1998-07-10 21:45:30 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult rv = NS_OK;
|
1998-11-17 22:28:51 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
|
|
|
|
1999-03-24 15:42:19 +00:00
|
|
|
// Prepare the block reflow engine
|
1998-12-05 16:02:08 +00:00
|
|
|
const nsStyleDisplay* display;
|
|
|
|
frame->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&) display);
|
1999-03-05 04:21:32 +00:00
|
|
|
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
|
|
|
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
1999-03-05 04:21:32 +00:00
|
|
|
brc.SetNextRCFrame(aState.mNextRCFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
1999-03-27 01:22:14 +00:00
|
|
|
// See if we should apply the top margin. If the block frame being
|
|
|
|
// reflowed is a continuation (non-null prev-in-flow) then we don't
|
|
|
|
// apply its top margin because its not significant. Otherwise, dig
|
|
|
|
// deeper.
|
|
|
|
PRBool applyTopMargin = PR_FALSE;
|
|
|
|
nsIFrame* framePrevInFlow;
|
|
|
|
frame->GetPrevInFlow(&framePrevInFlow);
|
|
|
|
if (nsnull == framePrevInFlow) {
|
|
|
|
applyTopMargin = ShouldApplyTopMargin(aState, aLine);
|
|
|
|
}
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
// Clear past floaters before the block if the clear style is not none
|
1999-10-12 23:24:22 +00:00
|
|
|
PRUint8 breakType = display->mBreakType;
|
|
|
|
aLine->SetBreakType(breakType);
|
|
|
|
if (NS_STYLE_CLEAR_NONE != breakType) {
|
|
|
|
PRBool alsoApplyTopMargin = aState.ClearPastFloaters(breakType);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (alsoApplyTopMargin) {
|
|
|
|
applyTopMargin = PR_TRUE;
|
|
|
|
}
|
1999-09-16 19:56:36 +00:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": y=%d child ", aState.mY);
|
1999-09-16 19:56:36 +00:00
|
|
|
ListTag(stdout, frame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" has clear of %d => %s, mPrevBottomMargin=%d\n",
|
1999-10-14 23:10:03 +00:00
|
|
|
breakType,
|
1999-09-16 19:56:36 +00:00
|
|
|
applyTopMargin ? "applyTopMargin" : "nope",
|
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-08-04 21:18:16 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
nscoord topMargin = 0;
|
|
|
|
if (applyTopMargin) {
|
|
|
|
// Precompute the blocks top margin value so that we can get the
|
|
|
|
// correct available space (there might be a floater that's
|
|
|
|
// already been placed below the aState.mPrevBottomMargin
|
|
|
|
|
|
|
|
// Setup a reflowState to get the style computed margin-top value
|
|
|
|
|
|
|
|
// The availSpace here is irrelevant to our needs - all we want
|
|
|
|
// out if this setup is the margin-top value which doesn't depend
|
|
|
|
// on the childs available space.
|
|
|
|
nsSize availSpace(aState.mContentArea.width, NS_UNCONSTRAINEDSIZE);
|
1999-11-24 06:03:41 +00:00
|
|
|
nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
|
1999-10-21 20:43:48 +00:00
|
|
|
frame, availSpace);
|
1999-10-15 23:35:10 +00:00
|
|
|
|
|
|
|
// Now compute the collapsed margin-top value
|
|
|
|
topMargin =
|
|
|
|
nsBlockReflowContext::ComputeCollapsedTopMargin(aState.mPresContext,
|
|
|
|
reflowState);
|
|
|
|
|
|
|
|
// And collapse it with the previous bottom margin to get the final value
|
|
|
|
topMargin =
|
|
|
|
nsBlockReflowContext::MaxMargin(topMargin, aState.mPrevBottomMargin);
|
|
|
|
|
|
|
|
// Temporarily advance the running Y value so that the
|
|
|
|
// GetAvailableSpace method will return the right available
|
|
|
|
// space. This undone as soon as the margin is computed.
|
|
|
|
aState.mY += topMargin;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Compute the available space for the block
|
1999-10-15 23:35:10 +00:00
|
|
|
aState.GetAvailableSpace();
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false");
|
2000-03-22 23:19:10 +00:00
|
|
|
#endif
|
|
|
|
PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE;
|
|
|
|
aLine->SetLineIsImpactedByFloater(isImpacted);
|
1999-04-03 18:59:01 +00:00
|
|
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
|
|
|
frame->IsSplittable(splitType);
|
|
|
|
nsRect availSpace;
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
1998-11-17 22:28:51 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
// Now put the Y coordinate back and flow the block letting the
|
|
|
|
// block reflow context compute the same top margin value we just
|
|
|
|
// computed (sigh).
|
|
|
|
if (topMargin) {
|
|
|
|
aState.mY -= topMargin;
|
|
|
|
availSpace.y -= topMargin;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != availSpace.height) {
|
|
|
|
availSpace.height += topMargin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Reflow the block into the available space
|
1999-06-08 00:30:26 +00:00
|
|
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
1999-01-16 20:58:17 +00:00
|
|
|
nsMargin computedOffsets;
|
1999-10-15 23:35:10 +00:00
|
|
|
rv = brc.ReflowBlock(frame, availSpace,
|
|
|
|
applyTopMargin, aState.mPrevBottomMargin,
|
|
|
|
aState.IsAdjacentWithTop(),
|
1999-01-16 20:58:17 +00:00
|
|
|
computedOffsets, frameReflowStatus);
|
2000-05-09 05:06:16 +00:00
|
|
|
if (PR_TRUE==brc.BlockShouldInvalidateItself()) {
|
|
|
|
Invalidate(aState.mPresContext, mRect);
|
|
|
|
}
|
|
|
|
|
2000-01-26 22:18:33 +00:00
|
|
|
if (frame == aState.mNextRCFrame) {
|
|
|
|
// NULL out mNextRCFrame so if we reflow it again we don't think it's still
|
|
|
|
// an incremental reflow
|
|
|
|
aState.mNextRCFrame = nsnull;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
aState.mPrevChild = frame;
|
1998-11-17 22:28:51 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
#if defined(REFLOW_STATUS_COVERAGE)
|
1999-02-09 17:31:33 +00:00
|
|
|
RecordReflowStatus(PR_TRUE, frameReflowStatus);
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-11-17 22:28:51 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
|
|
|
|
// None of the child block fits.
|
|
|
|
PushLines(aState);
|
1999-02-12 17:45:58 +00:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
else {
|
1998-12-11 15:49:07 +00:00
|
|
|
// Note: line-break-after a block is a nop
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// Try to place the child block
|
|
|
|
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
1999-03-27 01:22:14 +00:00
|
|
|
nscoord collapsedBottomMargin;
|
2000-02-22 22:06:19 +00:00
|
|
|
nsRect combinedArea(0,0,0,0);
|
1999-03-27 01:22:14 +00:00
|
|
|
*aKeepReflowGoing = brc.PlaceBlock(isAdjacentWithTop, computedOffsets,
|
|
|
|
&collapsedBottomMargin,
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->mBounds, combinedArea);
|
2000-03-14 04:03:33 +00:00
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// Mark the line as block so once we known the final shrink wrap width
|
|
|
|
// we can reflow the block to the correct size
|
|
|
|
// XXX We don't always need to do this...
|
|
|
|
aLine->MarkDirty();
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-03-14 04:03:33 +00:00
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// Add the right margin to the line's bounnds. That way it will be taken into
|
|
|
|
// account when we compute our shrink wrap size
|
|
|
|
nscoord marginRight = brc.GetMargin().right;
|
|
|
|
if (marginRight != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
aLine->mBounds.width += marginRight;
|
|
|
|
}
|
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetCombinedArea(combinedArea);
|
1999-02-12 17:45:58 +00:00
|
|
|
if (*aKeepReflowGoing) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// Some of the child block fit
|
|
|
|
|
|
|
|
// Advance to new Y position
|
|
|
|
nscoord newY = aLine->mBounds.YMost();
|
|
|
|
aState.mY = newY;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetCarriedOutBottomMargin(brc.GetCarriedOutBottomMargin());
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// Continue the block frame now if it didn't completely fit in
|
|
|
|
// the available space.
|
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
PRBool madeContinuation;
|
|
|
|
rv = CreateContinuationFor(aState, aLine, frame, madeContinuation);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1998-11-20 17:18:58 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Push continuation to a new line, but only if we actually
|
|
|
|
// made one.
|
|
|
|
if (madeContinuation) {
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1999-10-19 23:04:19 +00:00
|
|
|
nsLineBox* line = aState.NewLineBox(frame, 1, PR_TRUE);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull == line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1998-10-16 20:22:39 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
line->mNext = aLine->mNext;
|
|
|
|
aLine->mNext = line;
|
1998-11-17 22:28:51 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Do not count the continuation child on the line it used
|
|
|
|
// to be on
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetChildCount(aLine->GetChildCount() - 1);
|
1999-04-20 03:42:32 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// Advance to next line since some of the block fit. That way
|
|
|
|
// only the following lines will be pushed.
|
|
|
|
aState.mPrevLine = aLine;
|
|
|
|
PushLines(aState);
|
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
1999-02-12 17:45:58 +00:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// The bottom margin for a block is only applied on the last
|
|
|
|
// flow block. Since we just continued the child block frame,
|
|
|
|
// we know that line->mFirstChild is not the last flow block
|
|
|
|
// therefore zero out the running margin value.
|
1999-09-10 18:52:56 +00:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow incomplete, frame=");
|
1999-09-10 18:52:56 +00:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" prevBottomMargin=%d, setting to zero\n",
|
1999-09-10 18:52:56 +00:00
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mPrevBottomMargin = 0;
|
|
|
|
}
|
|
|
|
else {
|
1999-09-10 18:52:56 +00:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflow complete for ");
|
1999-09-10 18:52:56 +00:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" prevBottomMargin=%d collapsedBottomMargin=%d\n",
|
1999-09-10 18:52:56 +00:00
|
|
|
aState.mPrevBottomMargin, collapsedBottomMargin);
|
|
|
|
#endif
|
2000-06-29 22:03:42 +00:00
|
|
|
aState.mPrevBottomMargin = collapsedBottomMargin;
|
1998-11-06 02:09:21 +00:00
|
|
|
}
|
1999-03-27 01:22:14 +00:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": frame=");
|
1999-03-27 01:22:14 +00:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->GetCarriedOutBottomMargin(), collapsedBottomMargin,
|
1999-03-27 01:22:14 +00:00
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
1998-11-06 02:09:21 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Post-process the "line"
|
1999-04-10 17:31:45 +00:00
|
|
|
nsSize maxElementSize(0, 0);
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
1999-04-10 17:31:45 +00:00
|
|
|
maxElementSize = brc.GetMaxElementSize();
|
1999-10-14 23:10:03 +00:00
|
|
|
if (aState.IsImpactedByFloater() &&
|
1999-04-10 17:31:45 +00:00
|
|
|
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
|
|
|
// Add in floater impacts to the lines max-element-size, but
|
|
|
|
// only if the block element isn't one of us (otherwise the
|
|
|
|
// floater impacts will be counted twice).
|
|
|
|
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
|
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
1999-12-30 04:15:45 +00:00
|
|
|
// If we asked the block to update its maximum width, then record the
|
|
|
|
// updated value in the line, and update the current maximum width
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
1999-12-30 04:15:45 +00:00
|
|
|
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
2000-06-11 22:14:33 +00:00
|
|
|
// need to add in margin on block's reported max width (see bug 35964)
|
|
|
|
const nsMargin& margin = brc.GetMargin();
|
|
|
|
aLine->mMaximumWidth += margin.left + margin.right;
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::ReflowBlockFrame parent block %p line %p aLine->mMaximumWidth set to brc.GetMaximumWidth %d, updating aState.mMaximumWidth\n",
|
|
|
|
this, aLine, aLine->mMaximumWidth);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1999-12-30 04:15:45 +00:00
|
|
|
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
|
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
PostPlaceLine(aState, aLine, maxElementSize);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
1999-02-18 22:22:55 +00:00
|
|
|
// Place the "marker" (bullet) frame.
|
|
|
|
//
|
|
|
|
// According to the CSS2 spec, section 12.6.1, the "marker" box
|
|
|
|
// participates in the height calculation of the list-item box's
|
|
|
|
// first line box.
|
|
|
|
//
|
|
|
|
// There are exactly two places a bullet can be placed: near the
|
|
|
|
// first or second line. Its only placed on the second line in a
|
|
|
|
// rare case: an empty first line followed by a second line that
|
|
|
|
// contains a block (example: <LI>\n<P>... ). This is where
|
|
|
|
// the second case can happen.
|
|
|
|
if (HaveOutsideBullet() &&
|
|
|
|
((aLine == mLines) ||
|
|
|
|
((0 == mLines->mBounds.height) && (aLine == mLines->mNext)))) {
|
|
|
|
// Reflow the bullet
|
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
|
|
|
ReflowBullet(aState, metrics);
|
|
|
|
|
|
|
|
// For bullets that are placed next to a child block, there will
|
|
|
|
// be no correct ascent value. Therefore, make one up...
|
|
|
|
nscoord ascent = 0;
|
|
|
|
const nsStyleFont* font;
|
1999-05-13 00:55:38 +00:00
|
|
|
frame->GetStyleData(eStyleStruct_Font,
|
|
|
|
(const nsStyleStruct*&) font);
|
|
|
|
nsIRenderingContext& rc = *aState.mReflowState.rendContext;
|
|
|
|
rc.SetFont(font->mFont);
|
|
|
|
nsIFontMetrics* fm;
|
|
|
|
rv = rc.GetFontMetrics(fm);
|
|
|
|
if (NS_SUCCEEDED(rv) && (nsnull != fm)) {
|
|
|
|
fm->GetMaxAscent(ascent);
|
|
|
|
NS_RELEASE(fm);
|
1999-02-18 22:22:55 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
rv = NS_OK;
|
1999-02-18 22:22:55 +00:00
|
|
|
|
|
|
|
// Tall bullets won't look particularly nice here...
|
|
|
|
nsRect bbox;
|
|
|
|
mBullet->GetRect(bbox);
|
1999-10-15 23:35:10 +00:00
|
|
|
nscoord bulletTopMargin = applyTopMargin ? collapsedBottomMargin : 0;
|
1999-04-03 18:59:01 +00:00
|
|
|
bbox.y = aState.BorderPadding().top + ascent -
|
1999-10-15 23:35:10 +00:00
|
|
|
metrics.ascent + bulletTopMargin;
|
1999-10-26 04:44:41 +00:00
|
|
|
mBullet->SetRect(aState.mPresContext, bbox);
|
1999-02-18 22:22:55 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// None of the block fits. Determine the correct reflow status.
|
|
|
|
if (aLine == mLines) {
|
|
|
|
// If it's our very first line then we need to be pushed to
|
|
|
|
// our parents next-in-flow. Therefore, return break-before
|
|
|
|
// status for our reflow status.
|
|
|
|
aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Push the line that didn't fit and any lines that follow it
|
|
|
|
// to our next-in-flow.
|
|
|
|
PushLines(aState);
|
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
}
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
|
|
|
}
|
1998-10-30 22:10:10 +00:00
|
|
|
|
1999-03-21 01:15:12 +00:00
|
|
|
#define LINE_REFLOW_OK 0
|
|
|
|
#define LINE_REFLOW_STOP 1
|
|
|
|
#define LINE_REFLOW_REDO 2
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRBool* aKeepReflowGoing,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aDamageDirtyArea,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRBool aUpdateMaximumWidth)
|
1999-03-21 01:15:12 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
*aKeepReflowGoing = PR_TRUE;
|
|
|
|
|
1999-03-24 15:42:19 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
PRInt32 spins = 0;
|
|
|
|
#endif
|
1999-08-27 21:45:37 +00:00
|
|
|
PRUint8 lineReflowStatus = LINE_REFLOW_REDO;
|
|
|
|
while (LINE_REFLOW_REDO == lineReflowStatus) {
|
|
|
|
// Prevent overflowing limited thread stacks by creating
|
|
|
|
// nsLineLayout from the heap when the frame tree depth gets
|
|
|
|
// large.
|
|
|
|
if (aState.mReflowState.mReflowDepth > 30) {//XXX layout-tune.h?
|
|
|
|
rv = DoReflowInlineFramesMalloc(aState, aLine, aKeepReflowGoing,
|
2000-01-08 03:58:27 +00:00
|
|
|
&lineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-03-24 15:42:19 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
else {
|
|
|
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
2000-01-08 03:58:27 +00:00
|
|
|
&lineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-27 21:45:37 +00:00
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
spins++;
|
|
|
|
if (1000 == spins) {
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
1999-08-27 21:45:37 +00:00
|
|
|
NS_ABORT();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
1999-03-24 15:42:19 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine,
|
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-27 21:45:37 +00:00
|
|
|
{
|
1999-11-24 06:03:41 +00:00
|
|
|
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.mReflowState.mSpaceManager,
|
|
|
|
&aState.mReflowState,
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
1999-08-27 21:45:37 +00:00
|
|
|
if (!ll) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
ll->Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
|
|
|
nsresult rv = DoReflowInlineFrames(aState, *ll, aLine, aKeepReflowGoing,
|
2000-04-19 03:12:13 +00:00
|
|
|
aLineReflowStatus, aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-27 21:45:37 +00:00
|
|
|
ll->EndLineReflow();
|
|
|
|
delete ll;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine,
|
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-27 21:45:37 +00:00
|
|
|
{
|
1999-11-24 06:03:41 +00:00
|
|
|
nsLineLayout lineLayout(aState.mPresContext,
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.mReflowState.mSpaceManager,
|
|
|
|
&aState.mReflowState,
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
1999-08-27 21:45:37 +00:00
|
|
|
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
|
|
|
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
2000-01-08 03:58:27 +00:00
|
|
|
aKeepReflowGoing, aLineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-27 21:45:37 +00:00
|
|
|
lineLayout.EndLineReflow();
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-08 03:58:27 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|
|
|
nsLineLayout& aLineLayout,
|
|
|
|
nsLineBox* aLine,
|
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 03:12:13 +00:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-27 21:45:37 +00:00
|
|
|
{
|
1999-09-15 00:28:10 +00:00
|
|
|
// Forget all of the floaters on the line
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
1999-10-14 23:10:03 +00:00
|
|
|
aState.mRightFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
1999-03-27 01:22:14 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
// Setup initial coordinate system for reflowing the inline frames
|
|
|
|
// into. Apply a previous block frame's bottom margin first.
|
|
|
|
aState.mY += aState.mPrevBottomMargin;
|
|
|
|
aState.GetAvailableSpace();
|
2000-03-22 23:19:10 +00:00
|
|
|
PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetLineIsImpactedByFloater(impactedByFloaters);
|
2000-03-22 23:19:10 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
|
2000-03-22 23:19:10 +00:00
|
|
|
this, impactedByFloaters);
|
|
|
|
#endif
|
1999-08-27 21:45:37 +00:00
|
|
|
|
|
|
|
const nsMargin& borderPadding = aState.BorderPadding();
|
|
|
|
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
|
|
|
nscoord availWidth = aState.mAvailSpaceRect.width;
|
|
|
|
nscoord availHeight;
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
1999-08-27 21:45:37 +00:00
|
|
|
availHeight = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* XXX get the height right! */
|
|
|
|
availHeight = aState.mAvailSpaceRect.height;
|
|
|
|
}
|
2000-01-08 03:58:27 +00:00
|
|
|
if (aUpdateMaximumWidth) {
|
|
|
|
availWidth = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
aLineLayout.BeginLineReflow(x, aState.mY,
|
|
|
|
availWidth, availHeight,
|
|
|
|
impactedByFloaters,
|
|
|
|
PR_FALSE /*XXX isTopOfPage*/);
|
1999-08-31 03:09:40 +00:00
|
|
|
|
|
|
|
// XXX Unfortunately we need to know this before reflowing the first
|
|
|
|
// inline frame in the line. FIX ME.
|
1999-08-27 21:45:37 +00:00
|
|
|
if ((0 == aLineLayout.GetLineNumber()) &&
|
|
|
|
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
|
|
|
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reflow the frames that are already on the line first
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
PRUint8 lineReflowStatus = LINE_REFLOW_OK;
|
|
|
|
PRInt32 i;
|
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
2000-02-14 01:52:22 +00:00
|
|
|
aLine->SetHasPercentageChild(PR_FALSE); // To be set by ReflowInlineFrame below
|
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-11 21:15:02 +00:00
|
|
|
// need to repeatedly call GetChildCount here, because the child
|
|
|
|
// count can change during the loop!
|
|
|
|
for (i = 0; i < aLine->GetChildCount(); i++) {
|
1999-08-27 21:45:37 +00:00
|
|
|
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
|
|
|
&lineReflowStatus);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
if (LINE_REFLOW_OK != lineReflowStatus) {
|
|
|
|
// It is possible that one or more of next lines are empty
|
|
|
|
// (because of DeleteChildsNextInFlow). If so, delete them now
|
|
|
|
// in case we are finished.
|
|
|
|
nsLineBox* nextLine = aLine->mNext;
|
1999-10-14 23:10:03 +00:00
|
|
|
while ((nsnull != nextLine) && (0 == nextLine->GetChildCount())) {
|
1999-08-27 21:45:37 +00:00
|
|
|
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
|
|
|
// uses DoRemoveFrame?
|
|
|
|
aLine->mNext = nextLine->mNext;
|
|
|
|
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
|
1999-10-19 23:04:19 +00:00
|
|
|
aState.FreeLineBox(nextLine);
|
1999-08-27 21:45:37 +00:00
|
|
|
nextLine = aLine->mNext;
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
break;
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
1999-03-21 01:15:12 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
// Pull frames and reflow them until we can't
|
|
|
|
while (LINE_REFLOW_OK == lineReflowStatus) {
|
2000-04-19 03:12:13 +00:00
|
|
|
rv = PullFrame(aState, aLine, aDamageDirtyArea, frame);
|
1999-08-27 21:45:37 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (nsnull == frame) {
|
|
|
|
break;
|
|
|
|
}
|
1999-03-21 01:15:12 +00:00
|
|
|
while (LINE_REFLOW_OK == lineReflowStatus) {
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 oldCount = aLine->GetChildCount();
|
1999-08-27 21:45:37 +00:00
|
|
|
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
|
|
|
&lineReflowStatus);
|
1999-03-21 01:15:12 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
if (aLine->GetChildCount() != oldCount) {
|
1999-08-27 21:45:37 +00:00
|
|
|
// We just created a continuation for aFrame AND its going
|
|
|
|
// to end up on this line (e.g. :first-letter
|
|
|
|
// situation). Therefore we have to loop here before trying
|
|
|
|
// to pull another frame.
|
|
|
|
frame->GetNextSibling(&frame);
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
else {
|
|
|
|
break;
|
1999-03-24 15:42:19 +00:00
|
|
|
}
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
}
|
|
|
|
if (LINE_REFLOW_REDO == lineReflowStatus) {
|
|
|
|
// This happens only when we have a line that is impacted by
|
|
|
|
// floaters and the first element in the line doesn't fit with
|
|
|
|
// the floaters.
|
|
|
|
//
|
|
|
|
// What we do is to advance past the first floater we find and
|
|
|
|
// then reflow the line all over again.
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ASSERTION(aState.IsImpactedByFloater(),
|
1999-08-27 21:45:37 +00:00
|
|
|
"redo line on totally empty line");
|
|
|
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
|
|
|
"unconstrained height on totally empty line");
|
1999-10-29 14:34:53 +00:00
|
|
|
|
1999-08-27 21:45:37 +00:00
|
|
|
aState.mY += aState.mAvailSpaceRect.height;
|
|
|
|
// XXX: a small optimization can be done here when paginating:
|
|
|
|
// if the new Y coordinate is past the end of the block then
|
|
|
|
// push the line and return now instead of later on after we are
|
|
|
|
// past the floater.
|
|
|
|
}
|
|
|
|
else {
|
1999-03-21 01:15:12 +00:00
|
|
|
// If we are propogating out a break-before status then there is
|
|
|
|
// no point in placing the line.
|
1999-08-27 21:45:37 +00:00
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
2000-01-08 03:58:27 +00:00
|
|
|
rv = PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth);
|
1999-03-21 01:15:12 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-27 21:45:37 +00:00
|
|
|
*aLineReflowStatus = lineReflowStatus;
|
1999-03-21 01:15:12 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Reflow an inline frame. The reflow status is mapped from the frames
|
|
|
|
* reflow status to the lines reflow status (not to our reflow status).
|
|
|
|
* The line reflow status is simple: PR_TRUE means keep placing frames
|
|
|
|
* on the line; PR_FALSE means don't (the line is done). If the line
|
1999-10-14 23:10:03 +00:00
|
|
|
* has some sort of breaking affect then aLine's break-type will be set
|
1998-12-05 16:02:08 +00:00
|
|
|
* to something other than NS_STYLE_CLEAR_NONE.
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
1999-08-27 21:45:37 +00:00
|
|
|
nsLineLayout& aLineLayout,
|
1999-02-12 17:45:58 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsIFrame* aFrame,
|
1999-03-21 01:15:12 +00:00
|
|
|
PRUint8* aLineReflowStatus)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-03-21 01:15:12 +00:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_OK;
|
1998-10-30 22:10:10 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// If it's currently ok to be reflowing in first-letter style then
|
|
|
|
// we must be about to reflow a frame that has first-letter style.
|
1999-08-27 21:45:37 +00:00
|
|
|
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
1999-04-27 22:10:51 +00:00
|
|
|
#ifdef NOISY_FIRST_LETTER
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": reflowing ");
|
1999-04-27 22:10:51 +00:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" reflowingFirstLetter=%s\n", reflowingFirstLetter ? "on" : "off");
|
1999-04-27 22:10:51 +00:00
|
|
|
#endif
|
1998-06-18 16:25:41 +00:00
|
|
|
|
2000-02-14 01:52:22 +00:00
|
|
|
// Remember if we have a percentage aware child on this line
|
|
|
|
if (IsPercentageAwareChild(aFrame)) {
|
|
|
|
aLine->SetHasPercentageChild(PR_TRUE);
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Reflow the inline frame
|
|
|
|
nsReflowStatus frameReflowStatus;
|
2000-01-03 04:32:13 +00:00
|
|
|
PRBool pushedFrame;
|
1999-08-27 21:45:37 +00:00
|
|
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, &aState.mNextRCFrame,
|
2000-01-03 04:32:13 +00:00
|
|
|
frameReflowStatus, nsnull, pushedFrame);
|
2000-01-26 22:18:33 +00:00
|
|
|
if (aFrame == aState.mNextRCFrame) {
|
|
|
|
// NULL out mNextRCFrame so if we reflow it again we don't think it's still
|
|
|
|
// an incremental reflow
|
|
|
|
aState.mNextRCFrame = nsnull;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-09-10 19:32:14 +00:00
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef REALLY_NOISY_REFLOW_CHILD
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": status=%x\n", frameReflowStatus);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-09-10 19:32:14 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
#if defined(REFLOW_STATUS_COVERAGE)
|
1999-02-09 17:31:33 +00:00
|
|
|
RecordReflowStatus(PR_FALSE, frameReflowStatus);
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-09-10 19:32:14 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Send post-reflow notification
|
|
|
|
aState.mPrevChild = aFrame;
|
1998-09-10 19:32:14 +00:00
|
|
|
|
2000-06-14 23:15:59 +00:00
|
|
|
/* XXX
|
|
|
|
This is where we need to add logic to handle some odd behavior.
|
|
|
|
For one thing, we should usually place at least one thing next
|
|
|
|
to a left floater, even when that floater takes up all the width on a line.
|
|
|
|
see bug 22496
|
|
|
|
*/
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Process the child frames reflow status. There are 5 cases:
|
|
|
|
// complete, not-complete, break-before, break-after-complete,
|
|
|
|
// break-after-not-complete. There are two situations: we are a
|
|
|
|
// block or we are an inline. This makes a total of 10 cases
|
|
|
|
// (fortunately, there is some overlap).
|
1999-10-12 23:24:22 +00:00
|
|
|
aLine->SetBreakType(NS_STYLE_CLEAR_NONE);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_INLINE_IS_BREAK(frameReflowStatus)) {
|
|
|
|
// Always abort the line reflow (because a line break is the
|
|
|
|
// minimal amount of break we do).
|
1999-03-21 01:15:12 +00:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
1998-12-05 16:02:08 +00:00
|
|
|
|
1999-10-14 23:10:03 +00:00
|
|
|
// XXX what should aLine's break-type be set to in all these cases?
|
1998-12-05 16:02:08 +00:00
|
|
|
PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
|
|
|
|
NS_ASSERTION(breakType != NS_STYLE_CLEAR_NONE, "bad break type");
|
|
|
|
NS_ASSERTION(NS_STYLE_CLEAR_PAGE != breakType, "no page breaks yet");
|
|
|
|
|
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
|
|
|
|
// Break-before cases.
|
|
|
|
if (aFrame == aLine->mFirstChild) {
|
1999-03-21 01:15:12 +00:00
|
|
|
// If we break before the first frame on the line then we must
|
|
|
|
// be trying to place content where theres no room (e.g. on a
|
|
|
|
// line with wide floaters). Inform the caller to reflow the
|
|
|
|
// line after skipping past a floater.
|
|
|
|
*aLineReflowStatus = LINE_REFLOW_REDO;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// It's not the first child on this line so go ahead and split
|
|
|
|
// the line. We will see the frame again on the next-line.
|
1999-08-27 21:45:37 +00:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
|
|
|
|
// If we're splitting the line because the frame didn't fit and it
|
|
|
|
// was pushed, then mark the line as having word wrapped. We need to
|
|
|
|
// know that if we're shrink wrapping our width
|
|
|
|
if (pushedFrame) {
|
|
|
|
aLine->SetLineWrapped(PR_TRUE);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-10 19:32:14 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
// Break-after cases
|
1999-10-29 14:34:53 +00:00
|
|
|
if (breakType == NS_STYLE_CLEAR_LINE) {
|
|
|
|
if (!aLineLayout.GetLineEndsInBR()) {
|
|
|
|
breakType = NS_STYLE_CLEAR_NONE;
|
|
|
|
}
|
|
|
|
}
|
1999-10-12 23:24:22 +00:00
|
|
|
aLine->SetBreakType(breakType);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
// Create a continuation for the incomplete frame. Note that the
|
|
|
|
// frame may already have a continuation.
|
|
|
|
PRBool madeContinuation;
|
|
|
|
rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-03 04:32:13 +00:00
|
|
|
// Remember that the line has wrapped
|
|
|
|
aLine->SetLineWrapped(PR_TRUE);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-10 19:32:14 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Split line, but after the frame just reflowed
|
1999-03-16 19:36:00 +00:00
|
|
|
nsIFrame* nextFrame;
|
|
|
|
aFrame->GetNextSibling(&nextFrame);
|
1999-08-27 21:45:37 +00:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-09-11 04:13:29 +00:00
|
|
|
}
|
2000-10-12 20:30:43 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
// Mark next line dirty in case SplitLine didn't end up
|
|
|
|
// pushing any frames.
|
|
|
|
nsLineBox* next = aLine->mNext;
|
|
|
|
if ((nsnull != next) && !next->IsBlock()) {
|
|
|
|
next->MarkDirty();
|
1999-01-05 23:01:54 +00:00
|
|
|
}
|
2000-10-12 20:30:43 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
// Frame is not-complete, no special breaking status
|
1998-09-10 19:32:14 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Create a continuation for the incomplete frame. Note that the
|
|
|
|
// frame may already have a continuation.
|
|
|
|
PRBool madeContinuation;
|
|
|
|
rv = CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2000-01-03 04:32:13 +00:00
|
|
|
// Remember that the line has wrapped
|
|
|
|
aLine->SetLineWrapped(PR_TRUE);
|
|
|
|
|
1999-04-27 22:10:51 +00:00
|
|
|
// If we are reflowing the first letter frame then don't split the
|
|
|
|
// line and don't stop the line reflow...
|
|
|
|
PRBool splitLine = !reflowingFirstLetter;
|
|
|
|
if (reflowingFirstLetter) {
|
1999-11-01 15:24:57 +00:00
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
aFrame->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
if ((nsLayoutAtoms::inlineFrame == frameType.get()) ||
|
|
|
|
(nsLayoutAtoms::lineFrame == frameType.get())) {
|
1999-04-27 22:10:51 +00:00
|
|
|
splitLine = PR_TRUE;
|
|
|
|
}
|
1999-03-26 00:39:04 +00:00
|
|
|
}
|
1998-09-11 04:13:29 +00:00
|
|
|
|
1999-04-27 22:10:51 +00:00
|
|
|
if (splitLine) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// Split line after the current frame
|
1999-03-21 01:15:12 +00:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
1999-02-10 06:13:38 +00:00
|
|
|
aFrame->GetNextSibling(&aFrame);
|
1999-08-27 21:45:37 +00:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1999-04-27 22:10:51 +00:00
|
|
|
|
1999-02-09 17:31:33 +00:00
|
|
|
// Mark next line dirty in case SplitLine didn't end up
|
|
|
|
// pushing any frames.
|
|
|
|
nsLineBox* next = aLine->mNext;
|
|
|
|
if ((nsnull != next) && !next->IsBlock()) {
|
|
|
|
next->MarkDirty();
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
1998-09-10 19:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Create a continuation, if necessary, for aFrame. Place it on the
|
|
|
|
* same line that aFrame is on. Set aMadeNewFrame to PR_TRUE if a
|
|
|
|
* new frame is created.
|
|
|
|
*/
|
1998-06-30 20:14:04 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
1999-03-16 19:36:00 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
PRBool& aMadeNewFrame)
|
1998-06-30 20:14:04 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
aMadeNewFrame = PR_FALSE;
|
|
|
|
nsresult rv;
|
|
|
|
nsIFrame* nextInFlow;
|
1999-11-24 06:03:41 +00:00
|
|
|
rv = CreateNextInFlow(aState.mPresContext, this, aFrame, nextInFlow);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
1998-06-30 20:14:04 +00:00
|
|
|
return rv;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull != nextInFlow) {
|
|
|
|
aMadeNewFrame = PR_TRUE;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_FALSE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
1998-06-30 20:14:04 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
1999-08-27 21:45:37 +00:00
|
|
|
nsLineLayout& aLineLayout,
|
1999-04-20 00:27:43 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsIFrame* aFrame)
|
1998-10-02 21:50:53 +00:00
|
|
|
{
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ABORT_IF_FALSE(aLine->IsInline(), "illegal SplitLine on block line");
|
|
|
|
|
|
|
|
PRInt32 pushCount = aLine->GetChildCount() - aLineLayout.GetCurrentSpanCount();
|
|
|
|
NS_ABORT_IF_FALSE(pushCount >= 0, "bad push count");
|
|
|
|
|
1999-10-29 14:34:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("split line: from line=%p pushCount=%d aFrame=", aLine, pushCount);
|
1999-11-02 15:44:57 +00:00
|
|
|
if (aFrame) {
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
|
|
|
}
|
|
|
|
else {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("(null)");
|
1999-11-02 15:44:57 +00:00
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-10-29 14:34:53 +00:00
|
|
|
if (gReallyNoisyReflow) {
|
|
|
|
aLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
if (0 != pushCount) {
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ABORT_IF_FALSE(aLine->GetChildCount() > pushCount, "bad push");
|
|
|
|
NS_ABORT_IF_FALSE(nsnull != aFrame, "whoops");
|
|
|
|
|
|
|
|
// Put frames being split out into their own line
|
1999-10-19 23:04:19 +00:00
|
|
|
nsLineBox* newLine = aState.NewLineBox(aFrame, pushCount, PR_FALSE);
|
1999-10-14 23:10:03 +00:00
|
|
|
if (!newLine) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1998-10-02 21:50:53 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
newLine->mNext = aLine->mNext;
|
|
|
|
aLine->mNext = newLine;
|
|
|
|
aLine->SetChildCount(aLine->GetChildCount() - pushCount);
|
1999-10-29 14:34:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gReallyNoisyReflow) {
|
|
|
|
newLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
|
|
|
|
}
|
|
|
|
#endif
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1999-03-18 21:03:25 +00:00
|
|
|
// Let line layout know that some frames are no longer part of its
|
|
|
|
// state.
|
1999-10-14 23:10:03 +00:00
|
|
|
aLineLayout.SplitLineTo(aLine->GetChildCount());
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
1998-10-02 21:50:53 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState, nsLineBox* aLine)
|
1998-06-24 17:52:42 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* next = aLine->mNext;
|
|
|
|
while (nsnull != next) {
|
|
|
|
// There is another line
|
1999-10-14 23:10:03 +00:00
|
|
|
if (0 != next->GetChildCount()) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// If the next line is a block line then we must not justify
|
|
|
|
// this line because it means that this line is the last in a
|
|
|
|
// group of inline lines.
|
|
|
|
return !next->IsBlock();
|
|
|
|
}
|
1998-06-30 20:14:04 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// The next line is empty, try the next one
|
|
|
|
next = next->mNext;
|
1998-06-30 20:14:04 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX Not sure about this part
|
|
|
|
// Try our next-in-flows lines to answer the question
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != nextInFlow) {
|
|
|
|
nsLineBox* line = nextInFlow->mLines;
|
|
|
|
while (nsnull != line) {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (0 != line->GetChildCount()) {
|
1998-12-11 15:49:07 +00:00
|
|
|
return !line->IsBlock();
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
line = line->mNext;
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
1999-02-09 17:31:33 +00:00
|
|
|
nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-11-11 03:55:55 +00:00
|
|
|
|
1998-12-11 15:49:07 +00:00
|
|
|
// This is the last line - so don't allow justification
|
|
|
|
return PR_FALSE;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
1999-08-27 21:45:37 +00:00
|
|
|
nsLineLayout& aLineLayout,
|
1999-03-20 21:57:03 +00:00
|
|
|
nsLineBox* aLine,
|
2000-01-08 03:58:27 +00:00
|
|
|
PRBool* aKeepReflowGoing,
|
|
|
|
PRBool aUpdateMaximumWidth)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1999-09-21 00:13:50 +00:00
|
|
|
// Trim extra white-space from the line before placing the frames
|
1999-10-12 23:24:22 +00:00
|
|
|
PRBool trimmed = aLineLayout.TrimTrailingWhiteSpace();
|
|
|
|
aLine->SetTrimmed(trimmed);
|
1999-09-21 00:13:50 +00:00
|
|
|
|
1999-02-18 22:22:55 +00:00
|
|
|
// Vertically align the frames on this line.
|
|
|
|
//
|
|
|
|
// According to the CSS2 spec, section 12.6.1, the "marker" box
|
|
|
|
// participates in the height calculation of the list-item box's
|
|
|
|
// first line box.
|
|
|
|
//
|
|
|
|
// There are exactly two places a bullet can be placed: near the
|
|
|
|
// first or second line. Its only placed on the second line in a
|
|
|
|
// rare case: an empty first line followed by a second line that
|
|
|
|
// contains a block (example: <LI>\n<P>... ).
|
|
|
|
//
|
|
|
|
// For this code, only the first case is possible because this
|
|
|
|
// method is used for placing a line of inline frames. If the rare
|
|
|
|
// case is happening then the worst that will happen is that the
|
|
|
|
// bullet frame will be reflowed twice.
|
|
|
|
PRBool addedBullet = PR_FALSE;
|
1999-03-18 21:03:25 +00:00
|
|
|
if (HaveOutsideBullet() && (aLine == mLines) &&
|
1999-08-27 21:45:37 +00:00
|
|
|
(!aLineLayout.IsZeroHeight() || !aLine->mNext)) {
|
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
|
|
|
ReflowBullet(aState, metrics);
|
|
|
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
1999-02-18 22:22:55 +00:00
|
|
|
addedBullet = PR_TRUE;
|
|
|
|
}
|
1999-03-18 21:03:25 +00:00
|
|
|
nsSize maxElementSize;
|
2000-06-05 08:24:18 +00:00
|
|
|
nscoord lineAscent;
|
|
|
|
aLineLayout.VerticalAlignFrames(aLine, maxElementSize, lineAscent);
|
|
|
|
// Our ascent is the ascent of our first line
|
|
|
|
if (aLine == mLines) {
|
|
|
|
mAscent = lineAscent;
|
|
|
|
}
|
2000-07-28 09:18:15 +00:00
|
|
|
|
2000-01-03 04:32:13 +00:00
|
|
|
// See if we're shrink wrapping the width
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// When determining the line's width we also need to include any
|
|
|
|
// right floaters that impact us. This represents the shrink wrap
|
|
|
|
// width of the line
|
|
|
|
if (aState.IsImpactedByFloater() && !aLine->IsLineWrapped()) {
|
|
|
|
NS_ASSERTION(aState.mContentArea.width >= aState.mAvailSpaceRect.XMost(), "bad state");
|
|
|
|
aLine->mBounds.width += aState.mContentArea.width - aState.mAvailSpaceRect.XMost();
|
|
|
|
}
|
|
|
|
}
|
1999-03-20 21:57:03 +00:00
|
|
|
#ifdef DEBUG
|
1999-06-01 22:11:32 +00:00
|
|
|
{
|
|
|
|
static nscoord lastHeight = 0;
|
|
|
|
if (CRAZY_HEIGHT(aLine->mBounds.y)) {
|
|
|
|
lastHeight = aLine->mBounds.y;
|
|
|
|
if (abs(aLine->mBounds.y - lastHeight) > CRAZY_H/10) {
|
|
|
|
nsFrame::ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": line=%p y=%d line.bounds.height=%d\n",
|
|
|
|
aLine, aLine->mBounds.y, aLine->mBounds.height);
|
1999-06-01 22:11:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lastHeight = 0;
|
|
|
|
}
|
1999-03-20 21:57:03 +00:00
|
|
|
}
|
1999-03-05 04:21:32 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// Only block frames horizontally align their children because
|
|
|
|
// inline frames "shrink-wrap" around their children (therefore
|
|
|
|
// there is no extra horizontal space).
|
2000-04-17 14:40:46 +00:00
|
|
|
const nsStyleText* styleText = (const nsStyleText*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
|
|
|
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
|
|
|
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
|
|
|
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
2000-01-03 04:32:13 +00:00
|
|
|
if (!successful) {
|
|
|
|
// Mark the line dirty and then later once we've determined the width
|
|
|
|
// we can do the horizontal alignment
|
|
|
|
aLine->MarkDirty();
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
2000-04-17 14:40:46 +00:00
|
|
|
|
|
|
|
nsRect combinedArea;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLineLayout.RelativePositionFrames(combinedArea);
|
|
|
|
aLine->SetCombinedArea(combinedArea);
|
1999-03-20 01:37:43 +00:00
|
|
|
if (addedBullet) {
|
1999-08-27 21:45:37 +00:00
|
|
|
aLineLayout.RemoveBulletFrame(mBullet);
|
1999-03-20 01:37:43 +00:00
|
|
|
}
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1999-03-27 01:22:14 +00:00
|
|
|
// Inline lines do not have margins themselves; however they are
|
|
|
|
// impacted by prior block margins. If this line ends up having some
|
|
|
|
// height then we zero out the previous bottom margin value that was
|
|
|
|
// already applied to the line's starting Y coordinate. Otherwise we
|
|
|
|
// leave it be so that the previous blocks bottom margin can be
|
|
|
|
// collapsed with a block that follows.
|
|
|
|
nscoord newY;
|
|
|
|
if (aLine->mBounds.height > 0) {
|
|
|
|
// This line has some height. Therefore the application of the
|
|
|
|
// previous-bottom-margin should stick.
|
|
|
|
aState.mPrevBottomMargin = 0;
|
1999-04-03 18:59:01 +00:00
|
|
|
newY = aLine->mBounds.YMost();
|
1999-03-27 01:22:14 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Don't let the previous-bottom-margin value affect the newY
|
|
|
|
// coordinate (it was applied in ReflowInlineFrames speculatively)
|
|
|
|
// since the line is empty.
|
1999-04-03 18:59:01 +00:00
|
|
|
nscoord dy = -aState.mPrevBottomMargin;
|
1999-04-01 01:37:36 +00:00
|
|
|
newY = aState.mY + dy;
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->SlideBy(dy);
|
2000-06-05 08:24:18 +00:00
|
|
|
// keep our ascent in sync
|
|
|
|
if (mLines == aLine) {
|
|
|
|
mAscent += dy;
|
|
|
|
}
|
1999-03-27 01:22:14 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// See if the line fit. If it doesn't we need to push it. Our first
|
|
|
|
// line will always fit.
|
|
|
|
if ((mLines != aLine) && (newY > aState.mBottomEdge)) {
|
|
|
|
// Push this line and all of it's children and anything else that
|
|
|
|
// follows to our next-in-flow
|
|
|
|
PushLines(aState);
|
|
|
|
|
|
|
|
// Stop reflow and whack the reflow status if reflow hasn't
|
|
|
|
// already been stopped.
|
1999-02-12 17:45:58 +00:00
|
|
|
if (*aKeepReflowGoing) {
|
2000-02-22 22:06:19 +00:00
|
|
|
NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus,
|
1998-12-05 16:02:08 +00:00
|
|
|
"lost reflow status");
|
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
1999-02-12 17:45:58 +00:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-10-06 00:38:56 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
|
|
|
}
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mY = newY;
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
1999-07-14 17:26:20 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
|
|
|
IndentBy(stdout, GetDepth());
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("PASS1 ");
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": line.floaters=%s band.floaterCount=%d\n",
|
2000-02-02 07:37:18 +00:00
|
|
|
//aLine->mFloaters.NotEmpty() ? "yes" : "no",
|
1999-10-14 23:10:03 +00:00
|
|
|
aState.mHaveRightFloaters ? "(have right floaters)" : "",
|
1999-07-14 17:26:20 +00:00
|
|
|
aState.mBand.GetFloaterCount());
|
|
|
|
#endif
|
1999-04-10 17:31:45 +00:00
|
|
|
if (0 != aState.mBand.GetFloaterCount()) {
|
|
|
|
// Add in floater impacts to the lines max-element-size
|
|
|
|
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
|
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
2000-01-08 03:58:27 +00:00
|
|
|
|
2000-01-28 03:12:30 +00:00
|
|
|
// If we're reflowing the line just to incrementally update the
|
2000-01-08 03:58:27 +00:00
|
|
|
// maximum width, then don't post-place the line. It's doing work we
|
|
|
|
// don't need, and it will update things like aState.mKidXMost that
|
|
|
|
// we don't want updated...
|
2000-01-28 03:12:30 +00:00
|
|
|
if (aUpdateMaximumWidth) {
|
|
|
|
// However, we do need to update the max-element-size if requested
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2000-01-28 03:12:30 +00:00
|
|
|
aState.UpdateMaxElementSize(maxElementSize);
|
|
|
|
// We also cache the max element width in the line. This is needed for
|
|
|
|
// incremental reflow
|
|
|
|
aLine->mMaxElementWidth = maxElementSize.width;
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf ("nsBlockFrame::PlaceLine: %p setting MES for line %p to %d\n",
|
|
|
|
this, aLine, maxElementSize.width);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
2000-01-28 03:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2000-01-08 03:58:27 +00:00
|
|
|
PostPlaceLine(aState, aLine, maxElementSize);
|
|
|
|
}
|
1998-12-17 18:52:10 +00:00
|
|
|
|
1999-09-17 23:16:43 +00:00
|
|
|
// Add the already placed current-line floaters to the line
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->AppendFloaters(aState.mCurrentLineFloaters);
|
1999-09-15 00:28:10 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Any below current line floaters to place?
|
1999-09-15 00:28:10 +00:00
|
|
|
if (aState.mBelowCurrentLineFloaters.NotEmpty()) {
|
|
|
|
// Reflow the below-current-line floaters, then add them to the
|
|
|
|
// lines floater list.
|
|
|
|
aState.PlaceBelowCurrentLineFloaters(aState.mBelowCurrentLineFloaters);
|
1999-10-14 23:10:03 +00:00
|
|
|
aLine->AppendFloaters(aState.mBelowCurrentLineFloaters);
|
1998-06-30 23:51:26 +00:00
|
|
|
}
|
|
|
|
|
1999-03-23 04:28:20 +00:00
|
|
|
// When a line has floaters, factor them into the combined-area
|
|
|
|
// computations.
|
1999-10-14 23:10:03 +00:00
|
|
|
if (aLine->HasFloaters()) {
|
1999-03-23 04:28:20 +00:00
|
|
|
// Combine the floater combined area (stored in aState) and the
|
|
|
|
// value computed by the line layout code.
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
#ifdef NOISY_COMBINED_AREA
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": lineCA=%d,%d,%d,%d floaterCA=%d,%d,%d,%d\n",
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height,
|
|
|
|
aState.mFloaterCombinedArea.x, aState.mFloaterCombinedArea.y,
|
|
|
|
aState.mFloaterCombinedArea.width,
|
|
|
|
aState.mFloaterCombinedArea.height);
|
|
|
|
#endif
|
|
|
|
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
|
|
|
|
2000-01-03 04:32:13 +00:00
|
|
|
if (aState.mHaveRightFloaters &&
|
2000-04-17 14:40:46 +00:00
|
|
|
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// We are reflowing in an unconstrained situation or shrink wrapping and
|
|
|
|
// have some right floaters. They were placed at the infinite right edge
|
1999-10-14 23:10:03 +00:00
|
|
|
// which will cause the combined area to be unusable.
|
|
|
|
//
|
2000-01-03 04:32:13 +00:00
|
|
|
// To solve this issue, we pretend that the right floaters ended up just
|
|
|
|
// past the end of the line. Note that the right floater combined area
|
|
|
|
// we computed as we were going will have as its X coordinate the left
|
|
|
|
// most edge of all the right floaters. Therefore, to accomplish our goal
|
|
|
|
// all we do is set that X value to the lines XMost value.
|
1999-10-14 23:10:03 +00:00
|
|
|
#ifdef NOISY_COMBINED_AREA
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
|
1999-10-14 23:10:03 +00:00
|
|
|
aState.mRightFloaterCombinedArea.x,
|
|
|
|
aState.mRightFloaterCombinedArea.y,
|
|
|
|
aState.mRightFloaterCombinedArea.width,
|
|
|
|
aState.mRightFloaterCombinedArea.height,
|
|
|
|
aLine->mBounds.XMost());
|
|
|
|
#endif
|
|
|
|
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
|
|
|
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
2000-01-03 04:32:13 +00:00
|
|
|
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// Mark the line dirty so we come back and re-place the floater once
|
|
|
|
// the shrink wrap width is determined
|
|
|
|
aLine->MarkDirty();
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
}
|
|
|
|
aLine->SetCombinedArea(lineCombinedArea);
|
|
|
|
#ifdef NOISY_COMBINED_AREA
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" ==> final lineCA=%d,%d,%d,%d\n",
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
|
|
|
#endif
|
|
|
|
aState.mHaveRightFloaters = PR_FALSE;
|
1999-03-23 04:28:20 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Apply break-after clearing if necessary
|
1999-10-12 23:24:22 +00:00
|
|
|
PRUint8 breakType = aLine->GetBreakType();
|
|
|
|
switch (breakType) {
|
1998-12-05 16:02:08 +00:00
|
|
|
case NS_STYLE_CLEAR_LEFT:
|
|
|
|
case NS_STYLE_CLEAR_RIGHT:
|
|
|
|
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
1999-10-12 23:24:22 +00:00
|
|
|
aState.ClearFloaters(aState.mY, breakType);
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return rv;
|
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-17 18:52:10 +00:00
|
|
|
// Compute the line's max-element-size by adding into the raw value
|
|
|
|
// computed by reflowing the contents of the line (aMaxElementSize)
|
|
|
|
// the impact of floaters on this line or the preceeding lines.
|
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState,
|
1999-03-20 19:40:13 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsSize* aMaxElementSize)
|
1998-12-17 18:52:10 +00:00
|
|
|
{
|
|
|
|
nscoord maxWidth, maxHeight;
|
1999-10-21 20:43:48 +00:00
|
|
|
aState.mBand.GetMaxElementSize(aState.mPresContext, &maxWidth, &maxHeight);
|
1999-03-20 19:40:13 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
1999-03-22 23:03:31 +00:00
|
|
|
IndentBy(stdout, GetDepth());
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("PASS1 ");
|
1999-03-22 23:03:31 +00:00
|
|
|
}
|
1999-03-20 19:40:13 +00:00
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": maxFloaterSize=%d,%d\n", maxWidth, maxHeight);
|
1999-03-20 19:40:13 +00:00
|
|
|
#endif
|
1998-12-17 18:52:10 +00:00
|
|
|
|
1999-03-22 23:03:31 +00:00
|
|
|
// If the floaters are wider than the content, then use the maximum
|
|
|
|
// floater width as the maximum width.
|
|
|
|
//
|
|
|
|
// It used to be the case that we would always place some content
|
|
|
|
// next to a floater, regardless of the amount of available space
|
|
|
|
// after subtracing off the floaters sizes. This can lead to content
|
|
|
|
// overlapping floaters, so we no longer do this (and pass CSS2's
|
|
|
|
// conformance tests). This is not how navigator 4-1 used to do
|
|
|
|
// things.
|
|
|
|
if (maxWidth > aMaxElementSize->width) {
|
|
|
|
aMaxElementSize->width = maxWidth;
|
|
|
|
}
|
1998-12-17 18:52:10 +00:00
|
|
|
|
1999-03-20 19:40:13 +00:00
|
|
|
// Only update the max-element-size's height value if the floater is
|
|
|
|
// part of the current line.
|
1999-10-14 23:10:03 +00:00
|
|
|
if (aLine->HasFloaters()) {
|
1999-03-20 19:40:13 +00:00
|
|
|
// If the maximum-height of the tallest floater is larger than the
|
|
|
|
// maximum-height of the content then update the max-element-size
|
|
|
|
// height
|
|
|
|
if (maxHeight > aMaxElementSize->height) {
|
|
|
|
aMaxElementSize->height = maxHeight;
|
|
|
|
}
|
1998-12-17 18:52:10 +00:00
|
|
|
}
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf ("nsBlockFrame::ComputeLineMaxElementSize: %p returning MES %d\n",
|
|
|
|
this, aMaxElementSize->width);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1998-12-17 18:52:10 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
1999-03-18 21:03:25 +00:00
|
|
|
nsLineBox* aLine,
|
|
|
|
const nsSize& aMaxElementSize)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-11-19 15:33:29 +00:00
|
|
|
// If it's inline elements, then make sure the views are correctly
|
|
|
|
// positioned and sized
|
|
|
|
if (aLine->IsInline()) {
|
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
|
|
|
for (PRInt32 i = 0; i < aLine->GetChildCount(); i++) {
|
|
|
|
::PlaceFrameView(aState.mPresContext, frame);
|
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Update max-element-size
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
1999-04-03 18:59:01 +00:00
|
|
|
aState.UpdateMaxElementSize(aMaxElementSize);
|
1999-08-28 00:39:55 +00:00
|
|
|
// We also cache the max element width in the line. This is needed for
|
|
|
|
// incremental reflow
|
|
|
|
aLine->mMaxElementWidth = aMaxElementSize.width;
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf ("nsBlockFrame::PostPlaceLine: %p setting line %p MES %d\n",
|
|
|
|
this, aLine, aMaxElementSize.width);
|
2000-05-14 04:56:25 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1999-12-30 04:15:45 +00:00
|
|
|
// If this is an unconstrained reflow, then cache the line width in the
|
|
|
|
// line. We'll need this during incremental reflow if we're asked to
|
|
|
|
// calculate the maximum width
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
2000-05-14 04:56:25 +00:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockFrame::PostPlaceLine during UC Reflow of block %p line %p caching max width %d\n",
|
2000-05-14 04:56:25 +00:00
|
|
|
this, aLine, aLine->mBounds.XMost());
|
|
|
|
#endif
|
1999-12-30 04:15:45 +00:00
|
|
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Update xmost
|
|
|
|
nscoord xmost = aLine->mBounds.XMost();
|
1999-03-20 21:57:03 +00:00
|
|
|
#ifdef DEBUG
|
1999-09-17 23:16:43 +00:00
|
|
|
if (CRAZY_WIDTH(xmost)) {
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": line=%p xmost=%d\n", aLine, xmost);
|
1999-09-17 23:16:43 +00:00
|
|
|
}
|
1999-03-05 04:21:32 +00:00
|
|
|
#endif
|
2000-01-03 04:32:13 +00:00
|
|
|
// If we're shrink wrapping our width and the line was wrapped,
|
|
|
|
// then make sure we take up all of the available width
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
2000-01-03 04:32:13 +00:00
|
|
|
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
2000-06-11 22:14:33 +00:00
|
|
|
#ifdef NOISY_KIDXMOST
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p PostPlaceLine A aState.mKidXMost=%d\n", this, aState.mKidXMost);
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
2000-01-03 04:32:13 +00:00
|
|
|
}
|
|
|
|
else if (xmost > aState.mKidXMost) {
|
1998-12-05 16:02:08 +00:00
|
|
|
aState.mKidXMost = xmost;
|
2000-06-11 22:14:33 +00:00
|
|
|
#ifdef NOISY_KIDXMOST
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p PostPlaceLine B aState.mKidXMost=%d\n", this, aState.mKidXMost);
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-30 20:14:04 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::PushLines(nsBlockReflowState& aState)
|
1998-07-06 21:37:08 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_ASSERTION(nsnull != aState.mPrevLine, "bad push");
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox* lastLine = aState.mPrevLine;
|
|
|
|
nsLineBox* nextLine = lastLine->mNext;
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1999-12-07 23:41:48 +00:00
|
|
|
if (nextLine) {
|
|
|
|
lastLine->mNext = nsnull;
|
|
|
|
SetOverflowLines(aState.mPresContext, nextLine);
|
|
|
|
|
|
|
|
// Mark all the overflow lines dirty so that they get reflowed when
|
|
|
|
// they are pulled up by our next-in-flow.
|
|
|
|
while (nsnull != nextLine) {
|
|
|
|
nextLine->MarkDirty();
|
|
|
|
nextLine = nextLine->mNext;
|
|
|
|
}
|
1998-09-25 05:13:06 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Break frame sibling list
|
|
|
|
nsIFrame* lastFrame = lastLine->LastChild();
|
|
|
|
lastFrame->SetNextSibling(nsnull);
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-11-02 23:42:52 +00:00
|
|
|
VerifyOverflowSituation(aState.mPresContext);
|
1998-09-25 05:13:06 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool
|
1999-10-26 04:44:41 +00:00
|
|
|
nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-11-02 23:42:52 +00:00
|
|
|
VerifyOverflowSituation(aPresContext);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool drained = PR_FALSE;
|
1999-11-02 23:42:52 +00:00
|
|
|
nsLineBox* overflowLines;
|
1998-11-17 01:04:45 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// First grab the prev-in-flows overflow lines
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull != prevBlock) {
|
1999-11-02 23:42:52 +00:00
|
|
|
overflowLines = prevBlock->GetOverflowLines(aPresContext, PR_TRUE);
|
|
|
|
if (nsnull != overflowLines) {
|
1998-12-05 16:02:08 +00:00
|
|
|
drained = PR_TRUE;
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1999-11-02 23:42:52 +00:00
|
|
|
// Make all the frames on the overflow line list mine
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* lastFrame = nsnull;
|
1999-11-02 23:42:52 +00:00
|
|
|
nsIFrame* frame = overflowLines->mFirstChild;
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != frame) {
|
1999-01-14 05:16:23 +00:00
|
|
|
frame->SetParent(this);
|
1999-04-11 04:22:00 +00:00
|
|
|
|
|
|
|
// When pushing and pulling frames we need to check for whether any
|
|
|
|
// views need to be reparented
|
1999-10-26 04:44:41 +00:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, prevBlock, this);
|
1999-04-11 04:22:00 +00:00
|
|
|
|
|
|
|
// Get the next frame
|
1998-12-05 16:02:08 +00:00
|
|
|
lastFrame = frame;
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-09-25 05:13:06 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Join the line lists
|
|
|
|
if (nsnull == mLines) {
|
1999-11-02 23:42:52 +00:00
|
|
|
mLines = overflowLines;
|
1998-09-25 05:13:06 +00:00
|
|
|
}
|
|
|
|
else {
|
1998-12-05 16:02:08 +00:00
|
|
|
// Join the sibling lists together
|
|
|
|
lastFrame->SetNextSibling(mLines->mFirstChild);
|
1998-09-25 05:13:06 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Place overflow lines at the front of our line list
|
1999-11-02 23:42:52 +00:00
|
|
|
nsLineBox* lastLine = nsLineBox::LastLine(overflowLines);
|
1998-12-05 16:02:08 +00:00
|
|
|
lastLine->mNext = mLines;
|
1999-11-02 23:42:52 +00:00
|
|
|
mLines = overflowLines;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-09-25 05:13:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Now grab our own overflow lines
|
1999-11-02 23:42:52 +00:00
|
|
|
overflowLines = GetOverflowLines(aPresContext, PR_TRUE);
|
|
|
|
if (overflowLines) {
|
1998-12-05 16:02:08 +00:00
|
|
|
// This can happen when we reflow and not everything fits and then
|
|
|
|
// we are told to reflow again before a next-in-flow is created
|
|
|
|
// and reflows.
|
|
|
|
nsLineBox* lastLine = nsLineBox::LastLine(mLines);
|
2000-03-22 23:19:10 +00:00
|
|
|
if (nsnull == lastLine) { // if we had no lines before the drain operation
|
|
|
|
mLines = overflowLines; // set our mLines to the overflow
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
2000-03-22 23:19:10 +00:00
|
|
|
else { // otherwise, append the overflow to the mLines list
|
1999-11-02 23:42:52 +00:00
|
|
|
lastLine->mNext = overflowLines;
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* lastFrame = lastLine->LastChild();
|
1999-11-02 23:42:52 +00:00
|
|
|
lastFrame->SetNextSibling(overflowLines->mFirstChild);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
drained = PR_TRUE;
|
|
|
|
}
|
|
|
|
return drained;
|
1998-09-25 16:10:10 +00:00
|
|
|
}
|
|
|
|
|
1999-11-02 23:42:52 +00:00
|
|
|
nsLineBox*
|
|
|
|
nsBlockFrame::GetOverflowLines(nsIPresContext* aPresContext,
|
2000-01-22 01:16:50 +00:00
|
|
|
PRBool aRemoveProperty) const
|
1999-11-02 23:42:52 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
|
|
|
if (presShell) {
|
|
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
|
|
presShell->GetFrameManager(getter_AddRefs(frameManager));
|
|
|
|
|
|
|
|
if (frameManager) {
|
|
|
|
PRUint32 options = 0;
|
|
|
|
void* value;
|
|
|
|
|
|
|
|
if (aRemoveProperty) {
|
|
|
|
options |= NS_IFRAME_MGR_REMOVE_PROP;
|
|
|
|
}
|
2000-01-22 01:16:50 +00:00
|
|
|
frameManager->GetFrameProperty((nsIFrame*)this, nsLayoutAtoms::overflowLinesProperty,
|
1999-11-02 23:42:52 +00:00
|
|
|
options, &value);
|
|
|
|
return (nsLineBox*)value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor function for the overflowLines frame property
|
|
|
|
static void
|
|
|
|
DestroyOverflowLines(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIAtom* aPropertyName,
|
|
|
|
void* aPropertyValue)
|
|
|
|
{
|
|
|
|
if (aPropertyValue) {
|
|
|
|
nsLineBox* lines = (nsLineBox*) aPropertyValue;
|
|
|
|
nsLineBox::DeleteLineList(aPresContext, lines);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::SetOverflowLines(nsIPresContext* aPresContext,
|
|
|
|
nsLineBox* aOverflowFrames)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
if (presShell) {
|
|
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
|
|
presShell->GetFrameManager(getter_AddRefs(frameManager));
|
|
|
|
|
|
|
|
if (frameManager) {
|
|
|
|
rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::overflowLinesProperty,
|
|
|
|
aOverflowFrames, DestroyOverflowLines);
|
|
|
|
|
|
|
|
// Verify that we didn't overwrite an existing overflow list
|
|
|
|
NS_ASSERTION(rv != NS_IFRAME_MGR_PROP_OVERWRITTEN, "existing overflow list");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-17 18:52:10 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Frame list manipulation routines
|
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
nsIFrame*
|
|
|
|
nsBlockFrame::LastChild()
|
|
|
|
{
|
|
|
|
if (mLines) {
|
|
|
|
nsLineBox* line = nsLineBox::LastLine(mLines);
|
|
|
|
return line->LastChild();
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
1999-02-02 17:31:09 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::AppendFrames(nsIPresContext* aPresContext,
|
1999-02-26 17:04:44 +00:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aFrameList)
|
1999-02-02 17:31:09 +00:00
|
|
|
{
|
1999-04-21 19:58:38 +00:00
|
|
|
if (nsnull == aFrameList) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-09 05:06:16 +00:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.AppendFrames(this, aPresContext, aPresShell, aListName,
|
|
|
|
aFrameList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 17:04:44 +00:00
|
|
|
// XXX we don't *really* care about this right now because we are
|
|
|
|
// BuildFloaterList ing still
|
|
|
|
mFloaters.AppendFrames(nsnull, aFrameList);
|
|
|
|
return NS_OK;
|
1999-02-03 19:09:24 +00:00
|
|
|
}
|
1999-02-26 17:04:44 +00:00
|
|
|
else if (nsnull != aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
// Find the proper last-child for where the append should go
|
|
|
|
nsIFrame* lastKid = nsnull;
|
|
|
|
nsLineBox* lastLine = nsLineBox::LastLine(mLines);
|
|
|
|
if (lastLine) {
|
|
|
|
lastKid = lastLine->LastChild();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add frames after the last child
|
1999-04-21 19:58:38 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": append ");
|
1999-04-21 19:58:38 +00:00
|
|
|
nsFrame::ListTag(stdout, aFrameList);
|
|
|
|
if (lastKid) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" after ");
|
1999-04-21 19:58:38 +00:00
|
|
|
nsFrame::ListTag(stdout, lastKid);
|
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-04-21 19:58:38 +00:00
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
nsresult rv = AddFrames(aPresContext, aFrameList, lastKid);
|
1999-02-02 17:31:09 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 03:58:05 +00:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 17:31:09 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::InsertFrames(nsIPresContext* aPresContext,
|
1999-02-26 17:04:44 +00:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aPrevFrame,
|
|
|
|
nsIFrame* aFrameList)
|
1999-02-02 17:31:09 +00:00
|
|
|
{
|
2000-05-09 05:06:16 +00:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.InsertFrames(this, aPresContext, aPresShell, aListName,
|
|
|
|
aPrevFrame, aFrameList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 17:04:44 +00:00
|
|
|
// XXX we don't *really* care about this right now because we are
|
1999-07-14 15:16:56 +00:00
|
|
|
// BuildFloaterList'ing still
|
1999-02-26 17:04:44 +00:00
|
|
|
mFloaters.AppendFrames(nsnull, aFrameList);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (nsnull != aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
1999-02-03 19:09:24 +00:00
|
|
|
}
|
1999-02-26 17:04:44 +00:00
|
|
|
|
1999-04-21 19:58:38 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": insert ");
|
1999-04-21 19:58:38 +00:00
|
|
|
nsFrame::ListTag(stdout, aFrameList);
|
|
|
|
if (aPrevFrame) {
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" after ");
|
1999-04-21 19:58:38 +00:00
|
|
|
nsFrame::ListTag(stdout, aPrevFrame);
|
|
|
|
}
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-04-21 19:58:38 +00:00
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
nsresult rv = AddFrames(aPresContext, aFrameList, aPrevFrame);
|
1999-02-02 17:31:09 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 03:58:05 +00:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 17:31:09 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-06-18 16:25:41 +00:00
|
|
|
nsresult
|
1999-04-20 00:27:43 +00:00
|
|
|
nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrameList,
|
|
|
|
nsIFrame* aPrevSibling)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1999-04-20 00:27:43 +00:00
|
|
|
if (nsnull == aFrameList) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-12 03:00:51 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
// Attempt to find the line that contains the previous sibling
|
1999-04-20 03:42:32 +00:00
|
|
|
nsLineBox* prevSibLine = nsnull;
|
1999-04-20 21:51:39 +00:00
|
|
|
PRInt32 prevSiblingIndex = -1;
|
1999-04-20 00:27:43 +00:00
|
|
|
if (aPrevSibling) {
|
1999-11-01 15:24:57 +00:00
|
|
|
// Find the line that contains the previous sibling
|
|
|
|
prevSibLine = nsLineBox::FindLineContaining(mLines, aPrevSibling,
|
|
|
|
&prevSiblingIndex);
|
|
|
|
NS_ASSERTION(nsnull != prevSibLine, "prev sibling not in line list");
|
|
|
|
if (nsnull == prevSibLine) {
|
|
|
|
// Note: defensive code! FindLineContaining must not return
|
|
|
|
// null in this case, so if it does...
|
|
|
|
aPrevSibling = nsnull;
|
1999-02-01 17:29:37 +00:00
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
|
1999-04-20 21:51:39 +00:00
|
|
|
// Find the frame following aPrevSibling so that we can join up the
|
|
|
|
// two lists of frames.
|
1999-04-20 00:27:43 +00:00
|
|
|
nsIFrame* prevSiblingNextFrame = nsnull;
|
|
|
|
if (aPrevSibling) {
|
|
|
|
aPrevSibling->GetNextSibling(&prevSiblingNextFrame);
|
1999-04-20 21:51:39 +00:00
|
|
|
|
|
|
|
// Split line containing aPrevSibling in two if the insertion
|
|
|
|
// point is somewhere in the middle of the line.
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
|
1999-04-20 21:51:39 +00:00
|
|
|
if (rem) {
|
|
|
|
// Split the line in two where the frame(s) are being inserted.
|
2000-03-12 03:00:51 +00:00
|
|
|
nsLineBox* line = NS_NewLineBox(presShell, prevSiblingNextFrame, rem, PR_FALSE);
|
1999-04-20 21:51:39 +00:00
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
line->mNext = prevSibLine->mNext;
|
|
|
|
prevSibLine->mNext = line;
|
1999-10-14 23:10:03 +00:00
|
|
|
prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
|
1999-04-20 21:51:39 +00:00
|
|
|
prevSibLine->MarkDirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now (partially) join the sibling lists together
|
1999-04-20 03:42:32 +00:00
|
|
|
aPrevSibling->SetNextSibling(aFrameList);
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
else if (mLines) {
|
|
|
|
prevSiblingNextFrame = mLines->mFirstChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk through the new frames being added and update the line data
|
|
|
|
// structures to fit.
|
1999-04-20 21:51:39 +00:00
|
|
|
nsIFrame* newFrame = aFrameList;
|
|
|
|
while (newFrame) {
|
1999-10-12 23:24:22 +00:00
|
|
|
PRBool isBlock = nsLineLayout::TreatFrameAsBlock(newFrame);
|
|
|
|
|
1999-04-20 21:51:39 +00:00
|
|
|
// If the frame is a block frame, or if there is no previous line
|
|
|
|
// or if the previous line is a block line then make a new line.
|
|
|
|
if (isBlock || !prevSibLine || prevSibLine->IsBlock()) {
|
|
|
|
// Create a new line for the frame and add its line to the line
|
|
|
|
// list.
|
2000-03-12 03:00:51 +00:00
|
|
|
nsLineBox* line = NS_NewLineBox(presShell, newFrame, 1, isBlock);
|
1999-04-20 00:27:43 +00:00
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
1999-04-20 03:42:32 +00:00
|
|
|
if (prevSibLine) {
|
|
|
|
// Append new line after prevSibLine
|
|
|
|
line->mNext = prevSibLine->mNext;
|
|
|
|
prevSibLine->mNext = line;
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// New line is going before the other lines
|
|
|
|
line->mNext = mLines;
|
|
|
|
mLines = line;
|
|
|
|
}
|
1999-04-20 03:42:32 +00:00
|
|
|
prevSibLine = line;
|
1999-02-01 17:29:37 +00:00
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
else {
|
1999-10-14 23:10:03 +00:00
|
|
|
prevSibLine->SetChildCount(prevSibLine->GetChildCount() + 1);
|
1999-04-20 21:51:39 +00:00
|
|
|
prevSibLine->MarkDirty();
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
1999-04-20 21:51:39 +00:00
|
|
|
|
|
|
|
aPrevSibling = newFrame;
|
|
|
|
newFrame->GetNextSibling(&newFrame);
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
1999-04-20 03:42:32 +00:00
|
|
|
if (prevSiblingNextFrame) {
|
1999-04-20 21:51:39 +00:00
|
|
|
// Connect the last new frame to the remainder of the sibling list
|
|
|
|
aPrevSibling->SetNextSibling(prevSiblingNextFrame);
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
nsBlockFrame::FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
while (aFrame) {
|
|
|
|
nsIFrame* oldParent;
|
|
|
|
aFrame->GetParent(&oldParent);
|
|
|
|
aFrame->SetParent(this);
|
|
|
|
if (this != oldParent) {
|
1999-10-26 04:44:41 +00:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aPresContext, aFrame, oldParent, this);
|
1999-09-03 23:35:41 +00:00
|
|
|
aPresContext->ReParentStyleContext(aFrame, mStyleContext);
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
aFrame->GetNextSibling(&aFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-02 17:31:09 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::RemoveFrame(nsIPresContext* aPresContext,
|
1999-02-26 17:04:44 +00:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aOldFrame)
|
1999-02-02 17:31:09 +00:00
|
|
|
{
|
1999-02-26 17:04:44 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1999-09-22 00:58:58 +00:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": remove ");
|
1999-09-22 00:58:58 +00:00
|
|
|
nsFrame::ListTag(stdout, aOldFrame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-09-22 00:58:58 +00:00
|
|
|
#endif
|
|
|
|
|
2000-05-09 05:06:16 +00:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.RemoveFrame(this, aPresContext, aPresShell, aListName, aOldFrame);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 17:04:44 +00:00
|
|
|
// Remove floater from the floater list first
|
|
|
|
mFloaters.RemoveFrame(aOldFrame);
|
|
|
|
|
|
|
|
// Find which line contains the floater
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
1999-10-29 14:34:53 +00:00
|
|
|
if (line->IsInline() && line->RemoveFloater(aOldFrame)) {
|
1999-09-15 00:28:10 +00:00
|
|
|
aOldFrame->Destroy(aPresContext);
|
|
|
|
goto found_it;
|
1999-02-26 17:04:44 +00:00
|
|
|
}
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
found_it:
|
|
|
|
|
|
|
|
// Mark every line at and below the line where the floater was dirty
|
|
|
|
while (nsnull != line) {
|
|
|
|
line->MarkDirty();
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (nsnull != aListName) {
|
1999-09-22 00:58:58 +00:00
|
|
|
rv = NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
else {
|
1999-11-24 06:03:41 +00:00
|
|
|
rv = DoRemoveFrame(aPresContext, aOldFrame);
|
1999-02-03 19:09:24 +00:00
|
|
|
}
|
1999-02-23 19:18:12 +00:00
|
|
|
|
1999-02-02 17:31:09 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 03:58:05 +00:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 17:31:09 +00:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
nsresult
|
1999-04-20 00:27:43 +00:00
|
|
|
nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
1999-02-18 18:25:45 +00:00
|
|
|
nsIFrame* aDeletedFrame)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
2000-03-12 03:00:51 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
1999-01-05 23:01:54 +00:00
|
|
|
// Find the line and the previous sibling that contains
|
|
|
|
// deletedFrame; we also find the pointer to the line.
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame* flow = this;
|
1998-12-05 16:02:08 +00:00
|
|
|
nsLineBox** linep = &flow->mLines;
|
|
|
|
nsLineBox* line = flow->mLines;
|
1999-01-05 23:01:54 +00:00
|
|
|
nsLineBox* prevLine = nsnull;
|
|
|
|
nsIFrame* prevSibling = nsnull;
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != line) {
|
1999-01-05 23:01:54 +00:00
|
|
|
nsIFrame* frame = line->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1999-01-05 23:01:54 +00:00
|
|
|
while (--n >= 0) {
|
|
|
|
if (frame == aDeletedFrame) {
|
|
|
|
goto found_frame;
|
|
|
|
}
|
|
|
|
prevSibling = frame;
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-10-16 20:22:39 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
linep = &line->mNext;
|
1999-01-05 23:01:54 +00:00
|
|
|
prevLine = line;
|
1998-12-05 16:02:08 +00:00
|
|
|
line = line->mNext;
|
1998-08-04 21:18:16 +00:00
|
|
|
}
|
1999-01-05 23:01:54 +00:00
|
|
|
found_frame:;
|
|
|
|
#ifdef NS_DEBUG
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_ASSERTION(nsnull != line, "can't find deleted frame in lines");
|
1999-01-05 23:01:54 +00:00
|
|
|
if (nsnull != prevSibling) {
|
|
|
|
nsIFrame* tmp;
|
1999-02-10 06:13:38 +00:00
|
|
|
prevSibling->GetNextSibling(&tmp);
|
1999-01-05 23:01:54 +00:00
|
|
|
NS_ASSERTION(tmp == aDeletedFrame, "bad prevSibling");
|
|
|
|
}
|
|
|
|
#endif
|
1998-08-04 21:18:16 +00:00
|
|
|
|
1999-01-05 23:01:54 +00:00
|
|
|
// Remove frame and all of its continuations
|
1998-12-05 16:02:08 +00:00
|
|
|
while (nsnull != aDeletedFrame) {
|
|
|
|
while ((nsnull != line) && (nsnull != aDeletedFrame)) {
|
1998-06-24 17:52:42 +00:00
|
|
|
#ifdef NS_DEBUG
|
1999-08-31 03:09:40 +00:00
|
|
|
nsIFrame* parent;
|
1999-02-10 01:36:30 +00:00
|
|
|
aDeletedFrame->GetParent(&parent);
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_ASSERTION(flow == parent, "messed up delete code");
|
1999-03-16 19:36:00 +00:00
|
|
|
NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line");
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
|
|
|
|
1999-03-16 19:36:00 +00:00
|
|
|
// See if the frame being deleted is the last one on the line
|
|
|
|
PRBool isLastFrameOnLine = PR_FALSE;
|
1999-10-14 23:10:03 +00:00
|
|
|
if (1 == line->GetChildCount()) {
|
1999-03-16 19:36:00 +00:00
|
|
|
isLastFrameOnLine = PR_TRUE;
|
|
|
|
}
|
|
|
|
else if (line->LastChild() == aDeletedFrame) {
|
|
|
|
isLastFrameOnLine = PR_TRUE;
|
|
|
|
}
|
1999-01-05 23:01:54 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Remove aDeletedFrame from the line
|
1999-03-16 19:36:00 +00:00
|
|
|
nsIFrame* nextFrame;
|
|
|
|
aDeletedFrame->GetNextSibling(&nextFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (line->mFirstChild == aDeletedFrame) {
|
|
|
|
line->mFirstChild = nextFrame;
|
1999-02-18 18:25:45 +00:00
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
if (prevLine && !prevLine->IsBlock()) {
|
|
|
|
// Since we just removed a frame that follows some inline
|
|
|
|
// frames, we need to reflow the previous line.
|
1999-02-18 18:25:45 +00:00
|
|
|
prevLine->MarkDirty();
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1999-01-05 23:01:54 +00:00
|
|
|
// Take aDeletedFrame out of the sibling list. Note that
|
|
|
|
// prevSibling will only be nsnull when we are deleting the very
|
|
|
|
// first frame.
|
|
|
|
if (nsnull != prevSibling) {
|
|
|
|
prevSibling->SetNextSibling(nextFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy frame; capture its next-in-flow first in case we need
|
|
|
|
// to destroy that too.
|
|
|
|
nsIFrame* nextInFlow;
|
1999-02-24 04:48:08 +00:00
|
|
|
aDeletedFrame->GetNextInFlow(&nextInFlow);
|
1999-03-16 19:36:00 +00:00
|
|
|
nsSplittableType st;
|
|
|
|
aDeletedFrame->IsSplittable(st);
|
|
|
|
if (NS_FRAME_NOT_SPLITTABLE != st) {
|
1999-10-22 14:53:52 +00:00
|
|
|
nsSplittableFrame::RemoveFromFlow(aDeletedFrame);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef NOISY_REMOVE_FRAME
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("DoRemoveFrame: prevLine=%p line=%p frame=",
|
1999-03-16 19:36:00 +00:00
|
|
|
prevLine, line);
|
|
|
|
nsFrame::ListTag(stdout, aDeletedFrame);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" prevSibling=%p nextInFlow=%p\n", prevSibling, nextInFlow);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1999-11-24 06:03:41 +00:00
|
|
|
aDeletedFrame->Destroy(aPresContext);
|
1998-12-05 16:02:08 +00:00
|
|
|
aDeletedFrame = nextInFlow;
|
|
|
|
|
|
|
|
// If line is empty, remove it now
|
|
|
|
nsLineBox* next = line->mNext;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 lineChildCount = line->GetChildCount();
|
|
|
|
if (0 == --lineChildCount) {
|
1998-12-05 16:02:08 +00:00
|
|
|
*linep = next;
|
|
|
|
line->mNext = nsnull;
|
1999-09-21 05:15:39 +00:00
|
|
|
// Invalidate the space taken up by the line.
|
|
|
|
// XXX We need to do this if we're removing a frame as a result of
|
|
|
|
// a call to RemoveFrame(), but we may not need to do this in all
|
|
|
|
// cases...
|
1999-10-14 23:10:03 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
2000-04-17 14:40:46 +00:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
2000-04-17 14:40:46 +00:00
|
|
|
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
|
|
|
#endif
|
1999-10-26 04:44:41 +00:00
|
|
|
Invalidate(aPresContext, lineCombinedArea);
|
2000-03-12 03:00:51 +00:00
|
|
|
line->Destroy(presShell);
|
1999-03-16 19:36:00 +00:00
|
|
|
line = next;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-03-16 19:36:00 +00:00
|
|
|
// Make the line that just lost a frame dirty
|
1999-10-14 23:10:03 +00:00
|
|
|
line->SetChildCount(lineChildCount);
|
1999-01-05 23:01:54 +00:00
|
|
|
line->MarkDirty();
|
1999-03-16 19:36:00 +00:00
|
|
|
|
|
|
|
// If we just removed the last frame on the line then we need
|
|
|
|
// to advance to the next line.
|
|
|
|
if (isLastFrameOnLine) {
|
|
|
|
prevLine = line;
|
|
|
|
linep = &line->mNext;
|
|
|
|
line = next;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1999-01-05 23:01:54 +00:00
|
|
|
|
|
|
|
// See if we should keep looking in the current flow's line list.
|
|
|
|
if (nsnull != aDeletedFrame) {
|
|
|
|
if (aDeletedFrame != nextFrame) {
|
|
|
|
// The deceased frames continuation is not the next frame in
|
|
|
|
// the current flow's frame list. Therefore we know that the
|
|
|
|
// continuation is in a different parent. So break out of
|
|
|
|
// the loop so that we advance to the next parent.
|
|
|
|
#ifdef NS_DEBUG
|
1999-05-13 00:55:38 +00:00
|
|
|
nsIFrame* checkParent;
|
|
|
|
aDeletedFrame->GetParent(&checkParent);
|
|
|
|
NS_ASSERTION(checkParent != flow, "strange continuation");
|
1999-01-05 23:01:54 +00:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Advance to next flow block if the frame has more continuations
|
2000-10-27 14:14:36 +00:00
|
|
|
if (flow && aDeletedFrame) {
|
1999-02-09 17:31:33 +00:00
|
|
|
flow = (nsBlockFrame*) flow->mNextInFlow;
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_ASSERTION(nsnull != flow, "whoops, continuation without a parent");
|
2000-10-27 14:14:36 +00:00
|
|
|
// add defensive pointer check for bug 56894
|
|
|
|
if(flow) {
|
|
|
|
prevLine = nsnull;
|
|
|
|
line = flow->mLines;
|
|
|
|
linep = &flow->mLines;
|
|
|
|
prevSibling = nsnull;
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
1999-04-20 00:27:43 +00:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1999-01-15 22:53:39 +00:00
|
|
|
void
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext* aPresContext,
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* aChild)
|
1998-09-23 02:25:26 +00:00
|
|
|
{
|
1999-11-24 06:03:41 +00:00
|
|
|
NS_PRECONDITION(IsChild(aPresContext, aChild), "bad geometric parent");
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* nextInFlow;
|
1999-02-24 04:48:08 +00:00
|
|
|
aChild->GetNextInFlow(&nextInFlow);
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_PRECONDITION(nsnull != nextInFlow, "null next-in-flow");
|
1999-03-16 19:36:00 +00:00
|
|
|
nsBlockFrame* parent;
|
1999-02-10 01:36:30 +00:00
|
|
|
nextInFlow->GetParent((nsIFrame**)&parent);
|
1999-03-16 19:36:00 +00:00
|
|
|
NS_PRECONDITION(nsnull != parent, "next-in-flow with no parent");
|
|
|
|
NS_PRECONDITION(nsnull != parent->mLines, "next-in-flow with weird parent");
|
1999-11-02 23:42:52 +00:00
|
|
|
// NS_PRECONDITION(nsnull == parent->mOverflowLines, "parent with overflow");
|
1999-11-24 06:03:41 +00:00
|
|
|
parent->DoRemoveFrame(aPresContext, nextInFlow);
|
1998-10-02 21:50:53 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Floater support
|
|
|
|
|
1999-04-01 01:37:36 +00:00
|
|
|
nsresult
|
1999-03-23 04:28:20 +00:00
|
|
|
nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|
|
|
nsPlaceholderFrame* aPlaceholder,
|
1999-04-01 01:37:36 +00:00
|
|
|
nsRect& aCombinedRect,
|
1999-07-14 17:26:20 +00:00
|
|
|
nsMargin& aMarginResult,
|
|
|
|
nsMargin& aComputedOffsetsResult)
|
1998-10-02 21:50:53 +00:00
|
|
|
{
|
2000-06-11 22:14:33 +00:00
|
|
|
#ifdef NOISY_FLOATER
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("Reflow Floater %p in parent %p, availSpace(%d,%d,%d,%d)\n",
|
2000-06-11 22:14:33 +00:00
|
|
|
aPlaceholder->GetOutOfFlowFrame(), this,
|
|
|
|
aState.mAvailSpaceRect.x, aState.mAvailSpaceRect.y,
|
|
|
|
aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
|
2000-10-28 22:17:53 +00:00
|
|
|
);
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
1999-09-10 18:52:56 +00:00
|
|
|
// XXX update this just
|
|
|
|
aState.GetAvailableSpace();
|
|
|
|
|
1999-03-23 04:28:20 +00:00
|
|
|
// Reflow the floater. Since floaters are continued we given them an
|
|
|
|
// unbounded height. Floaters with an auto width are sized to zero
|
|
|
|
// according to the css2 spec.
|
2000-01-29 00:47:33 +00:00
|
|
|
// XXX We also need to take into account whether we should clear any
|
|
|
|
// preceeding floaters...
|
|
|
|
// XXX Why do we have to add in our border/padding?
|
|
|
|
nsRect availSpace(aState.mAvailSpaceRect.x + aState.BorderPadding().left,
|
|
|
|
aState.mAvailSpaceRect.y + aState.BorderPadding().top,
|
|
|
|
aState.mAvailSpaceRect.width, NS_UNCONSTRAINEDSIZE);
|
1999-04-23 14:34:48 +00:00
|
|
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
1999-04-01 01:37:36 +00:00
|
|
|
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
|
|
|
|
|
|
|
// Setup block reflow state to reflow the floater
|
|
|
|
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
2000-04-17 14:40:46 +00:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
|
|
|
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
1999-04-01 01:37:36 +00:00
|
|
|
brc.SetNextRCFrame(aState.mNextRCFrame);
|
|
|
|
|
|
|
|
// Reflow the floater
|
|
|
|
nsReflowStatus frameReflowStatus;
|
1999-10-15 23:35:10 +00:00
|
|
|
nsresult rv = brc.ReflowBlock(floater, availSpace, PR_TRUE, 0,
|
|
|
|
isAdjacentWithTop,
|
1999-07-14 17:26:20 +00:00
|
|
|
aComputedOffsetsResult, frameReflowStatus);
|
2000-05-09 05:06:16 +00:00
|
|
|
if (PR_TRUE==brc.BlockShouldInvalidateItself()) {
|
|
|
|
Invalidate(aState.mPresContext, mRect);
|
|
|
|
}
|
2000-01-26 22:18:33 +00:00
|
|
|
if (floater == aState.mNextRCFrame) {
|
|
|
|
// NULL out mNextRCFrame so if we reflow it again we don't think it's still
|
|
|
|
// an incremental reflow
|
|
|
|
aState.mNextRCFrame = nsnull;
|
|
|
|
}
|
1999-04-01 01:37:36 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
1999-04-01 01:37:36 +00:00
|
|
|
|
|
|
|
// Capture the margin information for the caller
|
|
|
|
const nsMargin& m = brc.GetMargin();
|
|
|
|
aMarginResult.top = brc.GetTopMargin();
|
|
|
|
aMarginResult.right = m.right;
|
|
|
|
aMarginResult.bottom =
|
|
|
|
nsBlockReflowContext::MaxMargin(brc.GetCarriedOutBottomMargin(),
|
|
|
|
m.bottom);
|
|
|
|
aMarginResult.left = m.left;
|
|
|
|
|
|
|
|
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
|
1999-12-06 15:49:53 +00:00
|
|
|
aCombinedRect = metrics.mOverflowArea;
|
1999-11-30 05:09:08 +00:00
|
|
|
// Set the rect, make sure the view is properly sized and positioned,
|
|
|
|
// and tell the frame we're done reflowing it
|
1999-10-26 04:44:41 +00:00
|
|
|
floater->SizeTo(aState.mPresContext, metrics.width, metrics.height);
|
1999-11-30 05:09:08 +00:00
|
|
|
nsIView* view;
|
|
|
|
floater->GetView(aState.mPresContext, &view);
|
|
|
|
if (view) {
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, floater, view,
|
1999-12-06 15:49:53 +00:00
|
|
|
&metrics.mOverflowArea,
|
1999-11-30 05:09:08 +00:00
|
|
|
NS_FRAME_NO_MOVE_VIEW);
|
|
|
|
}
|
|
|
|
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
1999-10-21 20:43:48 +00:00
|
|
|
|
2000-01-28 03:12:30 +00:00
|
|
|
// If we computed it, then stash away the max-element-size for later
|
2000-04-17 14:40:46 +00:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2000-05-09 05:06:16 +00:00
|
|
|
nsSize mes = brc.GetMaxElementSize();
|
|
|
|
mes.SizeBy(aMarginResult.left + aMarginResult.right,
|
|
|
|
aMarginResult.top + aMarginResult.bottom);
|
|
|
|
aState.StoreMaxElementSize(floater, mes);
|
2001-01-28 17:00:19 +00:00
|
|
|
aState.UpdateMaxElementSize(mes); // fix for bug 13553
|
2000-01-28 03:12:30 +00:00
|
|
|
}
|
2000-06-11 22:14:33 +00:00
|
|
|
#ifdef NOISY_FLOATER
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("end ReflowFloater %p, sized to %d,%d\n", floater, metrics.width, metrics.height);
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
1999-04-01 01:37:36 +00:00
|
|
|
return NS_OK;
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-08-27 21:45:37 +00:00
|
|
|
nsBlockReflowState::InitFloater(nsLineLayout& aLineLayout,
|
|
|
|
nsPlaceholderFrame* aPlaceholder)
|
1998-09-23 02:25:26 +00:00
|
|
|
{
|
1998-12-15 04:20:54 +00:00
|
|
|
// Set the geometric parent of the floater
|
1999-04-23 14:34:48 +00:00
|
|
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
1999-01-14 05:16:23 +00:00
|
|
|
floater->SetParent(mBlock);
|
1998-10-09 22:58:25 +00:00
|
|
|
|
1998-12-15 04:20:54 +00:00
|
|
|
// Then add the floater to the current line and place it when
|
|
|
|
// appropriate
|
1999-08-27 21:45:37 +00:00
|
|
|
AddFloater(aLineLayout, aPlaceholder, PR_TRUE);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// This is called by the line layout's AddFloater method when a
|
|
|
|
// place-holder frame is reflowed in a line. If the floater is a
|
|
|
|
// left-most child (it's x coordinate is at the line's left margin)
|
|
|
|
// then the floater is place immediately, otherwise the floater
|
|
|
|
// placement is deferred until the line has been reflowed.
|
|
|
|
void
|
1999-08-27 21:45:37 +00:00
|
|
|
nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
|
|
|
nsPlaceholderFrame* aPlaceholder,
|
1998-12-15 04:20:54 +00:00
|
|
|
PRBool aInitialReflow)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-03-23 04:28:20 +00:00
|
|
|
NS_PRECONDITION(nsnull != mCurrentLine, "null ptr");
|
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Allocate a nsFloaterCache for the floater
|
|
|
|
nsFloaterCache* fc = mFloaterCacheFreeList.Alloc();
|
|
|
|
fc->mPlaceholder = aPlaceholder;
|
|
|
|
fc->mIsCurrentLineFloater = aLineLayout.CanPlaceFloaterNow();
|
1998-09-23 02:25:26 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Now place the floater immediately if possible. Otherwise stash it
|
|
|
|
// away in mPendingFloaters and place it later.
|
1999-09-15 00:28:10 +00:00
|
|
|
if (fc->mIsCurrentLineFloater) {
|
|
|
|
// Record this floater in the current-line list
|
|
|
|
mCurrentLineFloaters.Append(fc);
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Because we are in the middle of reflowing a placeholder frame
|
|
|
|
// within a line (and possibly nested in an inline frame or two
|
|
|
|
// that's a child of our block) we need to restore the space
|
|
|
|
// manager's translation to the space that the block resides in
|
|
|
|
// before placing the floater.
|
|
|
|
nscoord ox, oy;
|
|
|
|
mSpaceManager->GetTranslation(ox, oy);
|
|
|
|
nscoord dx = ox - mSpaceManagerX;
|
|
|
|
nscoord dy = oy - mSpaceManagerY;
|
|
|
|
mSpaceManager->Translate(-dx, -dy);
|
1999-09-10 18:52:56 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Reflow the floater
|
|
|
|
mBlock->ReflowFloater(*this, aPlaceholder, fc->mCombinedArea,
|
|
|
|
fc->mMargins, fc->mOffsets);
|
1999-09-10 18:52:56 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// And then place it
|
1999-09-10 18:52:56 +00:00
|
|
|
PRBool isLeftFloater;
|
1999-10-14 23:10:03 +00:00
|
|
|
PlaceFloater(fc, &isLeftFloater);
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Pass on updated available space to the current inline reflow engine
|
|
|
|
GetAvailableSpace();
|
1999-08-27 21:45:37 +00:00
|
|
|
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
2000-04-17 14:40:46 +00:00
|
|
|
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
1999-08-27 21:45:37 +00:00
|
|
|
mAvailSpaceRect.height,
|
1999-10-29 14:34:53 +00:00
|
|
|
isLeftFloater,
|
|
|
|
aPlaceholder->GetOutOfFlowFrame());
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Restore coordinate system
|
|
|
|
mSpaceManager->Translate(dx, dy);
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
// This floater will be placed after the line is done (it is a
|
1999-09-15 00:28:10 +00:00
|
|
|
// below-current-line floater).
|
|
|
|
mBelowCurrentLineFloaters.Append(fc);
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-25 16:33:10 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockReflowState::IsLeftMostChild(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
nsIFrame* parent;
|
1999-02-10 01:36:30 +00:00
|
|
|
aFrame->GetParent(&parent);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (parent == mBlock) {
|
|
|
|
nsIFrame* child = mCurrentLine->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = mCurrentLine->GetChildCount();
|
1998-12-05 16:02:08 +00:00
|
|
|
while ((nsnull != child) && (aFrame != child) && (--n >= 0)) {
|
|
|
|
nsSize size;
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Is the child zero-sized?
|
|
|
|
child->GetSize(size);
|
|
|
|
if (size.width > 0) {
|
|
|
|
// We found a non-zero sized child frame that precedes aFrame
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-02-10 06:13:38 +00:00
|
|
|
child->GetNextSibling(&child);
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
break;
|
1998-06-30 20:14:04 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
else {
|
|
|
|
// See if there are any non-zero sized child frames that precede
|
|
|
|
// aFrame in the child list
|
|
|
|
nsIFrame* child;
|
2000-01-22 01:16:50 +00:00
|
|
|
parent->FirstChild(aPresContext, nsnull, &child);
|
1998-12-05 16:02:08 +00:00
|
|
|
while ((nsnull != child) && (aFrame != child)) {
|
|
|
|
nsSize size;
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Is the child zero-sized?
|
|
|
|
child->GetSize(size);
|
|
|
|
if (size.width > 0) {
|
|
|
|
// We found a non-zero sized child frame that precedes aFrame
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
1999-02-10 06:13:38 +00:00
|
|
|
child->GetNextSibling(&child);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// aFrame is the left-most non-zero sized frame in its geometric parent.
|
|
|
|
// Walk up one level and check that its parent is left-most as well
|
|
|
|
aFrame = parent;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
return PR_TRUE;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1999-03-31 04:10:27 +00:00
|
|
|
PRBool
|
|
|
|
nsBlockReflowState::CanPlaceFloater(const nsRect& aFloaterRect,
|
|
|
|
PRUint8 aFloats)
|
|
|
|
{
|
|
|
|
// If the current Y coordinate is not impacted by any floaters
|
|
|
|
// then by definition the floater fits.
|
|
|
|
PRBool result = PR_TRUE;
|
1999-04-03 18:59:01 +00:00
|
|
|
if (0 != mBand.GetFloaterCount()) {
|
1999-03-31 04:10:27 +00:00
|
|
|
if (mAvailSpaceRect.width < aFloaterRect.width) {
|
|
|
|
// The available width is too narrow (and its been impacted by a
|
|
|
|
// prior floater)
|
|
|
|
result = PR_FALSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// At this point we know that there is enough horizontal space for
|
|
|
|
// the floater (somewhere). Lets see if there is enough vertical
|
|
|
|
// space.
|
|
|
|
if (mAvailSpaceRect.height < aFloaterRect.height) {
|
|
|
|
// The available height is too short. However, its possible that
|
|
|
|
// there is enough open space below which is not impacted by a
|
|
|
|
// floater.
|
|
|
|
//
|
|
|
|
// Compute the X coordinate for the floater based on its float
|
|
|
|
// type, assuming its placed on the current line. This is
|
|
|
|
// where the floater will be placed horizontally if it can go
|
|
|
|
// here.
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord xa;
|
1999-03-31 04:10:27 +00:00
|
|
|
if (NS_STYLE_FLOAT_LEFT == aFloats) {
|
1999-05-13 00:55:38 +00:00
|
|
|
xa = mAvailSpaceRect.x;
|
1999-03-31 04:10:27 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-05-13 00:55:38 +00:00
|
|
|
xa = mAvailSpaceRect.XMost() - aFloaterRect.width;
|
1999-03-31 04:10:27 +00:00
|
|
|
|
|
|
|
// In case the floater is too big, don't go past the left edge
|
1999-05-13 00:55:38 +00:00
|
|
|
if (xa < mAvailSpaceRect.x) {
|
|
|
|
xa = mAvailSpaceRect.x;
|
1999-03-31 04:10:27 +00:00
|
|
|
}
|
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord xb = xa + aFloaterRect.width;
|
1999-03-31 04:10:27 +00:00
|
|
|
|
|
|
|
// Calculate the top and bottom y coordinates, again assuming
|
|
|
|
// that the floater is placed on the current line.
|
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord ya = mY - borderPadding.top;
|
|
|
|
if (ya < 0) {
|
1999-03-31 04:10:27 +00:00
|
|
|
// CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not
|
|
|
|
// be higher than the top of its containing block.
|
|
|
|
|
|
|
|
// XXX It's not clear if it means the higher than the outer edge
|
|
|
|
// or the border edge or the inner edge?
|
1999-05-13 00:55:38 +00:00
|
|
|
ya = 0;
|
1999-03-31 04:10:27 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord yb = ya + aFloaterRect.height;
|
1999-03-31 04:10:27 +00:00
|
|
|
|
|
|
|
nscoord saveY = mY;
|
|
|
|
for (;;) {
|
|
|
|
// Get the available space at the new Y coordinate
|
|
|
|
mY += mAvailSpaceRect.height;
|
|
|
|
GetAvailableSpace();
|
|
|
|
|
1999-04-03 18:59:01 +00:00
|
|
|
if (0 == mBand.GetFloaterCount()) {
|
1999-03-31 04:10:27 +00:00
|
|
|
// Winner. This band has no floaters on it, therefore
|
|
|
|
// there can be no overlap.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check and make sure the floater won't intersect any
|
|
|
|
// floaters on this band. The floaters starting and ending
|
|
|
|
// coordinates must be entirely in the available space.
|
1999-05-13 00:55:38 +00:00
|
|
|
if ((xa < mAvailSpaceRect.x) || (xb > mAvailSpaceRect.XMost())) {
|
1999-03-31 04:10:27 +00:00
|
|
|
// The floater can't go here.
|
|
|
|
result = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if there is now enough height for the floater.
|
1999-05-13 00:55:38 +00:00
|
|
|
if (yb < mY + mAvailSpaceRect.height) {
|
1999-03-31 04:10:27 +00:00
|
|
|
// Winner. The bottom Y coordinate of the floater is in
|
|
|
|
// this band.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore Y coordinate and available space information
|
|
|
|
// regardless of the outcome.
|
|
|
|
mY = saveY;
|
|
|
|
GetAvailableSpace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-09-15 00:28:10 +00:00
|
|
|
nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
1999-10-14 23:10:03 +00:00
|
|
|
PRBool* aIsLeftFloater)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-12-12 19:19:11 +00:00
|
|
|
// Save away the Y coordinate before placing the floater. We will
|
|
|
|
// restore mY at the end after placing the floater. This is
|
|
|
|
// necessary because any adjustments to mY during the floater
|
|
|
|
// placement are for the floater only, not for any non-floating
|
|
|
|
// content.
|
|
|
|
nscoord saveY = mY;
|
1999-09-15 00:28:10 +00:00
|
|
|
nsIFrame* floater = aFloaterCache->mPlaceholder->GetOutOfFlowFrame();
|
1998-07-29 04:03:12 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Get the type of floater
|
|
|
|
const nsStyleDisplay* floaterDisplay;
|
2001-01-25 02:58:12 +00:00
|
|
|
const nsStyleSpacing* floaterSpacing;
|
1999-07-14 17:26:20 +00:00
|
|
|
const nsStylePosition* floaterPosition;
|
1998-12-05 16:02:08 +00:00
|
|
|
floater->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&)floaterDisplay);
|
2001-01-25 02:58:12 +00:00
|
|
|
floater->GetStyleData(eStyleStruct_Spacing,
|
|
|
|
(const nsStyleStruct*&)floaterSpacing);
|
1999-07-14 17:26:20 +00:00
|
|
|
floater->GetStyleData(eStyleStruct_Position,
|
|
|
|
(const nsStyleStruct*&)floaterPosition);
|
1998-12-05 16:02:08 +00:00
|
|
|
|
|
|
|
// See if the floater should clear any preceeding floaters...
|
|
|
|
if (NS_STYLE_CLEAR_NONE != floaterDisplay->mBreakType) {
|
|
|
|
ClearFloaters(mY, floaterDisplay->mBreakType);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Get the band of available space
|
|
|
|
GetAvailableSpace();
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1998-08-04 21:18:16 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Get the floaters bounding box and margin information
|
|
|
|
nsRect region;
|
|
|
|
floater->GetRect(region);
|
1999-03-31 04:10:27 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Adjust the floater size by its margin. That's the area that will
|
|
|
|
// impact the space manager.
|
1999-09-15 00:28:10 +00:00
|
|
|
region.width += aFloaterCache->mMargins.left + aFloaterCache->mMargins.right;
|
|
|
|
region.height += aFloaterCache->mMargins.top + aFloaterCache->mMargins.bottom;
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Find a place to place the floater. The CSS2 spec doesn't want
|
|
|
|
// floaters overlapping each other or sticking out of the containing
|
1999-03-31 04:10:27 +00:00
|
|
|
// block if possible (CSS2 spec section 9.5.1, see the rule list).
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) ||
|
|
|
|
(NS_STYLE_FLOAT_RIGHT == floaterDisplay->mFloats),
|
|
|
|
"invalid float type");
|
|
|
|
|
1999-03-31 04:10:27 +00:00
|
|
|
// While there is not enough room for the floater, clear past other
|
|
|
|
// floaters until there is room (or the band is not impacted by a
|
|
|
|
// floater).
|
|
|
|
//
|
|
|
|
// Note: The CSS2 spec says that floaters should be placed as high
|
|
|
|
// as possible.
|
2000-06-11 22:14:33 +00:00
|
|
|
//
|
|
|
|
#ifdef FIX_BUG_37657
|
|
|
|
// Also note that in backwards compatibility mode, we skip this step
|
2000-09-04 21:44:48 +00:00
|
|
|
// for tables, since in old browsers, floating tables are horizontally
|
|
|
|
// stacked regardless of available space. (See bug 43086 about
|
|
|
|
// tables vs. non-tables.)
|
2000-06-11 22:14:33 +00:00
|
|
|
nsCompatibility mode;
|
|
|
|
mPresContext->GetCompatibilityMode(&mode);
|
2000-09-04 21:44:48 +00:00
|
|
|
if ((eCompatibility_NavQuirks != mode) ||
|
|
|
|
(NS_STYLE_DISPLAY_TABLE != floaterDisplay->mDisplay)) {
|
2000-06-11 22:14:33 +00:00
|
|
|
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
|
|
|
|
mY += mAvailSpaceRect.height;
|
|
|
|
GetAvailableSpace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
1999-03-31 04:10:27 +00:00
|
|
|
while (!CanPlaceFloater(region, floaterDisplay->mFloats)) {
|
1998-12-08 21:43:15 +00:00
|
|
|
mY += mAvailSpaceRect.height;
|
1998-12-05 16:02:08 +00:00
|
|
|
GetAvailableSpace();
|
|
|
|
}
|
2000-06-11 22:14:33 +00:00
|
|
|
#endif
|
1998-11-14 21:01:26 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Assign an x and y coordinate to the floater. Note that the x,y
|
|
|
|
// coordinates are computed <b>relative to the translation in the
|
|
|
|
// spacemanager</b> which means that the impacted region will be
|
|
|
|
// <b>inside</b> the border/padding area.
|
1999-09-17 23:16:43 +00:00
|
|
|
PRBool okToAddRectRegion = PR_TRUE;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRBool isLeftFloater;
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_STYLE_FLOAT_LEFT == floaterDisplay->mFloats) {
|
1999-10-14 23:10:03 +00:00
|
|
|
isLeftFloater = PR_TRUE;
|
1998-12-08 21:43:15 +00:00
|
|
|
region.x = mAvailSpaceRect.x;
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-10-14 23:10:03 +00:00
|
|
|
isLeftFloater = PR_FALSE;
|
2000-04-17 14:40:46 +00:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
|
|
|
region.x = mAvailSpaceRect.XMost() - region.width;
|
|
|
|
else {
|
|
|
|
okToAddRectRegion = PR_FALSE;
|
|
|
|
region.x = mAvailSpaceRect.x;
|
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
*aIsLeftFloater = isLeftFloater;
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
|
|
|
region.y = mY - borderPadding.top;
|
1998-12-05 16:02:08 +00:00
|
|
|
if (region.y < 0) {
|
|
|
|
// CSS2 spec, 9.5.1 rule [4]: A floating box's outer top may not
|
|
|
|
// be higher than the top of its containing block.
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX It's not clear if it means the higher than the outer edge
|
|
|
|
// or the border edge or the inner edge?
|
|
|
|
region.y = 0;
|
1998-06-27 22:56:09 +00:00
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Place the floater in the space manager
|
1999-09-17 23:16:43 +00:00
|
|
|
if (okToAddRectRegion) {
|
1999-10-29 14:34:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult rv =
|
|
|
|
#endif
|
2000-01-03 04:32:13 +00:00
|
|
|
mSpaceManager->AddRectRegion(floater, region);
|
1999-10-29 14:34:53 +00:00
|
|
|
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad floater placement");
|
1999-09-17 23:16:43 +00:00
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Save away the floaters region in the spacemanager, after making
|
|
|
|
// it relative to the containing block's frame instead of relative
|
|
|
|
// to the spacemanager translation (which is inset by the
|
|
|
|
// border+padding).
|
|
|
|
aFloaterCache->mRegion.x = region.x + borderPadding.left;
|
|
|
|
aFloaterCache->mRegion.y = region.y + borderPadding.top;
|
|
|
|
aFloaterCache->mRegion.width = region.width;
|
|
|
|
aFloaterCache->mRegion.height = region.height;
|
|
|
|
#ifdef NOISY_SPACEMANAGER
|
|
|
|
nscoord tx, ty;
|
|
|
|
mSpaceManager->GetTranslation(tx, ty);
|
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": PlaceFloater: AddRectRegion: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
|
1999-09-15 00:28:10 +00:00
|
|
|
tx, ty, mSpaceManagerX, mSpaceManagerY,
|
1999-09-16 19:56:36 +00:00
|
|
|
aFloaterCache->mRegion.x, aFloaterCache->mRegion.y,
|
|
|
|
aFloaterCache->mRegion.width, aFloaterCache->mRegion.height);
|
1999-09-15 00:28:10 +00:00
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Set the origin of the floater frame, in frame coordinates. These
|
|
|
|
// coordinates are <b>not</b> relative to the spacemanager
|
|
|
|
// translation, therefore we have to factor in our border/padding.
|
1999-09-15 00:28:10 +00:00
|
|
|
nscoord x = borderPadding.left + aFloaterCache->mMargins.left + region.x;
|
|
|
|
nscoord y = borderPadding.top + aFloaterCache->mMargins.top + region.y;
|
1999-07-14 17:26:20 +00:00
|
|
|
|
|
|
|
// If floater is relatively positioned, factor that in as well
|
|
|
|
if (NS_STYLE_POSITION_RELATIVE == floaterPosition->mPosition) {
|
1999-09-15 00:28:10 +00:00
|
|
|
x += aFloaterCache->mOffsets.left;
|
|
|
|
y += aFloaterCache->mOffsets.top;
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
1999-11-30 05:09:08 +00:00
|
|
|
|
|
|
|
// Position the floater and make sure and views are properly positioned
|
|
|
|
nsIView* view;
|
1999-10-26 04:44:41 +00:00
|
|
|
floater->MoveTo(mPresContext, x, y);
|
1999-11-30 05:09:08 +00:00
|
|
|
floater->GetView(mPresContext, &view);
|
|
|
|
if (view) {
|
|
|
|
nsContainerFrame::PositionFrameView(mPresContext, floater, view);
|
|
|
|
} else {
|
|
|
|
nsContainerFrame::PositionChildViews(mPresContext, floater);
|
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
|
|
|
|
// Update the floater combined area state
|
|
|
|
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
|
|
|
combinedArea.x += x;
|
|
|
|
combinedArea.y += y;
|
2000-04-17 14:40:46 +00:00
|
|
|
if (!isLeftFloater &&
|
|
|
|
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
2000-01-03 04:32:13 +00:00
|
|
|
// When we are placing a right floater in an unconstrained situation or
|
|
|
|
// when shrink wrapping, we don't apply it to the floater combined area
|
|
|
|
// immediately. Otherwise we end up with an infinitely wide combined
|
|
|
|
// area. Instead, we save it away in mRightFloaterCombinedArea so that
|
|
|
|
// later on when we know the width of a line we can compute a better value.
|
1999-10-14 23:10:03 +00:00
|
|
|
if (!mHaveRightFloaters) {
|
|
|
|
mRightFloaterCombinedArea = combinedArea;
|
|
|
|
mHaveRightFloaters = PR_TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CombineRects(combinedArea, mRightFloaterCombinedArea);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CombineRects(combinedArea, mFloaterCombinedArea);
|
1999-03-24 15:42:19 +00:00
|
|
|
}
|
1998-12-12 19:19:11 +00:00
|
|
|
|
|
|
|
// Now restore mY
|
|
|
|
mY = saveY;
|
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
1998-12-05 16:02:08 +00:00
|
|
|
nsRect r;
|
|
|
|
floater->GetRect(r);
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("placed floater: ");
|
1998-12-05 16:02:08 +00:00
|
|
|
((nsFrame*)floater)->ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-11-05 19:33:01 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
/**
|
|
|
|
* Place below-current-line floaters.
|
|
|
|
*/
|
|
|
|
void
|
1999-09-15 00:28:10 +00:00
|
|
|
nsBlockReflowState::PlaceBelowCurrentLineFloaters(nsFloaterCacheList& aList)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-09-15 00:28:10 +00:00
|
|
|
nsFloaterCache* fc = aList.Head();
|
|
|
|
while (fc) {
|
|
|
|
if (!fc->mIsCurrentLineFloater) {
|
1999-10-29 14:34:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("placing bcl floater: ");
|
1999-10-29 14:34:53 +00:00
|
|
|
nsFrame::ListTag(stdout, fc->mPlaceholder->GetOutOfFlowFrame());
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("\n");
|
1999-10-29 14:34:53 +00:00
|
|
|
}
|
|
|
|
#endif
|
1999-09-15 00:28:10 +00:00
|
|
|
mBlock->ReflowFloater(*this, fc->mPlaceholder, fc->mCombinedArea,
|
|
|
|
fc->mMargins, fc->mOffsets);
|
1999-03-23 04:28:20 +00:00
|
|
|
|
1999-09-15 00:28:10 +00:00
|
|
|
// Place the floater
|
1999-04-01 01:37:36 +00:00
|
|
|
PRBool isLeftFloater;
|
1999-10-14 23:10:03 +00:00
|
|
|
PlaceFloater(fc, &isLeftFloater);
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
fc = fc->Next();
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
|
|
|
nsBlockReflowState::ClearFloaters(nscoord aY, PRUint8 aBreakType)
|
1998-10-27 16:51:02 +00:00
|
|
|
{
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("clear floaters: in: mY=%d aY=%d(%d)\n",
|
1999-10-15 23:35:10 +00:00
|
|
|
mY, aY, aY - BorderPadding().top);
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
1998-10-27 16:51:02 +00:00
|
|
|
|
1999-09-16 19:56:36 +00:00
|
|
|
#ifdef NOISY_FLOATER_CLEARING
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("nsBlockReflowState::ClearFloaters: aY=%d breakType=%dn",
|
1999-09-16 19:56:36 +00:00
|
|
|
aY, aBreakType);
|
|
|
|
mSpaceManager->List(stdout);
|
|
|
|
#endif
|
1999-03-05 04:21:32 +00:00
|
|
|
const nsMargin& bp = BorderPadding();
|
1999-04-03 18:59:01 +00:00
|
|
|
nscoord newY = mBand.ClearFloaters(aY - bp.top, aBreakType);
|
1999-03-05 04:21:32 +00:00
|
|
|
mY = newY + bp.top;
|
1998-12-05 16:02:08 +00:00
|
|
|
GetAvailableSpace();
|
1998-09-23 02:25:26 +00:00
|
|
|
|
1999-10-15 23:35:10 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("clear floaters: out: mY=%d(%d)\n", mY, mY - bp.top);
|
1999-10-15 23:35:10 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
#endif
|
|
|
|
}
|
1998-10-27 16:51:02 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Painting, event handling
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRIntn
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::GetSkipSides() const
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
PRIntn skip = 0;
|
|
|
|
if (nsnull != mPrevInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_TOP;
|
1998-09-29 22:32:56 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_BOTTOM;
|
1998-11-11 03:55:55 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return skip;
|
|
|
|
}
|
1998-09-29 22:32:56 +00:00
|
|
|
|
1999-10-19 23:04:19 +00:00
|
|
|
#ifdef DEBUG
|
1999-03-22 22:42:30 +00:00
|
|
|
static void ComputeCombinedArea(nsLineBox* aLine,
|
|
|
|
nscoord aWidth, nscoord aHeight,
|
|
|
|
nsRect& aResult)
|
|
|
|
{
|
1999-05-13 00:55:38 +00:00
|
|
|
nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight;
|
1999-03-22 22:42:30 +00:00
|
|
|
while (nsnull != aLine) {
|
|
|
|
// Compute min and max x/y values for the reflowed frame's
|
|
|
|
// combined areas
|
1999-10-19 23:04:19 +00:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
nscoord x = lineCombinedArea.x;
|
|
|
|
nscoord y = lineCombinedArea.y;
|
|
|
|
nscoord xmost = x + lineCombinedArea.width;
|
|
|
|
nscoord ymost = y + lineCombinedArea.height;
|
1999-05-13 00:55:38 +00:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
1999-05-13 00:55:38 +00:00
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
|
|
|
aLine = aLine->mNext;
|
|
|
|
}
|
|
|
|
|
1999-05-13 00:55:38 +00:00
|
|
|
aResult.x = xa;
|
|
|
|
aResult.y = ya;
|
|
|
|
aResult.width = xb - xa;
|
|
|
|
aResult.height = yb - ya;
|
1999-03-22 22:42:30 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::Paint(nsIPresContext* aPresContext,
|
1999-03-26 00:39:04 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsFramePaintLayer aWhichLayer)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-08-27 21:45:37 +00:00
|
|
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-10-19 23:04:19 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyDamageRepair) {
|
|
|
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
|
|
|
PRInt32 depth = GetDepth();
|
|
|
|
nsRect ca;
|
|
|
|
ComputeCombinedArea(mLines, mRect.width, mRect.height, ca);
|
|
|
|
nsFrame::IndentBy(stdout, depth);
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
1999-10-19 23:04:19 +00:00
|
|
|
mRect.x, mRect.y, mRect.width, mRect.height,
|
|
|
|
aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height,
|
|
|
|
ca.x, ca.y, ca.width, ca.height);
|
|
|
|
}
|
1999-03-22 20:46:09 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-01-27 14:09:34 +00:00
|
|
|
// Check to see if we are an absolutely positioned block (div)
|
|
|
|
// then then check to see if we need to paint.
|
|
|
|
const nsStylePosition* postionStyle = (const nsStylePosition*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Position);
|
|
|
|
if (NS_STYLE_POSITION_RELATIVE == postionStyle->mPosition ||
|
|
|
|
NS_STYLE_POSITION_ABSOLUTE == postionStyle->mPosition ||
|
|
|
|
NS_STYLE_POSITION_FIXED == postionStyle->mPosition) {
|
|
|
|
PRBool isVisible;
|
|
|
|
if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && !isVisible) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
const nsStyleDisplay* disp = (const nsStyleDisplay*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Display);
|
1998-09-23 02:25:26 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Only paint the border and background if we're visible
|
2000-03-17 10:15:13 +00:00
|
|
|
if (disp->IsVisible() && (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) &&
|
1999-03-19 23:05:56 +00:00
|
|
|
(0 != mRect.width) && (0 != mRect.height)) {
|
1998-12-05 16:02:08 +00:00
|
|
|
PRIntn skipSides = GetSkipSides();
|
|
|
|
const nsStyleColor* color = (const nsStyleColor*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Color);
|
2001-01-25 02:58:12 +00:00
|
|
|
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Spacing);
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-10-19 23:04:19 +00:00
|
|
|
// Paint background, border and outline
|
1998-12-05 16:02:08 +00:00
|
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
|
2001-01-25 02:58:12 +00:00
|
|
|
aDirtyRect, rect, *color, *spacing, 0, 0);
|
1998-12-05 16:02:08 +00:00
|
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
|
2001-01-25 02:58:12 +00:00
|
|
|
aDirtyRect, rect, *spacing, mStyleContext,
|
1999-02-09 17:31:33 +00:00
|
|
|
skipSides);
|
1999-10-19 23:04:19 +00:00
|
|
|
nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
|
2001-01-25 02:58:12 +00:00
|
|
|
aDirtyRect, rect, *spacing, mStyleContext, 0);
|
1998-10-30 22:10:10 +00:00
|
|
|
}
|
|
|
|
|
2000-04-25 04:43:11 +00:00
|
|
|
// If overflow is hidden then set the clip rect so that children don't
|
|
|
|
// leak out of us. Note that because overflow'-clip' only applies to
|
|
|
|
// the content area we do this after painting the border and background
|
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) {
|
|
|
|
aRenderingContext.PushState();
|
|
|
|
SetOverflowClipRect(aRenderingContext);
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Child elements have the opportunity to override the visibility
|
|
|
|
// property and display even if the parent is hidden
|
1999-03-26 00:39:04 +00:00
|
|
|
if (NS_FRAME_PAINT_LAYER_FLOATERS == aWhichLayer) {
|
|
|
|
PaintFloaters(aPresContext, aRenderingContext, aDirtyRect);
|
|
|
|
}
|
1998-12-18 15:54:23 +00:00
|
|
|
PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
|
1998-10-02 21:50:53 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) {
|
|
|
|
PRBool clipState;
|
|
|
|
aRenderingContext.PopState(clipState);
|
1998-07-09 17:06:35 +00:00
|
|
|
}
|
1998-12-18 15:54:23 +00:00
|
|
|
|
1999-10-08 04:45:12 +00:00
|
|
|
#if 0
|
|
|
|
if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
|
|
|
|
// Render the bands in the spacemanager
|
|
|
|
nsISpaceManager* sm = mSpaceManager;
|
|
|
|
|
|
|
|
if (nsnull != sm) {
|
|
|
|
nsBlockBandData band;
|
|
|
|
band.Init(sm, nsSize(mRect.width, mRect.height));
|
|
|
|
nscoord y = 0;
|
|
|
|
while (y < mRect.height) {
|
|
|
|
nsRect availArea;
|
|
|
|
band.GetAvailableSpace(y, availArea);
|
|
|
|
|
|
|
|
// Render a box and a diagonal line through the band
|
|
|
|
aRenderingContext.SetColor(NS_RGB(0,255,0));
|
|
|
|
aRenderingContext.DrawRect(0, availArea.y,
|
|
|
|
mRect.width, availArea.height);
|
|
|
|
aRenderingContext.DrawLine(0, availArea.y,
|
|
|
|
mRect.width, availArea.YMost());
|
|
|
|
|
|
|
|
// Render boxes and opposite diagonal lines around the
|
|
|
|
// unavailable parts of the band.
|
|
|
|
PRInt32 i;
|
|
|
|
for (i = 0; i < band.GetTrapezoidCount(); i++) {
|
|
|
|
const nsBandTrapezoid* trapezoid = band.GetTrapezoid(i);
|
|
|
|
if (nsBandTrapezoid::Available != trapezoid->mState) {
|
|
|
|
nsRect r;
|
|
|
|
trapezoid->GetRect(r);
|
|
|
|
if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) {
|
|
|
|
aRenderingContext.SetColor(NS_RGB(0,255,128));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aRenderingContext.SetColor(NS_RGB(128,255,0));
|
|
|
|
}
|
|
|
|
aRenderingContext.DrawRect(r);
|
|
|
|
aRenderingContext.DrawLine(r.x, r.YMost(), r.XMost(), r.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
y = availArea.YMost();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-07-09 17:06:35 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::PaintFloaters(nsIPresContext* aPresContext,
|
1999-03-26 00:39:04 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
|
|
|
for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (!line->HasFloaters()) {
|
1998-12-05 16:02:08 +00:00
|
|
|
continue;
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 00:28:10 +00:00
|
|
|
while (fc) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
1998-12-05 16:02:08 +00:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 00:28:10 +00:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_BACKGROUND);
|
1999-03-26 00:39:04 +00:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 00:28:10 +00:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_FLOATERS);
|
1999-03-26 00:39:04 +00:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 00:28:10 +00:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_FOREGROUND);
|
|
|
|
fc = fc->Next();
|
1998-06-25 16:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-25 16:33:10 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::PaintChildren(nsIPresContext* aPresContext,
|
1999-03-22 20:46:09 +00:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsFramePaintLayer aWhichLayer)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-10-19 23:04:19 +00:00
|
|
|
#ifdef DEBUG
|
1999-03-22 20:46:09 +00:00
|
|
|
PRInt32 depth = 0;
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gNoisyDamageRepair) {
|
|
|
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
|
|
|
depth = GetDepth();
|
|
|
|
}
|
|
|
|
}
|
2000-11-27 23:23:28 +00:00
|
|
|
PRTime start = LL_ZERO; // Initialize these variables to silence the compiler.
|
|
|
|
PRInt32 drawnLines = 0; // They will only be used if set (gLamePaintMetrics).
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
start = PR_Now();
|
|
|
|
drawnLines = 0;
|
1999-03-22 20:46:09 +00:00
|
|
|
}
|
|
|
|
#endif
|
1999-10-19 23:04:19 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) {
|
1999-10-19 23:04:19 +00:00
|
|
|
// If the line's combined area (which includes child frames that
|
|
|
|
// stick outside of the line's bounding box or our bounding box)
|
|
|
|
// intersects the dirty rect then paint the line.
|
|
|
|
if (line->CombinedAreaIntersects(aDirtyRect)) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyDamageRepair &&
|
|
|
|
(NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
|
|
|
|
nsRect lineCombinedArea;
|
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
1999-03-22 20:46:09 +00:00
|
|
|
nsFrame::IndentBy(stdout, depth+1);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("draw line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
1999-03-22 20:46:09 +00:00
|
|
|
line, line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
1999-03-22 20:46:09 +00:00
|
|
|
}
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
drawnLines++;
|
|
|
|
}
|
1999-03-22 20:46:09 +00:00
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* kid = line->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1998-12-05 16:02:08 +00:00
|
|
|
while (--n >= 0) {
|
1998-12-18 15:54:23 +00:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid,
|
|
|
|
aWhichLayer);
|
1999-02-10 06:13:38 +00:00
|
|
|
kid->GetNextSibling(&kid);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-19 23:04:19 +00:00
|
|
|
#ifdef DEBUG
|
1999-03-22 20:46:09 +00:00
|
|
|
else {
|
1999-10-19 23:04:19 +00:00
|
|
|
if (gNoisyDamageRepair &&
|
|
|
|
(NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
|
|
|
|
nsRect lineCombinedArea;
|
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
1999-03-22 20:46:09 +00:00
|
|
|
nsFrame::IndentBy(stdout, depth+1);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("skip line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
1999-03-22 20:46:09 +00:00
|
|
|
line, line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
1999-10-14 23:10:03 +00:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
1999-03-22 20:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
1999-02-09 17:31:33 +00:00
|
|
|
|
1999-03-26 00:39:04 +00:00
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
|
1999-02-18 22:22:55 +00:00
|
|
|
if ((nsnull != mBullet) && HaveOutsideBullet()) {
|
1999-02-09 17:31:33 +00:00
|
|
|
// Paint outside bullets manually
|
1999-02-18 22:22:55 +00:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect, mBullet,
|
|
|
|
aWhichLayer);
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-19 23:04:19 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
PRTime end = PR_Now();
|
|
|
|
|
|
|
|
PRInt32 numLines = nsLineBox::ListLength(mLines);
|
|
|
|
if (!numLines) numLines = 1;
|
|
|
|
PRTime lines, deltaPerLine, delta;
|
|
|
|
LL_I2L(lines, numLines);
|
|
|
|
LL_SUB(delta, end, start);
|
|
|
|
LL_DIV(deltaPerLine, delta, lines);
|
|
|
|
|
|
|
|
ListTag(stdout);
|
|
|
|
char buf[400];
|
|
|
|
PR_snprintf(buf, sizeof(buf),
|
|
|
|
": %lld elapsed (%lld per line) lines=%d drawn=%d skip=%d",
|
|
|
|
delta, deltaPerLine,
|
|
|
|
numLines, drawnLines, numLines - drawnLines);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf("%s\n", buf);
|
1999-10-19 23:04:19 +00:00
|
|
|
}
|
|
|
|
#endif
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1999-08-24 21:51:47 +00:00
|
|
|
|
1999-04-13 21:29:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::HandleEvent(nsIPresContext* aPresContext,
|
1999-04-13 21:29:08 +00:00
|
|
|
nsGUIEvent* aEvent,
|
1999-11-24 06:03:41 +00:00
|
|
|
nsEventStatus* aEventStatus)
|
1999-04-13 21:29:08 +00:00
|
|
|
{
|
2000-05-11 04:25:43 +00:00
|
|
|
|
|
|
|
nsresult result;
|
2000-05-11 04:50:16 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
1999-08-24 21:51:47 +00:00
|
|
|
if (aEvent->message == NS_MOUSE_MOVE) {
|
2000-05-11 04:50:16 +00:00
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
if (!shell)
|
|
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIFrameSelection> frameSelection;
|
2000-05-11 04:25:43 +00:00
|
|
|
PRBool mouseDown = PR_FALSE;
|
2000-05-11 04:50:16 +00:00
|
|
|
//check to see if we need to ask the selection controller..
|
|
|
|
if (mState & NS_FRAME_INDEPENDENT_SELECTION)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
|
|
|
|
if (NS_FAILED(result) || !selCon)
|
|
|
|
return result?result:NS_ERROR_FAILURE;
|
|
|
|
frameSelection = do_QueryInterface(selCon);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
shell->GetFrameSelection(getter_AddRefs(frameSelection));
|
2000-05-11 04:25:43 +00:00
|
|
|
if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown)
|
|
|
|
return NS_OK;//do not handle
|
1999-08-24 21:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE ||
|
|
|
|
aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) {
|
2000-04-13 20:21:32 +00:00
|
|
|
|
2000-09-15 07:02:05 +00:00
|
|
|
nsMouseEvent *me = (nsMouseEvent *)aEvent;
|
2000-04-13 20:21:32 +00:00
|
|
|
|
1999-09-01 21:40:16 +00:00
|
|
|
nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we
|
|
|
|
//can tell who to pass it to
|
1999-08-24 21:51:47 +00:00
|
|
|
nsCOMPtr<nsILineIterator> it;
|
1999-09-01 21:40:16 +00:00
|
|
|
nsIFrame *mainframe = this;
|
1999-08-24 21:51:47 +00:00
|
|
|
nsCOMPtr<nsIFocusTracker> tracker;
|
2000-05-14 04:56:25 +00:00
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
2000-05-11 08:41:35 +00:00
|
|
|
if (!shell)
|
|
|
|
return NS_OK;
|
2000-02-02 22:24:56 +00:00
|
|
|
result = shell->QueryInterface(NS_GET_IID(nsIFocusTracker),getter_AddRefs(tracker));
|
1999-09-01 21:40:16 +00:00
|
|
|
|
2000-02-02 22:24:56 +00:00
|
|
|
result = mainframe->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it));
|
1999-09-01 21:40:16 +00:00
|
|
|
nsIView* parentWithView;
|
|
|
|
nsPoint origin;
|
2000-09-15 07:02:05 +00:00
|
|
|
nsPeekOffsetStruct pos;
|
1999-09-01 21:40:16 +00:00
|
|
|
|
2000-09-15 07:02:05 +00:00
|
|
|
while(NS_OK == result)
|
1999-09-01 21:40:16 +00:00
|
|
|
{ //we are starting aloop to allow us to "drill down to the one we want"
|
1999-11-24 06:03:41 +00:00
|
|
|
mainframe->GetOffsetFromView(aPresContext, origin, &parentWithView);
|
1999-09-01 21:40:16 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
return NS_OK;//do not handle
|
|
|
|
PRInt32 countLines;
|
|
|
|
result = it->GetNumLines(&countLines);
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
return NS_OK;//do not handle
|
|
|
|
PRInt32 i;
|
|
|
|
PRInt32 lineFrameCount;
|
|
|
|
nsIFrame *firstFrame;
|
|
|
|
nsRect rect;
|
|
|
|
PRInt32 closestLine = 0;
|
|
|
|
PRInt32 closestDistance = 999999; //some HUGE number that will always fail first comparison
|
|
|
|
//incase we hit another block frame.
|
|
|
|
for (i = 0; i< countLines;i++)
|
|
|
|
{
|
1999-10-12 23:24:22 +00:00
|
|
|
PRUint32 flags;
|
|
|
|
result = it->GetLine(i, &firstFrame, &lineFrameCount,rect,&flags);
|
1999-09-01 21:40:16 +00:00
|
|
|
if (NS_FAILED(result))
|
|
|
|
continue;//do not handle
|
|
|
|
rect+=origin;
|
1999-09-08 19:43:17 +00:00
|
|
|
rect.width = aEvent->point.x - rect.x+1;//EXTEND RECT TO REACH POINT
|
1999-09-01 21:40:16 +00:00
|
|
|
if (rect.Contains(aEvent->point.x, aEvent->point.y))
|
|
|
|
{
|
|
|
|
closestLine = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PRInt32 distance = PR_MIN(abs(rect.y - aEvent->point.y),abs((rect.y + rect.height) - aEvent->point.y));
|
|
|
|
if (distance < closestDistance)
|
|
|
|
{
|
|
|
|
closestDistance = distance;
|
|
|
|
closestLine = i;
|
|
|
|
}
|
|
|
|
else if (distance > closestDistance)
|
|
|
|
break;//done
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//we will now ask where to go. if we cant find what we want"aka another block frame"
|
|
|
|
//we drill down again
|
1999-10-13 01:15:26 +00:00
|
|
|
pos.mTracker = tracker;
|
|
|
|
pos.mDirection = eDirNext;
|
|
|
|
pos.mDesiredX = aEvent->point.x;
|
|
|
|
|
1999-11-24 06:03:41 +00:00
|
|
|
result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
|
1999-10-26 04:44:41 +00:00
|
|
|
&pos,
|
1999-09-01 21:40:16 +00:00
|
|
|
mainframe,
|
|
|
|
closestLine-1,
|
1999-10-13 01:15:26 +00:00
|
|
|
0
|
1999-09-01 21:40:16 +00:00
|
|
|
);
|
1999-10-13 01:15:26 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result) && pos.mResultFrame){
|
2000-09-15 07:02:05 +00:00
|
|
|
if (result == NS_OK)
|
|
|
|
result = pos.mResultFrame->QueryInterface(NS_GET_IID(nsILineIterator),getter_AddRefs(it));//if this fails thats ok
|
1999-10-14 23:52:42 +00:00
|
|
|
resultFrame = pos.mResultFrame;
|
1999-09-01 21:40:16 +00:00
|
|
|
mainframe = resultFrame;
|
|
|
|
}
|
1999-10-14 23:52:42 +00:00
|
|
|
else
|
1999-09-02 00:04:56 +00:00
|
|
|
break;//time to go nothing was found
|
1999-08-24 21:51:47 +00:00
|
|
|
}
|
1999-09-01 21:40:16 +00:00
|
|
|
//end while loop. if nssucceeded resutl then keep going that means
|
|
|
|
//we have successfully hit another block frame and we should keep going.
|
|
|
|
|
|
|
|
|
1999-08-24 21:51:47 +00:00
|
|
|
if (resultFrame)
|
2000-05-14 03:41:25 +00:00
|
|
|
{
|
2000-09-15 07:02:05 +00:00
|
|
|
if (NS_COMFALSE == result)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
|
|
|
|
//get the selection controller
|
|
|
|
if (NS_SUCCEEDED(result) && selCon)
|
|
|
|
{
|
|
|
|
PRInt16 displayresult;
|
|
|
|
selCon->GetDisplaySelection(&displayresult);
|
|
|
|
if (displayresult == nsISelectionController::SELECTION_OFF)
|
|
|
|
return NS_OK;//nothing to do we cannot affect selection from here
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIFrameSelection> frameselection;
|
|
|
|
shell->GetFrameSelection(getter_AddRefs(frameselection));
|
|
|
|
if (frameselection)
|
|
|
|
result = frameselection->HandleClick(pos.mResultContent, pos.mContentOffset,
|
|
|
|
pos.mContentOffsetEnd, me->isShift, PR_FALSE, pos.mPreferLeft);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs
|
2000-05-14 03:41:25 +00:00
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext))
|
|
|
|
CaptureMouse(aPresContext, PR_TRUE);
|
|
|
|
return result;
|
|
|
|
}
|
1999-08-24 21:51:47 +00:00
|
|
|
else
|
2000-05-14 03:41:25 +00:00
|
|
|
{
|
|
|
|
/*we have to add this because any frame that overrides nsFrame::HandleEvent for mouse down MUST capture the mouse events!!
|
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext))
|
|
|
|
CaptureMouse(aPresContext, PR_TRUE);*/
|
1999-08-24 21:51:47 +00:00
|
|
|
return NS_OK; //just stop it
|
2000-05-14 03:41:25 +00:00
|
|
|
}
|
1999-08-24 21:51:47 +00:00
|
|
|
}
|
2000-04-12 03:04:11 +00:00
|
|
|
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
1999-04-13 21:29:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-10-26 04:44:41 +00:00
|
|
|
nsBlockFrame::GetFrameForPoint(nsIPresContext* aPresContext,
|
|
|
|
const nsPoint& aPoint,
|
2000-03-22 02:43:08 +00:00
|
|
|
nsFramePaintLayer aWhichLayer,
|
1999-10-26 04:44:41 +00:00
|
|
|
nsIFrame** aFrame)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
2000-01-18 15:17:31 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
2000-03-22 02:43:08 +00:00
|
|
|
switch (aWhichLayer) {
|
|
|
|
case NS_FRAME_PAINT_LAYER_FOREGROUND:
|
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame);
|
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (nsnull != mBullet) {
|
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::bulletList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_FRAME_PAINT_LAYER_FLOATERS:
|
|
|
|
// we painted our floaters before our children, and thus
|
|
|
|
// we should check floaters within children first
|
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame);
|
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (mFloaters.NotEmpty()) {
|
|
|
|
|
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FOREGROUND, PR_FALSE, aFrame);
|
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_FLOATERS, PR_FALSE, aFrame);
|
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetFrameForPointUsing(aPresContext, aPoint, nsLayoutAtoms::floaterList, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_FALSE, aFrame);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_FRAME_PAINT_LAYER_BACKGROUND:
|
|
|
|
// we're a block, so PR_TRUE for consider self
|
|
|
|
return GetFrameForPointUsing(aPresContext, aPoint, nsnull, NS_FRAME_PAINT_LAYER_BACKGROUND, PR_TRUE, aFrame);
|
|
|
|
break;
|
1999-02-09 17:31:33 +00:00
|
|
|
}
|
2000-03-22 02:43:08 +00:00
|
|
|
// we shouldn't get here
|
|
|
|
NS_ASSERTION(PR_FALSE, "aWhichLayer was not understood");
|
|
|
|
return NS_ERROR_FAILURE;
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
2000-01-12 08:28:24 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
|
|
|
|
{
|
2000-05-09 05:06:16 +00:00
|
|
|
if (aChild) {
|
|
|
|
// See if the child is absolutely positioned
|
|
|
|
nsFrameState childState;
|
|
|
|
aChild->GetFrameState(&childState);
|
|
|
|
if (childState & NS_FRAME_OUT_OF_FLOW) {
|
|
|
|
const nsStylePosition* position;
|
|
|
|
aChild->GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position);
|
|
|
|
|
|
|
|
if (position->IsAbsolutelyPositioned()) {
|
|
|
|
// Generate a reflow command to reflow our dirty absolutely
|
|
|
|
// positioned child frames.
|
|
|
|
// XXX Note that we don't currently try and coalesce the reflow commands,
|
|
|
|
// although we should. We can't use the NS_FRAME_HAS_DIRTY_CHILDREN
|
|
|
|
// flag, because that's used to indicate whether in-flow children are
|
|
|
|
// dirty...
|
|
|
|
nsIReflowCommand* reflowCmd;
|
|
|
|
nsresult rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
|
|
|
|
nsIReflowCommand::ReflowDirty);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
reflowCmd->SetChildListName(nsLayoutAtoms::absoluteList);
|
|
|
|
aPresShell->AppendReflowCommand(reflowCmd);
|
|
|
|
NS_RELEASE(reflowCmd);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-12 08:28:24 +00:00
|
|
|
// Mark the line containing the child frame dirty.
|
|
|
|
if (aChild) {
|
|
|
|
PRBool isFloater;
|
|
|
|
nsLineBox* prevLine;
|
|
|
|
nsLineBox* line = FindLineFor(aChild, &prevLine, &isFloater);
|
|
|
|
|
|
|
|
if (!isFloater) {
|
|
|
|
if (line) MarkLineDirty(line, prevLine);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
line = mLines;
|
|
|
|
while (nsnull != line) {
|
|
|
|
line->MarkDirty();
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Either generate a reflow command to reflow the dirty child or
|
|
|
|
// coalesce this reflow request with an existing reflow command
|
|
|
|
if (!(mState & NS_FRAME_HAS_DIRTY_CHILDREN)) {
|
|
|
|
// If this is the first dirty child,
|
|
|
|
// post a dirty children reflow command targeted at yourself
|
|
|
|
mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
|
|
|
|
|
|
|
|
nsFrame::CreateAndPostReflowCommand(aPresShell, this,
|
|
|
|
nsIReflowCommand::ReflowDirty, nsnull, nsnull, nsnull);
|
|
|
|
}
|
|
|
|
else {
|
2000-01-12 21:52:58 +00:00
|
|
|
if (!(mState & NS_FRAME_IS_DIRTY)) {
|
|
|
|
// Mark yourself as dirty
|
|
|
|
mState |= NS_FRAME_IS_DIRTY;
|
2000-01-12 08:28:24 +00:00
|
|
|
|
2000-01-12 21:52:58 +00:00
|
|
|
// Cancel the dirty children reflow command you posted earlier
|
|
|
|
nsIReflowCommand::ReflowType type = nsIReflowCommand::ReflowDirty;
|
|
|
|
aPresShell->CancelReflowCommand(this, &type);
|
2000-01-12 08:28:24 +00:00
|
|
|
|
2000-01-12 21:52:58 +00:00
|
|
|
// Pass up the reflow request to the parent frame.
|
|
|
|
mParent->ReflowDirtyChild(aPresShell, this);
|
2000-01-12 08:28:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Debugging
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
static PRBool
|
|
|
|
InLineList(nsLineBox* aLines, nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
while (nsnull != aLines) {
|
|
|
|
nsIFrame* frame = aLines->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = aLines->GetChildCount();
|
1998-12-05 16:02:08 +00:00
|
|
|
while (--n >= 0) {
|
|
|
|
if (frame == aFrame) {
|
|
|
|
return PR_TRUE;
|
1998-11-05 19:33:01 +00:00
|
|
|
}
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-07-16 23:30:49 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
aLines = aLines->mNext;
|
1998-07-16 23:30:49 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return PR_FALSE;
|
1998-06-18 16:25:41 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
static PRBool
|
|
|
|
InSiblingList(nsLineBox* aLine, nsIFrame* aFrame)
|
1998-11-12 18:19:22 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull != aLine) {
|
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
|
|
|
while (nsnull != frame) {
|
|
|
|
if (frame == aFrame) {
|
|
|
|
return PR_TRUE;
|
1998-11-12 18:19:22 +00:00
|
|
|
}
|
1999-02-10 06:13:38 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-11-12 18:19:22 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
return PR_FALSE;
|
1998-11-12 18:19:22 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
PRBool
|
1999-11-02 23:42:52 +00:00
|
|
|
nsBlockFrame::IsChild(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
1998-11-12 18:19:22 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
nsIFrame* parent;
|
1999-02-10 01:36:30 +00:00
|
|
|
aFrame->GetParent(&parent);
|
1998-12-05 16:02:08 +00:00
|
|
|
if (parent != (nsIFrame*)this) {
|
|
|
|
return PR_FALSE;
|
1998-11-12 18:19:22 +00:00
|
|
|
}
|
1998-12-05 16:02:08 +00:00
|
|
|
if (InLineList(mLines, aFrame) && InSiblingList(mLines, aFrame)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-11-02 23:42:52 +00:00
|
|
|
nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
|
|
|
if (InLineList(overflowLines, aFrame) && InSiblingList(overflowLines, aFrame)) {
|
1998-12-05 16:02:08 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
1998-11-12 18:19:22 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-02-09 17:31:33 +00:00
|
|
|
nsBlockFrame::VerifyTree() const
|
1998-07-18 21:45:17 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX rewrite this
|
1998-07-18 21:45:17 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-31 03:09:40 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
|
|
|
|
{
|
1999-08-31 04:32:13 +00:00
|
|
|
if (!aHandler || !aResult) {
|
1999-08-31 03:09:40 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 sum = sizeof(*this);
|
|
|
|
|
|
|
|
// Add in size of each line object
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (line) {
|
1999-10-02 02:51:03 +00:00
|
|
|
PRUint32 lineBoxSize;
|
1999-10-14 23:10:03 +00:00
|
|
|
nsIAtom* atom = line->SizeOf(aHandler, &lineBoxSize);
|
|
|
|
aHandler->AddSize(atom, lineBoxSize);
|
1999-08-31 03:09:40 +00:00
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aResult = sum;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-09-01 01:02:16 +00:00
|
|
|
#endif
|
1999-08-31 03:09:40 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
//----------------------------------------------------------------------
|
1998-07-18 21:45:17 +00:00
|
|
|
|
1999-02-25 05:31:15 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::Init(nsIPresContext* aPresContext,
|
1999-02-25 05:31:15 +00:00
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aContext,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
|
|
|
if (aPrevInFlow) {
|
1999-11-03 00:42:12 +00:00
|
|
|
// Copy over the block/area frame type flags
|
1999-02-25 05:31:15 +00:00
|
|
|
nsBlockFrame* blockFrame = (nsBlockFrame*)aPrevInFlow;
|
|
|
|
|
1999-11-03 00:42:12 +00:00
|
|
|
SetFlags(blockFrame->mState & NS_BLOCK_FLAGS_MASK);
|
1999-02-25 05:31:15 +00:00
|
|
|
}
|
1999-03-19 23:05:56 +00:00
|
|
|
|
1999-03-29 23:44:45 +00:00
|
|
|
nsresult rv = nsBlockFrameSuper::Init(aPresContext, aContent, aParent,
|
|
|
|
aContext, aPrevInFlow);
|
|
|
|
return rv;
|
1999-02-25 05:31:15 +00:00
|
|
|
}
|
|
|
|
|
1999-04-27 22:10:51 +00:00
|
|
|
nsIStyleContext*
|
|
|
|
nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext)
|
|
|
|
{
|
|
|
|
nsIStyleContext* fls;
|
|
|
|
aPresContext->ProbePseudoStyleContextFor(mContent,
|
|
|
|
nsHTMLAtoms::firstLetterPseudo,
|
|
|
|
mStyleContext, PR_FALSE, &fls);
|
|
|
|
return fls;
|
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 06:03:41 +00:00
|
|
|
nsBlockFrame::SetInitialChildList(nsIPresContext* aPresContext,
|
1999-02-09 17:31:33 +00:00
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aChildList)
|
1998-12-05 16:02:08 +00:00
|
|
|
{
|
1999-02-26 17:04:44 +00:00
|
|
|
nsresult rv = NS_OK;
|
1998-06-24 17:52:42 +00:00
|
|
|
|
2000-05-09 05:06:16 +00:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 17:04:44 +00:00
|
|
|
mFloaters.SetFrames(aChildList);
|
|
|
|
}
|
|
|
|
else {
|
1999-04-20 00:27:43 +00:00
|
|
|
|
|
|
|
// Lookup up the two pseudo style contexts
|
|
|
|
if (nsnull == mPrevInFlow) {
|
1999-11-24 06:03:41 +00:00
|
|
|
nsIStyleContext* firstLetterStyle = GetFirstLetterStyle(aPresContext);
|
1999-04-27 22:10:51 +00:00
|
|
|
if (nsnull != firstLetterStyle) {
|
|
|
|
mState |= NS_BLOCK_HAS_FIRST_LETTER_STYLE;
|
|
|
|
#ifdef NOISY_FIRST_LETTER
|
|
|
|
ListTag(stdout);
|
2000-10-28 22:17:53 +00:00
|
|
|
printf(": first-letter style found\n");
|
1999-04-27 22:10:51 +00:00
|
|
|
#endif
|
|
|
|
NS_RELEASE(firstLetterStyle);
|
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
|
|
|
|
1999-11-24 06:03:41 +00:00
|
|
|
rv = AddFrames(aPresContext, aChildList, nsnull);
|
1999-02-26 17:04:44 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1998-06-18 16:25:41 +00:00
|
|
|
|
1999-02-26 17:04:44 +00:00
|
|
|
// Create list bullet if this is a list-item. Note that this is done
|
|
|
|
// here so that RenumberLists will work (it needs the bullets to
|
|
|
|
// store the bullet numbers).
|
|
|
|
const nsStyleDisplay* styleDisplay;
|
|
|
|
GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay);
|
|
|
|
if ((nsnull == mPrevInFlow) &&
|
|
|
|
(NS_STYLE_DISPLAY_LIST_ITEM == styleDisplay->mDisplay) &&
|
|
|
|
(nsnull == mBullet)) {
|
|
|
|
// Resolve style for the bullet frame
|
|
|
|
nsIStyleContext* kidSC;
|
1999-11-24 06:03:41 +00:00
|
|
|
aPresContext->ResolvePseudoStyleContextFor(mContent,
|
1999-02-26 17:04:44 +00:00
|
|
|
nsHTMLAtoms::mozListBulletPseudo,
|
|
|
|
mStyleContext, PR_FALSE, &kidSC);
|
|
|
|
|
|
|
|
// Create bullet frame
|
1999-12-04 23:49:50 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
mBullet = new (shell.get()) nsBulletFrame;
|
|
|
|
|
1999-02-26 17:04:44 +00:00
|
|
|
if (nsnull == mBullet) {
|
|
|
|
NS_RELEASE(kidSC);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
mBullet->Init(aPresContext, mContent, this, kidSC, nsnull);
|
1999-02-09 17:31:33 +00:00
|
|
|
NS_RELEASE(kidSC);
|
1998-07-02 00:04:12 +00:00
|
|
|
|
1999-02-26 17:04:44 +00:00
|
|
|
// If the list bullet frame should be positioned inside then add
|
|
|
|
// it to the flow now.
|
|
|
|
const nsStyleList* styleList;
|
|
|
|
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
1999-04-20 00:27:43 +00:00
|
|
|
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE ==
|
|
|
|
styleList->mListStylePosition) {
|
1999-11-24 06:03:41 +00:00
|
|
|
AddFrames(aPresContext, mBullet, nsnull);
|
1999-02-26 17:04:44 +00:00
|
|
|
mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
1998-07-02 00:04:12 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
return NS_OK;
|
1998-06-24 17:52:42 +00:00
|
|
|
}
|
|
|
|
|
1999-07-14 17:26:20 +00:00
|
|
|
PRBool
|
|
|
|
nsBlockFrame::FrameStartsCounterScope(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
const nsStyleContent* styleContent;
|
|
|
|
aFrame->GetStyleData(eStyleStruct_Content,
|
|
|
|
(const nsStyleStruct*&) styleContent);
|
|
|
|
if (0 != styleContent->CounterResetCount()) {
|
|
|
|
// Winner
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockFrame::RenumberLists(nsIPresContext* aPresContext)
|
1999-07-14 17:26:20 +00:00
|
|
|
{
|
|
|
|
if (!FrameStartsCounterScope(this)) {
|
|
|
|
// If this frame doesn't start a counter scope then we don't need
|
|
|
|
// to renumber child list items.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup initial list ordinal value
|
|
|
|
// XXX Map html's start property to counter-reset style
|
|
|
|
PRInt32 ordinal = 1;
|
|
|
|
nsIHTMLContent* hc;
|
|
|
|
if (mContent && (NS_OK == mContent->QueryInterface(kIHTMLContentIID, (void**) &hc))) {
|
|
|
|
nsHTMLValue value;
|
|
|
|
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
|
|
|
hc->GetHTMLAttribute(nsHTMLAtoms::start, value)) {
|
|
|
|
if (eHTMLUnit_Integer == value.GetUnit()) {
|
|
|
|
ordinal = value.GetIntValue();
|
|
|
|
if (ordinal <= 0) {
|
|
|
|
ordinal = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_RELEASE(hc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get to first-in-flow
|
1999-09-16 19:56:36 +00:00
|
|
|
nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow();
|
2000-07-28 09:02:34 +00:00
|
|
|
RenumberListsInBlock(aPresContext, block, &ordinal, 0);
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
|
|
|
|
1999-09-17 23:16:43 +00:00
|
|
|
PRBool
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockFrame::RenumberListsInBlock(nsIPresContext* aPresContext,
|
|
|
|
nsBlockFrame* aBlockFrame,
|
2000-07-28 09:02:34 +00:00
|
|
|
PRInt32* aOrdinal,
|
|
|
|
PRInt32 aDepth)
|
1999-09-17 23:16:43 +00:00
|
|
|
{
|
|
|
|
PRBool renumberedABullet = PR_FALSE;
|
|
|
|
|
|
|
|
while (nsnull != aBlockFrame) {
|
|
|
|
// Examine each line in the block
|
|
|
|
nsLineBox* line = aBlockFrame->mLines;
|
|
|
|
while (line) {
|
|
|
|
nsIFrame* kid = line->mFirstChild;
|
1999-10-14 23:10:03 +00:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1999-09-17 23:16:43 +00:00
|
|
|
while (--n >= 0) {
|
2000-07-28 09:02:34 +00:00
|
|
|
PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (kidRenumberedABullet) {
|
|
|
|
line->MarkDirty();
|
|
|
|
renumberedABullet = PR_TRUE;
|
|
|
|
}
|
|
|
|
kid->GetNextSibling(&kid);
|
|
|
|
}
|
|
|
|
line = line->mNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance to the next continuation
|
|
|
|
aBlockFrame->GetNextInFlow((nsIFrame**) &aBlockFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
return renumberedABullet;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX temporary code: after ib work is done in frame construction
|
|
|
|
// code this can be removed.
|
|
|
|
PRBool
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockFrame::RenumberListsIn(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aContainerFrame,
|
2000-07-28 09:02:34 +00:00
|
|
|
PRInt32* aOrdinal,
|
|
|
|
PRInt32 aDepth)
|
1999-07-14 17:26:20 +00:00
|
|
|
{
|
1999-09-17 23:16:43 +00:00
|
|
|
PRBool renumberedABullet = PR_FALSE;
|
1999-07-14 17:26:20 +00:00
|
|
|
|
|
|
|
// For each flow-block...
|
|
|
|
while (nsnull != aContainerFrame) {
|
|
|
|
// For each frame in the flow-block...
|
|
|
|
nsIFrame* kid;
|
2000-01-22 01:16:50 +00:00
|
|
|
aContainerFrame->FirstChild(aPresContext, nsnull, &kid);
|
1999-07-14 17:26:20 +00:00
|
|
|
while (nsnull != kid) {
|
2000-07-28 09:02:34 +00:00
|
|
|
PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (kidRenumberedABullet) {
|
|
|
|
renumberedABullet = PR_TRUE;
|
|
|
|
}
|
|
|
|
kid->GetNextSibling(&kid);
|
|
|
|
}
|
|
|
|
aContainerFrame->GetNextInFlow(&aContainerFrame);
|
|
|
|
}
|
|
|
|
return renumberedABullet;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2000-01-22 01:16:50 +00:00
|
|
|
nsBlockFrame::RenumberListsFor(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aKid,
|
2000-07-28 09:02:34 +00:00
|
|
|
PRInt32* aOrdinal,
|
|
|
|
PRInt32 aDepth)
|
1999-09-17 23:16:43 +00:00
|
|
|
{
|
2001-02-02 21:17:01 +00:00
|
|
|
NS_ASSERTION(aPresContext && aKid && aOrdinal, "null params are immoral!");
|
|
|
|
|
2000-06-14 23:15:59 +00:00
|
|
|
// add in a sanity check for absurdly deep frame trees. See bug 42138
|
2000-07-28 09:02:34 +00:00
|
|
|
if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth)
|
2000-06-14 23:15:59 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
|
1999-09-17 23:16:43 +00:00
|
|
|
PRBool kidRenumberedABullet = PR_FALSE;
|
2001-02-02 21:17:01 +00:00
|
|
|
nsIFrame* kid = aKid;
|
|
|
|
|
|
|
|
// if the frame is a placeholder, then get the out of flow frame
|
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
aKid->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
if (nsLayoutAtoms::placeholderFrame == frameType.get()) {
|
|
|
|
kid = NS_STATIC_CAST(nsPlaceholderFrame*, aKid)->GetOutOfFlowFrame();
|
|
|
|
NS_ASSERTION(kid, "no out-of-flow frame");
|
|
|
|
}
|
1999-07-14 17:26:20 +00:00
|
|
|
|
1999-09-17 23:16:43 +00:00
|
|
|
// If the frame is a list-item and the frame implements our
|
|
|
|
// block frame API then get it's bullet and set the list item
|
|
|
|
// ordinal.
|
|
|
|
const nsStyleDisplay* display;
|
2001-02-02 21:17:01 +00:00
|
|
|
kid->GetStyleData(eStyleStruct_Display,
|
1999-09-17 23:16:43 +00:00
|
|
|
(const nsStyleStruct*&) display);
|
|
|
|
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
|
|
|
// Make certain that the frame isa block-frame in case
|
|
|
|
// something foreign has crept in.
|
|
|
|
nsBlockFrame* listItem;
|
2001-02-02 21:17:01 +00:00
|
|
|
nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**)&listItem);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (nsnull != listItem->mBullet) {
|
|
|
|
PRBool changed;
|
|
|
|
*aOrdinal = listItem->mBullet->SetListItemOrdinal(*aOrdinal,
|
|
|
|
&changed);
|
|
|
|
if (changed) {
|
|
|
|
kidRenumberedABullet = PR_TRUE;
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
|
|
|
}
|
1999-09-17 23:16:43 +00:00
|
|
|
|
|
|
|
// XXX temporary? if the list-item has child list-items they
|
|
|
|
// should be numbered too; especially since the list-item is
|
|
|
|
// itself (ASSUMED!) not to be a counter-reseter.
|
2000-07-28 09:02:34 +00:00
|
|
|
PRBool meToo = RenumberListsInBlock(aPresContext, listItem, aOrdinal, aDepth + 1);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (meToo) {
|
|
|
|
kidRenumberedABullet = PR_TRUE;
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-17 23:16:43 +00:00
|
|
|
else if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) {
|
2001-02-02 21:17:01 +00:00
|
|
|
if (FrameStartsCounterScope(kid)) {
|
1999-09-17 23:16:43 +00:00
|
|
|
// Don't bother recursing into a block frame that is a new
|
|
|
|
// counter scope. Any list-items in there will be handled by
|
|
|
|
// it.
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If the display=block element ISA block-frame then go
|
|
|
|
// ahead and recurse into it as it might have child
|
|
|
|
// list-items.
|
|
|
|
nsBlockFrame* kidBlock;
|
2001-02-02 21:17:01 +00:00
|
|
|
nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &kidBlock);
|
1999-09-17 23:16:43 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-07-28 09:02:34 +00:00
|
|
|
kidRenumberedABullet = RenumberListsInBlock(aPresContext, kidBlock, aOrdinal, aDepth + 1);
|
1999-09-17 23:16:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (NS_STYLE_DISPLAY_INLINE == display->mDisplay) {
|
|
|
|
// XXX temporary code: after ib work is done in frame construction
|
|
|
|
// code this can be removed.
|
|
|
|
|
|
|
|
// If the display=inline element ISA nsInlineFrame then go
|
|
|
|
// ahead and recurse into it as it might have child
|
|
|
|
// list-items.
|
|
|
|
nsInlineFrame* kidInline;
|
2001-02-02 21:17:01 +00:00
|
|
|
nsresult rv = kid->QueryInterface(nsInlineFrame::kInlineFrameCID,
|
1999-09-17 23:16:43 +00:00
|
|
|
(void**) &kidInline);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2001-02-02 21:17:01 +00:00
|
|
|
kidRenumberedABullet = RenumberListsIn(aPresContext, kid, aOrdinal, aDepth + 1);
|
1999-09-17 23:16:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return kidRenumberedABullet;
|
1999-07-14 17:26:20 +00:00
|
|
|
}
|
1998-10-16 20:22:39 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
1999-02-18 22:22:55 +00:00
|
|
|
nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|
|
|
nsHTMLReflowMetrics& aMetrics)
|
1998-06-18 16:25:41 +00:00
|
|
|
{
|
1998-12-05 16:02:08 +00:00
|
|
|
// Reflow the bullet now
|
|
|
|
nsSize availSize;
|
|
|
|
availSize.width = NS_UNCONSTRAINEDSIZE;
|
|
|
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
1999-11-24 06:03:41 +00:00
|
|
|
nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
|
1999-03-05 04:21:32 +00:00
|
|
|
mBullet, availSize);
|
1999-10-30 02:52:11 +00:00
|
|
|
nsReflowStatus status;
|
1999-11-24 06:03:41 +00:00
|
|
|
mBullet->WillReflow(aState.mPresContext);
|
|
|
|
mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status);
|
1998-11-19 03:52:29 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Place the bullet now; use its right margin to distance it
|
|
|
|
// from the rest of the frames in the line
|
1999-07-20 03:41:03 +00:00
|
|
|
nscoord x = - reflowState.mComputedMargin.right - aMetrics.width;
|
1999-02-18 22:22:55 +00:00
|
|
|
|
|
|
|
// Approximate the bullets position; vertical alignment will provide
|
|
|
|
// the final vertical location.
|
1999-07-14 17:26:20 +00:00
|
|
|
const nsMargin& bp = aState.BorderPadding();
|
1999-03-05 04:21:32 +00:00
|
|
|
nscoord y = bp.top;
|
1999-10-26 04:44:41 +00:00
|
|
|
mBullet->SetRect(aState.mPresContext, nsRect(x, y, aMetrics.width, aMetrics.height));
|
1999-11-24 06:03:41 +00:00
|
|
|
mBullet->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-07-22 05:02:07 +00:00
|
|
|
|
1999-02-26 17:04:44 +00:00
|
|
|
//XXX get rid of this -- its slow
|
1998-12-05 16:02:08 +00:00
|
|
|
void
|
|
|
|
nsBlockFrame::BuildFloaterList()
|
|
|
|
{
|
|
|
|
nsIFrame* head = nsnull;
|
|
|
|
nsIFrame* current = nsnull;
|
|
|
|
nsLineBox* line = mLines;
|
|
|
|
while (nsnull != line) {
|
1999-10-14 23:10:03 +00:00
|
|
|
if (line->HasFloaters()) {
|
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 00:28:10 +00:00
|
|
|
while (fc) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
1998-12-05 16:02:08 +00:00
|
|
|
if (nsnull == head) {
|
|
|
|
current = head = floater;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
current->SetNextSibling(floater);
|
|
|
|
current = floater;
|
|
|
|
}
|
1999-09-15 00:28:10 +00:00
|
|
|
fc = fc->Next();
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
line = line->mNext;
|
1998-11-19 03:52:29 +00:00
|
|
|
}
|
1998-06-24 17:52:42 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// Terminate end of floater list just in case a floater was removed
|
|
|
|
if (nsnull != current) {
|
|
|
|
current->SetNextSibling(nsnull);
|
1998-11-19 03:52:29 +00:00
|
|
|
}
|
1999-01-15 22:53:39 +00:00
|
|
|
mFloaters.SetFrames(head);
|
1998-12-05 16:02:08 +00:00
|
|
|
}
|
1998-10-30 22:10:10 +00:00
|
|
|
|
1998-12-05 16:02:08 +00:00
|
|
|
// XXX keep the text-run data in the first-in-flow of the block
|
1999-02-26 17:04:44 +00:00
|
|
|
|
1999-03-16 19:36:00 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
1999-04-20 00:27:43 +00:00
|
|
|
nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
1999-03-16 19:36:00 +00:00
|
|
|
{
|
1999-10-19 23:04:19 +00:00
|
|
|
if (!gVerifyLines) {
|
|
|
|
return;
|
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
nsLineBox* line = mLines;
|
|
|
|
if (!line) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add up the counts on each line. Also validate that IsFirstLine is
|
|
|
|
// set properly.
|
|
|
|
PRInt32 count = 0;
|
|
|
|
PRBool seenBlock = PR_FALSE;
|
|
|
|
while (nsnull != line) {
|
|
|
|
if (aFinalCheckOK) {
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line");
|
1999-04-20 00:27:43 +00:00
|
|
|
if (line->IsBlock()) {
|
|
|
|
seenBlock = PR_TRUE;
|
|
|
|
}
|
1999-08-31 03:09:40 +00:00
|
|
|
if (line->IsBlock()) {
|
1999-10-14 23:10:03 +00:00
|
|
|
NS_ASSERTION(1 == line->GetChildCount(), "bad first line");
|
1999-04-20 00:27:43 +00:00
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
}
|
1999-10-14 23:10:03 +00:00
|
|
|
count += line->GetChildCount();
|
1999-04-20 00:27:43 +00:00
|
|
|
line = line->mNext;
|
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
|
1999-04-20 00:27:43 +00:00
|
|
|
// Then count the frames
|
|
|
|
PRInt32 frameCount = 0;
|
|
|
|
nsIFrame* frame = mLines->mFirstChild;
|
|
|
|
while (nsnull != frame) {
|
|
|
|
frameCount++;
|
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
|
|
|
NS_ASSERTION(count == frameCount, "bad line list");
|
|
|
|
|
|
|
|
// Next: test that each line has right number of frames on it
|
|
|
|
line = mLines;
|
|
|
|
nsLineBox* prevLine = nsnull;
|
|
|
|
while (nsnull != line) {
|
1999-10-14 23:10:03 +00:00
|
|
|
count = line->GetChildCount();
|
1999-04-20 00:27:43 +00:00
|
|
|
frame = line->mFirstChild;
|
|
|
|
while (--count >= 0) {
|
1999-03-16 19:36:00 +00:00
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
1999-04-20 00:27:43 +00:00
|
|
|
prevLine = line;
|
|
|
|
line = line->mNext;
|
1999-10-14 23:10:03 +00:00
|
|
|
if ((nsnull != line) && (0 != line->GetChildCount())) {
|
1999-04-20 00:27:43 +00:00
|
|
|
NS_ASSERTION(frame == line->mFirstChild, "bad line list");
|
1999-03-16 19:36:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Its possible that a frame can have some frames on an overflow
|
|
|
|
// list. But its never possible for multiple frames to have overflow
|
|
|
|
// lists. Check that this fact is actually true.
|
|
|
|
void
|
1999-11-02 23:42:52 +00:00
|
|
|
nsBlockFrame::VerifyOverflowSituation(nsIPresContext* aPresContext)
|
1999-03-16 19:36:00 +00:00
|
|
|
{
|
|
|
|
nsBlockFrame* flow = (nsBlockFrame*) GetFirstInFlow();
|
|
|
|
while (nsnull != flow) {
|
1999-11-02 23:42:52 +00:00
|
|
|
nsLineBox* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
|
|
|
if (nsnull != overflowLines) {
|
|
|
|
NS_ASSERTION(nsnull != overflowLines->mFirstChild,
|
1999-03-16 19:36:00 +00:00
|
|
|
"bad overflow list");
|
|
|
|
}
|
|
|
|
flow = (nsBlockFrame*) flow->mNextInFlow;
|
|
|
|
}
|
|
|
|
}
|
1999-03-22 22:42:30 +00:00
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsBlockFrame::GetDepth() const
|
|
|
|
{
|
|
|
|
PRInt32 depth = 0;
|
|
|
|
nsIFrame* parent = mParent;
|
|
|
|
while (nsnull != parent) {
|
|
|
|
parent->GetParent(&parent);
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
return depth;
|
|
|
|
}
|
1999-03-16 19:36:00 +00:00
|
|
|
#endif
|