2001-09-29 00:14:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2001-10-25 05:08:40 +04:00
|
|
|
// vim:cindent:ts=2:et:sw=2:
|
2001-09-29 00:14:13 +04:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
1998-06-18 20:25:41 +04:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/NPL/
|
1998-06-18 20:25:41 +04:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
1998-06-18 20:25:41 +04:00
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
1999-11-06 06:40:37 +03:00
|
|
|
*
|
2001-09-29 00:14:13 +04:00
|
|
|
* Contributor(s):
|
2000-04-17 18:40:46 +04:00
|
|
|
* Steve Clark <buster@netscape.com>
|
|
|
|
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
2000-09-05 01:44:48 +04:00
|
|
|
* L. David Baron <dbaron@fas.harvard.edu>
|
2001-09-29 00:14:13 +04:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1999-03-20 02:05:56 +03:00
|
|
|
#include "nsCOMPtr.h"
|
1998-11-16 20:11:12 +03:00
|
|
|
#include "nsBlockFrame.h"
|
1998-12-05 19:02:08 +03:00
|
|
|
#include "nsBlockReflowContext.h"
|
2001-05-01 08:22:57 +04:00
|
|
|
#include "nsBlockReflowState.h"
|
1998-12-09 00:43:15 +03:00
|
|
|
#include "nsBlockBandData.h"
|
1998-12-05 19:02:08 +03:00
|
|
|
#include "nsBulletFrame.h"
|
|
|
|
#include "nsLineBox.h"
|
1999-04-20 04:27:43 +04:00
|
|
|
#include "nsInlineFrame.h"
|
1998-09-15 04:19:49 +04:00
|
|
|
#include "nsLineLayout.h"
|
1998-06-18 20:25:41 +04:00
|
|
|
#include "nsPlaceholderFrame.h"
|
|
|
|
#include "nsStyleConsts.h"
|
1998-06-24 21:52:42 +04:00
|
|
|
#include "nsCSSRendering.h"
|
1999-11-03 02:42:52 +03:00
|
|
|
#include "nsIFrameManager.h"
|
1998-06-18 20:25:41 +04:00
|
|
|
#include "nsIPresContext.h"
|
|
|
|
#include "nsIPresShell.h"
|
2002-05-10 22:22:41 +04:00
|
|
|
#include "nsReflowPath.h"
|
1998-06-18 20:25:41 +04:00
|
|
|
#include "nsIStyleContext.h"
|
|
|
|
#include "nsIView.h"
|
1998-07-11 00:30:23 +04:00
|
|
|
#include "nsIFontMetrics.h"
|
1998-09-23 06:25:26 +04:00
|
|
|
#include "nsHTMLParts.h"
|
|
|
|
#include "nsHTMLAtoms.h"
|
|
|
|
#include "nsHTMLValue.h"
|
2000-12-30 22:22:22 +03:00
|
|
|
#include "nsIDOMEvent.h"
|
1998-09-24 00:10:40 +04:00
|
|
|
#include "nsIHTMLContent.h"
|
1998-11-15 00:01:26 +03:00
|
|
|
#include "prprf.h"
|
1998-12-09 08:30:17 +03:00
|
|
|
#include "nsLayoutAtoms.h"
|
1998-11-05 22:33:01 +03:00
|
|
|
#include "nsITextContent.h"
|
1999-07-14 21:26:20 +04:00
|
|
|
#include "nsStyleChangeList.h"
|
1999-08-31 08:32:13 +04:00
|
|
|
#include "nsISizeOfHandler.h"
|
1999-08-25 01:51:47 +04:00
|
|
|
#include "nsIFocusTracker.h"
|
|
|
|
#include "nsIFrameSelection.h"
|
1999-10-07 02:05:23 +04:00
|
|
|
#include "nsSpaceManager.h"
|
2001-10-25 05:08:40 +04:00
|
|
|
#include "nsIntervalSet.h"
|
1999-10-16 03:35:10 +04:00
|
|
|
#include "prenv.h"
|
|
|
|
#include "plstr.h"
|
2001-07-16 06:40:48 +04:00
|
|
|
#include "nsGUIEvent.h"
|
1999-01-06 02:01:54 +03:00
|
|
|
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
#include "nsBidiPresUtils.h"
|
|
|
|
#endif // IBMBIDI
|
|
|
|
|
2001-03-08 05:46:44 +03:00
|
|
|
#include "nsIDOMHTMLBodyElement.h"
|
|
|
|
#include "nsIDOMHTMLHtmlElement.h"
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
2001-12-18 01:39:59 +03:00
|
|
|
#include "nsPrintfCString.h"
|
2001-05-01 08:22:57 +04:00
|
|
|
#include "nsBlockDebugFlags.h"
|
1999-10-16 03:35:10 +04:00
|
|
|
|
2001-05-01 08:22:57 +04:00
|
|
|
PRBool nsBlockFrame::gLamePaintMetrics;
|
|
|
|
PRBool nsBlockFrame::gLameReflowMetrics;
|
|
|
|
PRBool nsBlockFrame::gNoisy;
|
|
|
|
PRBool nsBlockFrame::gNoisyDamageRepair;
|
|
|
|
PRBool nsBlockFrame::gNoisyMaxElementSize;
|
|
|
|
PRBool nsBlockFrame::gNoisyReflow;
|
|
|
|
PRBool nsBlockFrame::gReallyNoisyReflow;
|
|
|
|
PRBool nsBlockFrame::gNoisySpaceManager;
|
|
|
|
PRBool nsBlockFrame::gVerifyLines;
|
|
|
|
PRBool nsBlockFrame::gDisableResizeOpt;
|
|
|
|
|
|
|
|
PRInt32 nsBlockFrame::gNoiseIndent;
|
1999-10-16 03:35:10 +04:00
|
|
|
|
|
|
|
struct BlockDebugFlags {
|
|
|
|
const char* name;
|
|
|
|
PRBool* on;
|
|
|
|
};
|
|
|
|
|
|
|
|
static BlockDebugFlags gFlags[] = {
|
2001-05-01 08:22:57 +04:00
|
|
|
{ "reflow", &nsBlockFrame::gNoisyReflow },
|
|
|
|
{ "really-noisy-reflow", &nsBlockFrame::gReallyNoisyReflow },
|
|
|
|
{ "max-element-size", &nsBlockFrame::gNoisyMaxElementSize },
|
|
|
|
{ "space-manager", &nsBlockFrame::gNoisySpaceManager },
|
|
|
|
{ "verify-lines", &nsBlockFrame::gVerifyLines },
|
|
|
|
{ "damage-repair", &nsBlockFrame::gNoisyDamageRepair },
|
|
|
|
{ "lame-paint-metrics", &nsBlockFrame::gLamePaintMetrics },
|
|
|
|
{ "lame-reflow-metrics", &nsBlockFrame::gLameReflowMetrics },
|
|
|
|
{ "disable-resize-opt", &nsBlockFrame::gDisableResizeOpt },
|
1999-10-16 03:35:10 +04:00
|
|
|
};
|
|
|
|
#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
|
|
|
|
|
|
|
|
static void
|
|
|
|
ShowDebugFlags()
|
|
|
|
{
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("Here are the available GECKO_BLOCK_DEBUG_FLAGS:\n");
|
1999-10-16 03:35:10 +04:00
|
|
|
BlockDebugFlags* bdf = gFlags;
|
|
|
|
BlockDebugFlags* end = gFlags + NUM_DEBUG_FLAGS;
|
|
|
|
for (; bdf < end; bdf++) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" %s\n", bdf->name);
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("Note: GECKO_BLOCK_DEBUG_FLAGS is a comma seperated list of flag\n");
|
|
|
|
printf("names (no whitespace)\n");
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
|
|
|
|
2001-05-01 08:22:57 +04:00
|
|
|
void
|
|
|
|
nsBlockFrame::InitDebugFlags()
|
1999-10-16 03:35:10 +04:00
|
|
|
{
|
|
|
|
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-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame: setting %s debug flag on\n", bdf->name);
|
1999-10-16 03:35:10 +04:00
|
|
|
gNoisy = PR_TRUE;
|
|
|
|
found = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
error = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cm) break;
|
|
|
|
*cm = ',';
|
|
|
|
flags = cm + 1;
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
ShowDebugFlags();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-11-05 22:33:01 +03:00
|
|
|
#endif
|
|
|
|
|
2000-06-15 03:15:59 +04:00
|
|
|
// 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-12 02:14:33 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//----------------------------------------------------------------------
|
1998-09-24 00:10:40 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Debugging support code
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
2001-12-18 01:39:59 +03:00
|
|
|
const char* nsBlockFrame::kReflowCommandType[] = {
|
1998-12-05 19:02:08 +03:00
|
|
|
"ContentChanged",
|
|
|
|
"StyleChanged",
|
1999-03-05 07:21:32 +03:00
|
|
|
"ReflowDirty",
|
2001-12-18 01:39:59 +03:00
|
|
|
"Timeout",
|
1998-12-05 19:02:08 +03:00
|
|
|
"UserDefined",
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_FIRST_LINE
|
|
|
|
static void
|
|
|
|
DumpStyleGeneaology(nsIFrame* aFrame, const char* gap)
|
|
|
|
{
|
|
|
|
fputs(gap, stdout);
|
1999-03-05 07:21:32 +03:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": ");
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIStyleContext* sc;
|
1999-03-05 07:21:32 +03:00
|
|
|
aFrame->GetStyleContext(&sc);
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != sc) {
|
|
|
|
nsIStyleContext* psc;
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p ", sc);
|
1998-12-05 19:02:08 +03:00
|
|
|
psc = sc->GetParent();
|
|
|
|
NS_RELEASE(sc);
|
|
|
|
sc = psc;
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REFLOW_STATUS_COVERAGE
|
|
|
|
static void
|
1999-02-09 20:31:33 +03:00
|
|
|
RecordReflowStatus(PRBool aChildIsBlock, nsReflowStatus aFrameReflowStatus)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-02-09 20:31:33 +03:00
|
|
|
static PRUint32 record[2];
|
1998-12-05 19:02:08 +03:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
// 0: child-is-block
|
|
|
|
// 1: child-is-inline
|
1998-12-05 19:02:08 +03: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-29 02:17:53 +04:00
|
|
|
printf("record(%d): %02x %02x\n", index, record[0], record[1]);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2002-05-03 17:49:44 +04:00
|
|
|
/**
|
|
|
|
* A helper class to manage maintenance of the space manager during
|
|
|
|
* nsBlockFrame::Reflow. It automatically restores the old space
|
|
|
|
* manager in the reflow state when the object goes out of scope.
|
|
|
|
*/
|
|
|
|
class nsAutoSpaceManager {
|
|
|
|
public:
|
|
|
|
nsAutoSpaceManager(nsHTMLReflowState& aReflowState)
|
|
|
|
: mReflowState(aReflowState),
|
|
|
|
#ifdef DEBUG
|
|
|
|
mOwns(PR_TRUE),
|
|
|
|
#endif
|
|
|
|
mNew(nsnull),
|
|
|
|
mOld(nsnull) {}
|
|
|
|
|
|
|
|
~nsAutoSpaceManager();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new space manager for the specified frame. This will
|
|
|
|
* `remember' the old space manager, and install the new space
|
|
|
|
* manager in the reflow state.
|
|
|
|
*/
|
|
|
|
nsresult
|
|
|
|
CreateSpaceManagerFor(nsIPresContext *aPresContext,
|
|
|
|
nsIFrame *aFrame);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/**
|
|
|
|
* `Orphan' any space manager that the nsAutoSpaceManager created;
|
|
|
|
* i.e., make it so that we don't destroy the space manager when we
|
|
|
|
* go out of scope.
|
|
|
|
*/
|
|
|
|
void DebugOrphanSpaceManager() { mOwns = PR_FALSE; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
protected:
|
|
|
|
nsHTMLReflowState &mReflowState;
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRBool mOwns;
|
|
|
|
#endif
|
|
|
|
nsSpaceManager *mNew;
|
|
|
|
nsSpaceManager *mOld;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsAutoSpaceManager::~nsAutoSpaceManager()
|
|
|
|
{
|
|
|
|
// Restore the old space manager in the reflow state if necessary.
|
|
|
|
if (mNew) {
|
|
|
|
#ifdef NOISY_SPACEMANAGER
|
2002-05-07 05:32:55 +04:00
|
|
|
printf("restoring old space manager %p\n", mOld);
|
2002-05-03 17:49:44 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
mReflowState.mSpaceManager = mOld;
|
|
|
|
|
|
|
|
#ifdef NOISY_SPACEMANAGER
|
|
|
|
if (mOld) {
|
2002-05-07 05:32:55 +04:00
|
|
|
NS_STATIC_CAST(nsFrame *, mReflowState.frame)->ListTag(stdout);
|
2002-05-03 17:49:44 +04:00
|
|
|
printf(": space-manager %p after reflow\n", mOld);
|
|
|
|
mOld->List(stdout);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (mOwns)
|
|
|
|
#endif
|
|
|
|
delete mNew;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsAutoSpaceManager::CreateSpaceManagerFor(nsIPresContext *aPresContext, nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
// Create a new space manager and install it in the reflow
|
|
|
|
// state. `Remember' the old space manager so we can restore it
|
|
|
|
// later.
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
mNew = new nsSpaceManager(shell, aFrame);
|
|
|
|
if (! mNew)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
#ifdef NOISY_SPACEMANAGER
|
|
|
|
printf("constructed new space manager %p (replacing %p)\n",
|
2002-05-07 05:32:55 +04:00
|
|
|
mNew, mReflowState.mSpaceManager);
|
2002-05-03 17:49:44 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Set the space manager in the existing reflow state
|
|
|
|
mOld = mReflowState.mSpaceManager;
|
|
|
|
mReflowState.mSpaceManager = mNew;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2001-05-01 08:22:57 +04:00
|
|
|
void
|
|
|
|
nsBlockFrame::CombineRects(const nsRect& r1, nsRect& r2)
|
1999-03-23 07:28:20 +03:00
|
|
|
{
|
1999-05-13 04:55:38 +04:00
|
|
|
nscoord xa = r2.x;
|
|
|
|
nscoord ya = r2.y;
|
|
|
|
nscoord xb = xa + r2.width;
|
|
|
|
nscoord yb = ya + r2.height;
|
1999-03-23 07:28:20 +03:00
|
|
|
nscoord x = r1.x;
|
|
|
|
nscoord y = r1.y;
|
|
|
|
nscoord xmost = x + r1.width;
|
|
|
|
nscoord ymost = y + r1.height;
|
1999-05-13 04:55:38 +04:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
r2.x = xa;
|
|
|
|
r2.y = ya;
|
|
|
|
r2.width = xb - xa;
|
|
|
|
r2.height = yb - ya;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
1999-03-27 04:22:14 +03:00
|
|
|
const nsIID kBlockFrameCID = NS_BLOCK_FRAME_CID;
|
1998-09-24 00:10:40 +04:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
nsresult
|
1999-12-05 02:49:50 +03:00
|
|
|
NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags)
|
1999-02-09 20:31:33 +03:00
|
|
|
{
|
1999-05-12 02:03:29 +04:00
|
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
|
|
if (nsnull == aNewFrame) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
1999-12-05 02:49:50 +03:00
|
|
|
nsBlockFrame* it = new (aPresShell) nsBlockFrame;
|
1999-02-09 20:31:33 +03:00
|
|
|
if (nsnull == it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
1999-10-08 08:32:46 +04:00
|
|
|
it->SetFlags(aFlags);
|
1999-05-12 02:03:29 +04:00
|
|
|
*aNewFrame = it;
|
1999-02-09 20:31:33 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsBlockFrame::nsBlockFrame()
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
InitDebugFlags();
|
|
|
|
#endif
|
1998-09-24 00:10:40 +04:00
|
|
|
}
|
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::~nsBlockFrame()
|
1998-09-24 00:10:40 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::Destroy(nsIPresContext* aPresContext)
|
1998-09-24 00:10:40 +04:00
|
|
|
{
|
2000-05-09 09:06:16 +04:00
|
|
|
mAbsoluteContainer.DestroyFrames(this, aPresContext);
|
1999-02-19 01:22:55 +03:00
|
|
|
// Outside bullets are not in our child-list so check for them here
|
|
|
|
// and delete them when present.
|
2001-03-14 09:45:41 +03:00
|
|
|
if (mBullet && HaveOutsideBullet()) {
|
1999-07-22 06:24:52 +04:00
|
|
|
mBullet->Destroy(aPresContext);
|
1999-02-09 20:31:33 +03:00
|
|
|
mBullet = nsnull;
|
|
|
|
}
|
|
|
|
|
1999-07-22 08:00:57 +04:00
|
|
|
mFloaters.DestroyFrames(aPresContext);
|
1999-06-15 10:16:29 +04:00
|
|
|
|
1999-11-24 09:03:41 +03:00
|
|
|
nsLineBox::DeleteLineList(aPresContext, mLines);
|
1999-02-10 21:12:24 +03:00
|
|
|
|
1999-07-22 06:24:52 +04:00
|
|
|
return nsBlockFrameSuper::Destroy(aPresContext);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-09-27 00:05:09 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2001-10-30 09:02:05 +03:00
|
|
|
NS_PRECONDITION(aInstancePtr, "null out param");
|
1999-02-09 20:31:33 +03:00
|
|
|
if (aIID.Equals(kBlockFrameCID)) {
|
2001-10-30 09:02:05 +03:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(void*, NS_STATIC_CAST(nsBlockFrame*, this));
|
1999-02-09 20:31:33 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-10-30 09:02:05 +03:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsILineIterator)) ||
|
|
|
|
aIID.Equals(NS_GET_IID(nsILineIteratorNavigator)))
|
2000-05-16 12:11:14 +04:00
|
|
|
{
|
1999-05-13 04:55:38 +04:00
|
|
|
nsLineIterator* it = new nsLineIterator;
|
|
|
|
if (!it) {
|
|
|
|
*aInstancePtr = nsnull;
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2001-10-30 09:02:05 +03:00
|
|
|
NS_ADDREF(it); // reference passed to caller
|
2001-06-01 02:19:43 +04:00
|
|
|
const nsStyleVisibility* visibility;
|
|
|
|
GetStyleData(eStyleStruct_Visibility, (const nsStyleStruct*&) visibility);
|
1999-05-13 04:55:38 +04:00
|
|
|
nsresult rv = it->Init(mLines,
|
2001-06-01 02:19:43 +04:00
|
|
|
visibility->mDirection == NS_STYLE_DIRECTION_RTL);
|
1999-05-13 04:55:38 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2001-10-30 09:02:05 +03:00
|
|
|
NS_RELEASE(it);
|
1999-05-13 04:55:38 +04:00
|
|
|
return rv;
|
|
|
|
}
|
2001-10-30 09:02:05 +03:00
|
|
|
*aInstancePtr = NS_STATIC_CAST(void*,
|
|
|
|
NS_STATIC_CAST(nsILineIteratorNavigator*, it));
|
2000-05-16 12:11:14 +04:00
|
|
|
return NS_OK;
|
1999-05-13 04:55:38 +04:00
|
|
|
}
|
1999-02-09 20:31:33 +03:00
|
|
|
return nsBlockFrameSuper::QueryInterface(aIID, aInstancePtr);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-09-24 00:10:40 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::IsSplittable(nsSplittableType& aIsSplittable) const
|
1998-09-24 00:10:40 +04:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
aIsSplittable = NS_FRAME_SPLITTABLE_NON_RECTANGULAR;
|
1998-10-03 08:28:05 +04:00
|
|
|
return NS_OK;
|
1998-09-24 00:10:40 +04:00
|
|
|
}
|
|
|
|
|
1999-11-02 01:12:45 +03:00
|
|
|
#ifdef DEBUG
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_METHOD
|
1999-10-26 08:44:41 +04:00
|
|
|
nsBlockFrame::List(nsIPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-03-05 07:21:32 +03:00
|
|
|
IndentBy(out, aIndent);
|
1999-01-16 03:00:50 +03:00
|
|
|
ListTag(out);
|
2000-07-27 09:16:08 +04:00
|
|
|
#ifdef DEBUG_waterson
|
2000-10-29 02:17:53 +04:00
|
|
|
fprintf(out, " [parent=%p]", mParent);
|
2000-07-27 09:16:08 +04:00
|
|
|
#endif
|
1999-01-16 03:00:50 +03:00
|
|
|
nsIView* view;
|
1999-10-26 08:44:41 +04:00
|
|
|
GetView(aPresContext, &view);
|
1999-01-16 03:00:50 +03:00
|
|
|
if (nsnull != view) {
|
2001-10-25 05:08:40 +04:00
|
|
|
fprintf(out, " [view=%p]", NS_STATIC_CAST(void*, view));
|
1999-01-16 03:00:50 +03:00
|
|
|
}
|
1999-04-28 02:10:51 +04:00
|
|
|
if (nsnull != mNextSibling) {
|
2001-10-25 05:08:40 +04:00
|
|
|
fprintf(out, " next=%p", NS_STATIC_CAST(void*, mNextSibling));
|
1999-04-28 02:10:51 +04:00
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1999-01-16 03:00:50 +03:00
|
|
|
// Output the flow linkage
|
|
|
|
if (nsnull != mPrevInFlow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, mPrevInFlow));
|
1999-01-16 03:00:50 +03:00
|
|
|
}
|
|
|
|
if (nsnull != mNextInFlow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
fprintf(out, " next-in-flow=%p", NS_STATIC_CAST(void*, mNextInFlow));
|
1999-01-16 03:00:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Output the rect and state
|
1999-03-05 07:21:32 +03:00
|
|
|
fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
|
1999-01-16 03:00:50 +03:00
|
|
|
if (0 != mState) {
|
|
|
|
fprintf(out, " [state=%08x]", mState);
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
1999-09-01 05:02:16 +04:00
|
|
|
PRInt32 numInlineLines = 0;
|
|
|
|
PRInt32 numBlockLines = 0;
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! mLines.empty()) {
|
|
|
|
for (const_line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
|
|
|
if (line->IsBlock())
|
1999-09-01 05:02:16 +04:00
|
|
|
numBlockLines++;
|
2001-10-25 05:08:40 +04:00
|
|
|
else
|
1999-09-01 05:02:16 +04:00
|
|
|
numInlineLines++;
|
|
|
|
}
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
fprintf(out, " sc=%p(i=%d,b=%d)<\n",
|
|
|
|
NS_STATIC_CAST(void*, mStyleContext), numInlineLines, numBlockLines);
|
1999-01-16 03:00:50 +03:00
|
|
|
aIndent++;
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Output the lines
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! mLines.empty()) {
|
|
|
|
for (const_line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
1999-10-26 08:44:41 +04:00
|
|
|
line->List(aPresContext, out, aIndent);
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-01-16 03:19:10 +03:00
|
|
|
nsIAtom* listName = nsnull;
|
|
|
|
PRInt32 listIndex = 0;
|
|
|
|
for (;;) {
|
|
|
|
nsIFrame* kid;
|
1999-02-10 05:25:01 +03:00
|
|
|
GetAdditionalChildListName(listIndex++, &listName);
|
1999-01-16 03:19:10 +03:00
|
|
|
if (nsnull == listName) {
|
|
|
|
break;
|
|
|
|
}
|
2000-01-22 04:16:50 +03:00
|
|
|
FirstChild(aPresContext, listName, &kid);
|
1999-01-16 03:19:10 +03:00
|
|
|
if (nsnull != kid) {
|
|
|
|
IndentBy(out, aIndent);
|
|
|
|
nsAutoString tmp;
|
|
|
|
if (nsnull != listName) {
|
|
|
|
listName->ToString(tmp);
|
2001-10-16 07:53:44 +04:00
|
|
|
fputs(NS_LossyConvertUCS2toASCII(tmp).get(), out);
|
1999-01-16 03:19:10 +03:00
|
|
|
}
|
|
|
|
fputs("<\n", out);
|
|
|
|
while (nsnull != kid) {
|
1999-11-02 01:12:45 +03:00
|
|
|
nsIFrameDebug* frameDebug;
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
if (NS_SUCCEEDED(CallQueryInterface(kid, &frameDebug))) {
|
1999-11-02 01:12:45 +03:00
|
|
|
frameDebug->List(aPresContext, out, aIndent + 1);
|
|
|
|
}
|
1999-02-10 09:13:38 +03:00
|
|
|
kid->GetNextSibling(&kid);
|
1999-01-16 03:19:10 +03:00
|
|
|
}
|
|
|
|
IndentBy(out, aIndent);
|
|
|
|
fputs(">\n", out);
|
|
|
|
}
|
|
|
|
NS_IF_RELEASE(listName);
|
|
|
|
}
|
|
|
|
|
1999-01-16 03:00:50 +03:00
|
|
|
aIndent--;
|
1999-03-05 07:21:32 +03:00
|
|
|
IndentBy(out, aIndent);
|
1999-01-16 03:00:50 +03:00
|
|
|
fputs(">\n", out);
|
1998-07-01 03:51:26 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-07-01 03:51:26 +04:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
NS_IMETHODIMP
|
2001-11-14 04:33:42 +03:00
|
|
|
nsBlockFrame::GetFrameName(nsAString& aResult) const
|
1999-02-09 20:31:33 +03:00
|
|
|
{
|
2001-11-14 04:33:42 +03:00
|
|
|
return MakeFrameName(NS_LITERAL_STRING("Block"), aResult);
|
1999-02-09 20:31:33 +03:00
|
|
|
}
|
1999-11-02 01:12:45 +03:00
|
|
|
#endif
|
1999-02-09 20:31:33 +03:00
|
|
|
|
1999-02-12 20:45:58 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::GetFrameType(nsIAtom** aType) const
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
|
1999-04-20 22:22:28 +04:00
|
|
|
*aType = nsLayoutAtoms::blockFrame;
|
1999-02-12 20:45:58 +03:00
|
|
|
NS_ADDREF(*aType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Child frame enumeration
|
1998-08-03 21:07:44 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
2000-01-22 04:16:50 +03:00
|
|
|
nsBlockFrame::FirstChild(nsIPresContext* aPresContext,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame** aFirstChild) const
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-02-10 05:25:01 +03:00
|
|
|
NS_PRECONDITION(nsnull != aFirstChild, "null OUT parameter pointer");
|
2000-05-09 09:06:16 +04:00
|
|
|
if (aListName == nsLayoutAtoms::absoluteList) {
|
|
|
|
return mAbsoluteContainer.FirstChild(this, aListName, aFirstChild);
|
|
|
|
}
|
|
|
|
else if (nsnull == aListName) {
|
2001-10-25 05:08:40 +04:00
|
|
|
*aFirstChild = (mLines.empty()) ? nsnull : mLines.front()->mFirstChild;
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
1998-08-03 21:07:44 +04:00
|
|
|
}
|
2000-01-22 04:16:50 +03:00
|
|
|
else if (aListName == nsLayoutAtoms::overflowList) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
|
|
|
*aFirstChild = overflowLines
|
|
|
|
? overflowLines->front()->mFirstChild
|
|
|
|
: nsnull;
|
2000-01-22 04:16:50 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-02-09 20:31:33 +03:00
|
|
|
else if (aListName == nsLayoutAtoms::floaterList) {
|
1999-02-10 05:25:01 +03:00
|
|
|
*aFirstChild = mFloaters.FirstChild();
|
1999-02-09 20:31:33 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
else if (aListName == nsLayoutAtoms::bulletList) {
|
1999-04-20 07:42:32 +04:00
|
|
|
if (HaveOutsideBullet()) {
|
|
|
|
*aFirstChild = mBullet;
|
|
|
|
}
|
1999-04-21 01:51:39 +04:00
|
|
|
else {
|
|
|
|
*aFirstChild = nsnull;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
1999-02-09 20:31:33 +03:00
|
|
|
}
|
1999-02-10 05:25:01 +03:00
|
|
|
*aFirstChild = nsnull;
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
1998-08-03 21:07:44 +04:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::GetAdditionalChildListName(PRInt32 aIndex,
|
1999-02-10 05:25:01 +03:00
|
|
|
nsIAtom** aListName) const
|
1999-02-09 20:31:33 +03:00
|
|
|
{
|
1999-02-10 05:25:01 +03:00
|
|
|
NS_PRECONDITION(nsnull != aListName, "null OUT parameter pointer");
|
1999-02-09 20:31:33 +03:00
|
|
|
if (aIndex < 0) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
1999-02-10 05:25:01 +03:00
|
|
|
*aListName = nsnull;
|
1999-02-09 20:31:33 +03:00
|
|
|
switch (aIndex) {
|
|
|
|
case NS_BLOCK_FRAME_FLOATER_LIST_INDEX:
|
1999-02-10 05:25:01 +03:00
|
|
|
*aListName = nsLayoutAtoms::floaterList;
|
|
|
|
NS_ADDREF(*aListName);
|
1999-02-09 20:31:33 +03:00
|
|
|
break;
|
|
|
|
case NS_BLOCK_FRAME_BULLET_LIST_INDEX:
|
1999-04-21 01:51:39 +04:00
|
|
|
*aListName = nsLayoutAtoms::bulletList;
|
|
|
|
NS_ADDREF(*aListName);
|
1999-02-09 20:31:33 +03:00
|
|
|
break;
|
2000-05-09 09:06:16 +04:00
|
|
|
case NS_BLOCK_FRAME_ABSOLUTE_LIST_INDEX:
|
|
|
|
*aListName = nsLayoutAtoms::absoluteList;
|
|
|
|
NS_ADDREF(*aListName);
|
|
|
|
break;
|
1999-02-09 20:31:33 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::IsPercentageBase(PRBool& aBase) const
|
|
|
|
{
|
|
|
|
aBase = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-01-12 19:42:03 +03:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Frame structure methods
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Reflow methods
|
1998-08-03 21:07:44 +04:00
|
|
|
|
2000-05-09 09:06:16 +04: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
|
2001-06-01 02:19:43 +04:00
|
|
|
if (aReflowState.mStyleDisplay->IsAbsolutelyPositioned() ||
|
|
|
|
(NS_STYLE_POSITION_RELATIVE == aReflowState.mStyleDisplay->mPosition)) {
|
2000-05-09 09:06:16 +04:00
|
|
|
aContainingBlockWidth = aFrameWidth;
|
|
|
|
aContainingBlockHeight = aFrameHeight;
|
|
|
|
|
|
|
|
// Containing block is relative to the padding edge
|
|
|
|
nsMargin border;
|
2001-02-07 12:57:26 +03:00
|
|
|
if (!aReflowState.mStyleBorder->GetBorder(border)) {
|
2000-05-09 09:06:16 +04:00
|
|
|
NS_NOTYETIMPLEMENTED("percentage border");
|
|
|
|
}
|
|
|
|
aContainingBlockWidth -= border.left + border.right;
|
|
|
|
aContainingBlockHeight -= border.top + border.bottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
1999-03-05 07:21:32 +03:00
|
|
|
nsHTMLReflowMetrics& aMetrics,
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
nsReflowStatus& aStatus)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2000-04-21 18:59:47 +04:00
|
|
|
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame", aReflowState.reason);
|
2001-11-14 16:40:03 +03:00
|
|
|
DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
1999-10-20 03:04:19 +04:00
|
|
|
if (gNoisyReflow) {
|
2001-12-18 01:39:59 +03:00
|
|
|
nsCAutoString reflow;
|
|
|
|
reflow.Append(nsHTMLReflowState::ReasonToString(aReflowState.reason));
|
|
|
|
|
|
|
|
if (aReflowState.reason == eReflowReason_Incremental) {
|
2002-05-10 22:22:41 +04:00
|
|
|
nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;
|
2001-12-18 01:39:59 +03:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
if (command) {
|
|
|
|
// We're the target.
|
|
|
|
reflow += " (";
|
2001-12-18 01:39:59 +03:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
nsReflowType type;
|
|
|
|
command->GetType(type);
|
|
|
|
reflow += kReflowCommandType[type];
|
2001-12-18 01:39:59 +03:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
reflow += ")";
|
|
|
|
}
|
2001-12-18 01:39:59 +03:00
|
|
|
}
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2001-09-06 00:27:19 +04:00
|
|
|
printf(": begin %s reflow availSize=%d,%d computedSize=%d,%d\n",
|
2001-12-18 01:39:59 +03:00
|
|
|
reflow.get(),
|
2001-09-06 00:27:19 +04:00
|
|
|
aReflowState.availableWidth, aReflowState.availableHeight,
|
1999-10-16 03:35:10 +04:00
|
|
|
aReflowState.mComputedWidth, aReflowState.mComputedHeight);
|
1999-10-20 03:04:19 +04:00
|
|
|
}
|
|
|
|
if (gNoisy) {
|
1999-10-16 03:35:10 +04:00
|
|
|
gNoiseIndent++;
|
|
|
|
}
|
2000-11-28 02:23:28 +03: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-20 03:04:19 +04:00
|
|
|
if (gLameReflowMetrics) {
|
|
|
|
start = PR_Now();
|
|
|
|
ctc = nsLineBox::GetCtorCount();
|
|
|
|
}
|
1999-10-16 03:35:10 +04:00
|
|
|
#endif
|
|
|
|
|
2002-06-12 07:21:00 +04:00
|
|
|
nsRect oldRect(mRect);
|
|
|
|
|
2002-04-19 03:37:51 +04:00
|
|
|
// Should we create a space manager?
|
2002-05-03 17:49:44 +04:00
|
|
|
nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState));
|
|
|
|
|
2002-04-19 03:37:51 +04:00
|
|
|
// XXXldb If we start storing the space manager in the frame rather
|
|
|
|
// than keeping it around only during reflow then we should create it
|
|
|
|
// only when there are actually floats to manage. Otherwise things
|
|
|
|
// like tables will gain significant bloat.
|
2002-05-03 17:49:44 +04:00
|
|
|
if (NS_BLOCK_SPACE_MGR & mState)
|
|
|
|
autoSpaceManager.CreateSpaceManagerFor(aPresContext, this);
|
2002-04-19 03:37:51 +04:00
|
|
|
|
2002-07-29 08:19:15 +04:00
|
|
|
// See if it's an incremental reflow command
|
2002-06-12 07:21:00 +04:00
|
|
|
if (mAbsoluteContainer.HasAbsoluteFrames() &&
|
2002-07-29 08:19:15 +04:00
|
|
|
eReflowReason_Incremental == aReflowState.reason) {
|
2000-05-09 09:06:16 +04:00
|
|
|
// Give the absolute positioning code a chance to handle it
|
|
|
|
nscoord containingBlockWidth;
|
|
|
|
nscoord containingBlockHeight;
|
|
|
|
PRBool handled;
|
|
|
|
|
|
|
|
CalculateContainingBlock(aReflowState, mRect.width, mRect.height,
|
|
|
|
containingBlockWidth, containingBlockHeight);
|
|
|
|
|
|
|
|
mAbsoluteContainer.IncrementalReflow(this, aPresContext, aReflowState,
|
2002-09-24 15:43:48 +04:00
|
|
|
containingBlockWidth,
|
|
|
|
containingBlockHeight,
|
|
|
|
handled);
|
2000-05-09 09:06:16 +04:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
aMetrics.width = mRect.width;
|
|
|
|
aMetrics.height = mRect.height;
|
2002-09-24 15:43:48 +04:00
|
|
|
aMetrics.ascent = mAscent;
|
|
|
|
aMetrics.descent = aMetrics.height - aMetrics.ascent;
|
|
|
|
|
2000-05-09 09:06:16 +04:00
|
|
|
// Whether or not we're complete hasn't changed
|
|
|
|
aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE;
|
|
|
|
|
|
|
|
// Factor the absolutely positioned child bounds into the overflow area
|
2002-09-24 15:43:48 +04:00
|
|
|
ComputeCombinedArea(aReflowState, aMetrics);
|
|
|
|
nsRect childBounds;
|
|
|
|
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
|
2000-05-09 09:06:16 +04:00
|
|
|
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;
|
|
|
|
}
|
2002-04-19 03:37:51 +04:00
|
|
|
|
2000-05-09 09:06:16 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
|
|
|
|
#ifdef DEBUG_kipp
|
|
|
|
{
|
|
|
|
extern char* nsPresShell_ReflowStackPointerTop;
|
|
|
|
char marker;
|
|
|
|
char* newsp = (char*) ▮
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("XXX: frame tree is too deep; approx stack size = %d\n",
|
1999-08-28 01:45:37 +04:00
|
|
|
nsPresShell_ReflowStackPointerTop - newsp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-01-03 07:32:13 +03:00
|
|
|
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
|
|
|
NS_BLOCK_MARGIN_ROOT & mState);
|
1999-02-23 22:32:00 +03:00
|
|
|
|
2002-05-03 00:25:32 +04:00
|
|
|
// The condition for doing Bidi resolutions includes a test for the
|
|
|
|
// dirtiness flags, because blocks sometimes send a resize reflow
|
|
|
|
// even though they have dirty children, An example where this can
|
|
|
|
// occur is when adding lines to a text control (bugs 95228 and 95400
|
|
|
|
// were caused by not doing Bidi resolution in these cases)
|
|
|
|
if (eReflowReason_Resize != aReflowState.reason ||
|
|
|
|
mState & NS_FRAME_IS_DIRTY || mState & NS_FRAME_HAS_DIRTY_CHILDREN) {
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! mLines.empty()) {
|
2001-03-09 06:29:00 +03:00
|
|
|
PRBool bidiEnabled;
|
2001-05-16 17:40:08 +04:00
|
|
|
aPresContext->GetBidiEnabled(&bidiEnabled);
|
2001-03-09 06:29:00 +03:00
|
|
|
if (bidiEnabled) {
|
|
|
|
nsBidiPresUtils* bidiUtils;
|
|
|
|
aPresContext->GetBidiUtils(&bidiUtils);
|
|
|
|
if (bidiUtils) {
|
|
|
|
PRBool forceReflow;
|
|
|
|
nsresult rc = bidiUtils->Resolve(aPresContext, this,
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.front()->mFirstChild,
|
2002-07-10 04:52:17 +04:00
|
|
|
forceReflow,
|
|
|
|
aReflowState.mFlags.mVisualBidiFormControl);
|
2001-03-09 06:29:00 +03:00
|
|
|
if (NS_SUCCEEDED(rc) && forceReflow) {
|
|
|
|
// Mark everything dirty
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb This should be done right.
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
2001-03-09 06:29:00 +03:00
|
|
|
line->MarkDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
2000-10-30 07:48:53 +03:00
|
|
|
RenumberLists(aPresContext);
|
1999-03-05 22:25:44 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult rv = NS_OK;
|
2001-05-04 00:11:50 +04:00
|
|
|
|
1999-03-05 07:21:32 +03:00
|
|
|
switch (aReflowState.reason) {
|
1998-12-05 19:02:08 +03:00
|
|
|
case eReflowReason_Initial:
|
1999-04-20 04:27:43 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflow=initial\n");
|
1999-04-20 04:27:43 +04:00
|
|
|
#endif
|
1999-11-24 09:03:41 +03:00
|
|
|
DrainOverflowLines(aPresContext);
|
1998-12-05 19:02:08 +03:00
|
|
|
rv = PrepareInitialReflow(state);
|
|
|
|
mState &= ~NS_FRAME_FIRST_REFLOW;
|
2000-01-12 11:28:24 +03:00
|
|
|
break;
|
|
|
|
|
2001-12-18 01:39:59 +03:00
|
|
|
case eReflowReason_Dirty:
|
|
|
|
// Do nothing; the dirty lines will already have been marked.
|
1998-12-05 19:02:08 +03:00
|
|
|
break;
|
1998-07-02 04:04:12 +04:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
case eReflowReason_Incremental: {
|
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": reflow=incremental ");
|
|
|
|
#endif
|
|
|
|
nsReflowPath *path = aReflowState.path;
|
|
|
|
nsHTMLReflowCommand *command = path->mReflowCommand;
|
|
|
|
if (command) {
|
2001-12-18 01:39:59 +03:00
|
|
|
nsReflowType type;
|
2002-05-10 22:22:41 +04:00
|
|
|
command->GetType(type);
|
1999-04-20 04:27:43 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
2002-05-10 22:22:41 +04:00
|
|
|
printf("type=%s ", kReflowCommandType[type]);
|
1999-04-20 04:27:43 +04:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
switch (type) {
|
2001-12-18 01:39:59 +03:00
|
|
|
case eReflowType_StyleChanged:
|
1998-12-05 19:02:08 +03:00
|
|
|
rv = PrepareStyleChangedReflow(state);
|
|
|
|
break;
|
2001-12-18 01:39:59 +03:00
|
|
|
case eReflowType_ReflowDirty:
|
|
|
|
// Do nothing; the dirty lines will already have been marked.
|
1999-02-03 22:09:24 +03:00
|
|
|
break;
|
2002-05-10 22:22:41 +04:00
|
|
|
case eReflowType_ContentChanged:
|
|
|
|
// Perform a full reflow.
|
|
|
|
rv = PrepareResizeReflow(state);
|
|
|
|
break;
|
1998-12-05 19:02:08 +03:00
|
|
|
default:
|
2002-05-10 22:22:41 +04:00
|
|
|
// We shouldn't get here. But, if we do, perform a full reflow.
|
|
|
|
NS_ERROR("unexpected reflow type");
|
1998-12-05 19:02:08 +03:00
|
|
|
rv = PrepareResizeReflow(state);
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 04:38:56 +04:00
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
|
|
|
|
if (path->FirstChild() != path->EndChildren()) {
|
|
|
|
// We're along the reflow path, but not necessarily the target
|
|
|
|
// of the reflow.
|
1999-04-20 04:27:43 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2002-05-10 22:22:41 +04:00
|
|
|
printf(" next={ ");
|
|
|
|
|
|
|
|
for (nsReflowPath::iterator iter = path->FirstChild();
|
|
|
|
iter != path->EndChildren();
|
|
|
|
++iter) {
|
|
|
|
nsFrame::ListTag(stdout, *iter);
|
|
|
|
printf(" ");
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
|
|
|
|
printf("}");
|
1999-04-20 04:27:43 +04:00
|
|
|
#endif
|
1998-10-06 04:38:56 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
rv = PrepareChildIncrementalReflow(state);
|
1998-10-17 00:22:39 +04:00
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
|
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
break;
|
2002-05-10 22:22:41 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
|
2000-03-15 18:16:03 +03:00
|
|
|
case eReflowReason_StyleChange:
|
2001-10-25 05:08:40 +04:00
|
|
|
DrainOverflowLines(aPresContext);
|
2000-03-15 18:16:03 +03:00
|
|
|
rv = PrepareStyleChangedReflow(state);
|
|
|
|
break;
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
case eReflowReason_Resize:
|
|
|
|
default:
|
1999-04-20 04:27:43 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflow=resize (%d)\n", aReflowState.reason);
|
1999-04-20 04:27:43 +04:00
|
|
|
#endif
|
1999-11-24 09:03:41 +03:00
|
|
|
DrainOverflowLines(aPresContext);
|
1998-12-05 19:02:08 +03:00
|
|
|
rv = PrepareResizeReflow(state);
|
|
|
|
break;
|
1998-10-17 00:22:39 +04:00
|
|
|
}
|
|
|
|
|
2001-05-04 00:11:50 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "setting up reflow failed");
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
2000-02-23 01:06:19 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Now reflow...
|
|
|
|
rv = ReflowDirtyLines(state);
|
2001-05-04 00:11:50 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2002-04-11 05:13:41 +04:00
|
|
|
aStatus = state.mReflowStatus;
|
2002-05-29 02:50:43 +04:00
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
// Put continued floaters at the beginning of the first overflow line. If the first line
|
|
|
|
// is a block then create a new line as the first line and put the floaters there. If there
|
|
|
|
// are no overflow lines, then create one and put the floaters in it.
|
2002-05-29 02:50:43 +04:00
|
|
|
if (state.mOverflowFloaters.NotEmpty()) {
|
|
|
|
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
|
|
|
if (overflowLines) {
|
|
|
|
line_iterator firstLine = overflowLines->begin();
|
2002-07-17 05:48:56 +04:00
|
|
|
if (firstLine->IsBlock()) { // floaters go on a new line before 1st overflow line
|
|
|
|
nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
|
|
|
|
state.mOverflowFloaters.GetLength(), PR_FALSE);
|
|
|
|
firstLine = mLines.before_insert(firstLine, newLine);
|
|
|
|
}
|
|
|
|
else { // floaters go on 1st overflow line
|
|
|
|
nsIFrame* firstFrame = firstLine->mFirstChild;
|
|
|
|
firstLine->mFirstChild = state.mOverflowFloaters.FirstChild();
|
|
|
|
PRInt32 numOverflowFloaters = state.mOverflowFloaters.GetLength();
|
|
|
|
// hook up the last placeholder with the original frames
|
|
|
|
nsPlaceholderFrame* lastPlaceholder =
|
|
|
|
(nsPlaceholderFrame*)state.mOverflowFloaters.LastChild();
|
|
|
|
lastPlaceholder->SetNextSibling(firstFrame);
|
|
|
|
NS_ASSERTION(firstFrame != lastPlaceholder, "trying to set next sibling to self");
|
|
|
|
firstLine->SetChildCount(firstLine->GetChildCount() + numOverflowFloaters);
|
|
|
|
}
|
2002-05-29 02:50:43 +04:00
|
|
|
}
|
2002-07-17 05:48:56 +04:00
|
|
|
else {
|
|
|
|
// Create a line, put the floaters in it, and then push.
|
2002-05-29 02:50:43 +04:00
|
|
|
nsLineBox* newLine = state.NewLineBox(state.mOverflowFloaters.FirstChild(),
|
|
|
|
state.mOverflowFloaters.GetLength(), PR_FALSE);
|
|
|
|
if (!newLine)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2002-07-17 05:48:56 +04:00
|
|
|
state.mOverflowFloaters.SetFrames(nsnull);
|
2002-05-29 02:50:43 +04:00
|
|
|
mLines.push_back(newLine);
|
|
|
|
nsLineList::iterator nextToLastLine = ----end_lines();
|
|
|
|
PushLines(state, nextToLastLine);
|
|
|
|
}
|
2002-07-17 05:48:56 +04:00
|
|
|
aStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
state.mOverflowFloaters.SetFrames(nsnull);
|
2002-05-29 02:50:43 +04:00
|
|
|
}
|
|
|
|
|
2002-04-11 05:13:41 +04:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
|
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN == aReflowState.mStyleDisplay->mOverflow) {
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
}
|
|
|
|
else {
|
1999-03-05 22:25:44 +03:00
|
|
|
#ifdef DEBUG_kipp
|
2002-04-11 05:13:41 +04:00
|
|
|
ListTag(stdout); printf(": block is not complete\n");
|
1999-03-05 22:25:44 +03:00
|
|
|
#endif
|
1999-03-05 07:21:32 +03:00
|
|
|
}
|
2001-05-04 00:11:50 +04:00
|
|
|
}
|
2002-04-11 05:13:41 +04:00
|
|
|
|
|
|
|
// XXX_perf get rid of this! This is one of the things that makes
|
|
|
|
// incremental reflow O(N^2).
|
|
|
|
BuildFloaterList();
|
2000-01-12 11:28:24 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Compute our final size
|
1999-03-05 07:21:32 +03:00
|
|
|
ComputeFinalSize(aReflowState, state, aMetrics);
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2000-03-23 02:19:10 +03: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;
|
2001-10-26 09:06:07 +04:00
|
|
|
rv = frameManager->SetFrameProperty(
|
|
|
|
this, nsLayoutAtoms::spaceManagerProperty,
|
|
|
|
reflowState.mSpaceManager,
|
|
|
|
nsnull /* should be nsSpaceManagerDestroyer*/);
|
2002-05-03 17:49:44 +04:00
|
|
|
|
|
|
|
autoSpaceManager.DebugOrphanSpaceManager();
|
2000-03-23 02:19:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-04-28 11:53:41 +04:00
|
|
|
// Determine if we need to repaint our border
|
|
|
|
CheckInvalidateBorder(aPresContext, aMetrics, aReflowState);
|
1999-07-14 19:16:56 +04:00
|
|
|
|
2000-05-09 09:06:16 +04: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
|
2002-06-12 07:21:00 +04:00
|
|
|
// We want to do this under either of two conditions:
|
|
|
|
// 1. If we didn't do the incremental reflow above.
|
|
|
|
// 2. If our size changed.
|
|
|
|
// Even though it's the padding edge that's the containing block, we
|
|
|
|
// can use our rect (the border edge) since if the border style
|
|
|
|
// changed, the reflow would have been targeted at us so we'd satisfy
|
|
|
|
// condition 1.
|
2002-08-06 16:54:52 +04:00
|
|
|
if (NS_SUCCEEDED(rv) && mAbsoluteContainer.HasAbsoluteFrames()) {
|
|
|
|
nsRect childBounds;
|
|
|
|
if (eReflowReason_Incremental != aReflowState.reason ||
|
|
|
|
aReflowState.path->mReflowCommand ||
|
|
|
|
mRect != oldRect) {
|
|
|
|
nscoord containingBlockWidth;
|
|
|
|
nscoord containingBlockHeight;
|
|
|
|
|
|
|
|
CalculateContainingBlock(aReflowState, aMetrics.width, aMetrics.height,
|
|
|
|
containingBlockWidth, containingBlockHeight);
|
|
|
|
|
|
|
|
rv = mAbsoluteContainer.Reflow(this, aPresContext, aReflowState,
|
|
|
|
containingBlockWidth,
|
|
|
|
containingBlockHeight,
|
|
|
|
childBounds);
|
|
|
|
} else {
|
|
|
|
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
|
|
|
|
}
|
2000-05-09 09:06:16 +04:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-03 17:49:44 +04:00
|
|
|
// Clear the space manager pointer in the block reflow state so we
|
|
|
|
// don't waste time translating the coordinate system back on a dead
|
|
|
|
// space manager.
|
|
|
|
if (NS_BLOCK_SPACE_MGR & mState)
|
2002-04-19 03:37:51 +04:00
|
|
|
state.mSpaceManager = nsnull;
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisy) {
|
|
|
|
gNoiseIndent--;
|
1999-10-20 03:04:19 +04:00
|
|
|
}
|
|
|
|
if (gNoisyReflow) {
|
1999-10-16 03:35:10 +04:00
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d",
|
1999-10-16 03:35:10 +04:00
|
|
|
aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ",
|
|
|
|
aMetrics.width, aMetrics.height,
|
2001-10-25 05:08:40 +04:00
|
|
|
aMetrics.mCarriedOutBottomMargin.get());
|
1999-10-16 03:35:10 +04:00
|
|
|
if (mState & NS_FRAME_OUTSIDE_CHILDREN) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" combinedArea={%d,%d,%d,%d}",
|
1999-12-06 18:49:53 +03:00
|
|
|
aMetrics.mOverflowArea.x,
|
|
|
|
aMetrics.mOverflowArea.y,
|
|
|
|
aMetrics.mOverflowArea.width,
|
|
|
|
aMetrics.mOverflowArea.height);
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
|
|
|
if (aMetrics.maxElementSize) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" maxElementSize=%d,%d",
|
1999-10-16 03:35:10 +04:00
|
|
|
aMetrics.maxElementSize->width,
|
|
|
|
aMetrics.maxElementSize->height);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-10-15 03:10:03 +04:00
|
|
|
}
|
1999-10-20 03:04:19 +04:00
|
|
|
|
|
|
|
if (gLameReflowMetrics) {
|
|
|
|
PRTime end = PR_Now();
|
|
|
|
|
|
|
|
PRInt32 ectc = nsLineBox::GetCtorCount();
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 numLines = mLines.size();
|
1999-10-20 03:04:19 +04:00
|
|
|
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-29 02:17:53 +04:00
|
|
|
printf("%s\n", buf);
|
1999-10-20 03:04:19 +04:00
|
|
|
}
|
2002-07-01 21:43:02 +04:00
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
if (aMetrics.maxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf("block %p returning with maxElementSize=%d,%d\n", this,
|
|
|
|
aMetrics.maxElementSize->width,
|
|
|
|
aMetrics.maxElementSize->height);
|
|
|
|
}
|
2000-05-09 09:06:16 +04:00
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
|
|
|
|
1999-07-07 06:33:17 +04:00
|
|
|
static PRBool
|
|
|
|
HaveAutoWidth(const nsHTMLReflowState& aReflowState)
|
|
|
|
{
|
1999-09-10 00:53:32 +04:00
|
|
|
const nsHTMLReflowState* rs = &aReflowState;
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == rs->mComputedWidth) {
|
1999-07-07 06:33:17 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-09-10 00:53:32 +04:00
|
|
|
const nsStylePosition* pos = rs->mStylePosition;
|
|
|
|
|
1999-07-07 06:33:17 +04:00
|
|
|
for (;;) {
|
1999-09-10 00:53:32 +04:00
|
|
|
if (!pos) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-07-07 06:33:17 +04:00
|
|
|
nsStyleUnit widthUnit = pos->mWidth.GetUnit();
|
|
|
|
if (eStyleUnit_Auto == widthUnit) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
if (eStyleUnit_Inherit != widthUnit) {
|
|
|
|
break;
|
|
|
|
}
|
2001-07-04 06:00:05 +04:00
|
|
|
const nsHTMLReflowState* prs = rs->parentReflowState;
|
1999-07-07 06:33:17 +04:00
|
|
|
if (!prs) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-09-10 00:53:32 +04:00
|
|
|
rs = prs;
|
1999-07-07 06:33:17 +04:00
|
|
|
pos = prs->mStylePosition;
|
|
|
|
}
|
1999-09-10 00:53:32 +04:00
|
|
|
|
1999-07-07 06:33:17 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2000-02-14 04:52:22 +03:00
|
|
|
|
|
|
|
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb why do we check vertical and horizontal at the same time? Don't
|
|
|
|
// we usually care about one or the other?
|
2000-02-14 04:52:22 +03:00
|
|
|
static PRBool
|
|
|
|
IsPercentageAwareChild(const nsIFrame* aFrame)
|
|
|
|
{
|
2001-10-03 04:01:04 +04:00
|
|
|
NS_ASSERTION(aFrame, "null frame is not allowed");
|
2001-02-07 12:57:26 +03:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
const nsStyleMargin* margin;
|
|
|
|
rv = aFrame->GetStyleData(eStyleStruct_Margin,(const nsStyleStruct*&) margin);
|
2000-02-14 04:52:22 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return PR_TRUE; // just to be on the safe side
|
|
|
|
}
|
2001-02-07 12:57:26 +03:00
|
|
|
if (nsLineLayout::IsPercentageUnitSides(&margin->mMargin)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-02-14 04:52:22 +03:00
|
|
|
|
2001-02-07 12:57:26 +03:00
|
|
|
const nsStylePadding* padding;
|
|
|
|
rv = aFrame->GetStyleData(eStyleStruct_Padding,(const nsStyleStruct*&) padding);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return PR_TRUE; // just to be on the safe side
|
|
|
|
}
|
|
|
|
if (nsLineLayout::IsPercentageUnitSides(&padding->mPadding)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsStyleBorder* border;
|
|
|
|
rv = aFrame->GetStyleData(eStyleStruct_Border,(const nsStyleStruct*&) border);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return PR_TRUE; // just to be on the safe side
|
|
|
|
}
|
|
|
|
if (nsLineLayout::IsPercentageUnitSides(&border->mBorder)) {
|
2000-02-14 04:52:22 +03: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-12 00:46:44 +04:00
|
|
|
|| nsLineLayout::IsPercentageUnitSides(&pos->mOffset)) { // XXX need more here!!!
|
2000-02-14 04:52:22 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2001-07-04 06:00:05 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
1999-03-05 07:21:32 +03:00
|
|
|
nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
|
|
|
nsBlockReflowState& aState,
|
|
|
|
nsHTMLReflowMetrics& aMetrics)
|
1998-06-25 20:33:10 +04:00
|
|
|
{
|
1999-03-05 07:21:32 +03:00
|
|
|
const nsMargin& borderPadding = aState.BorderPadding();
|
1999-09-15 04:28:10 +04:00
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
1999-09-15 04:28:10 +04:00
|
|
|
aState.mPrevBottomMargin,
|
|
|
|
borderPadding.top, borderPadding.bottom);
|
|
|
|
#endif
|
1999-03-20 02:05:56 +03:00
|
|
|
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Handling min-width/max-width stuff after reflowing children
|
|
|
|
// seems wrong. But IIRC this function only does more than a little
|
|
|
|
// bit in rare cases (or something like that, I'm not really sure).
|
|
|
|
// What are those cases, and do we get the wrong behavior?
|
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
// Compute final width
|
|
|
|
nscoord maxWidth = 0, maxHeight = 0;
|
|
|
|
#ifdef NOISY_KIDXMOST
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p aState.mKidXMost=%d\n", this, aState.mKidXMost);
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
2000-06-30 02:03:42 +04:00
|
|
|
if (!HaveAutoWidth(aReflowState)) {
|
|
|
|
// Use style defined width
|
|
|
|
aMetrics.width = borderPadding.left + aReflowState.mComputedWidth +
|
|
|
|
borderPadding.right;
|
|
|
|
|
|
|
|
// 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 21:52:42 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
else {
|
2002-08-06 08:50:40 +04:00
|
|
|
nscoord minWidth = aState.mKidXMost + borderPadding.right;
|
2000-06-30 02:03:42 +04: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
if ((mLines.empty()) ||
|
|
|
|
((mLines.front() == mLines.back()) && !mLines.front()->IsBlock() &&
|
|
|
|
(NS_STYLE_CLEAR_NONE == mLines.front()->GetBreakType())
|
2000-06-30 02:03:42 +04:00
|
|
|
/*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)) &&
|
2001-09-12 02:17:21 +04:00
|
|
|
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) &&
|
|
|
|
!aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
2000-06-30 02:03:42 +04:00
|
|
|
!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-23 01:42:30 +03:00
|
|
|
borderPadding.right;
|
|
|
|
}
|
1999-08-28 04:39:55 +04:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
// See if we should compute our max element size
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2001-09-12 02:17:21 +04:00
|
|
|
// Add in border and padding dimensions to already computed
|
|
|
|
// max-element-size values.
|
|
|
|
maxWidth = aState.mMaxElementSize.width +
|
|
|
|
borderPadding.left + borderPadding.right;
|
2000-06-30 02:03:42 +04:00
|
|
|
if (computedWidth < maxWidth) {
|
|
|
|
computedWidth = maxWidth;
|
|
|
|
}
|
|
|
|
}
|
2000-01-03 07:32:13 +03:00
|
|
|
|
2000-06-30 02:03:42 +04: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 07:32:13 +03:00
|
|
|
}
|
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
aMetrics.width = computedWidth;
|
2000-01-03 07:32:13 +03:00
|
|
|
|
2000-06-30 02:03:42 +04: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 07:32:13 +03:00
|
|
|
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
|
|
|
if (aReflowState.parentReflowState) {
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
|
|
|
parentIsShrinkWrapWidth = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
if (!parentIsShrinkWrapWidth) {
|
|
|
|
nsHTMLReflowState reflowState(aReflowState);
|
1999-03-20 22:40:13 +03:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
reflowState.mComputedWidth = aMetrics.width - borderPadding.left -
|
|
|
|
borderPadding.right;
|
|
|
|
reflowState.reason = eReflowReason_Resize;
|
|
|
|
reflowState.mSpaceManager->ClearRegions();
|
1999-09-15 04:28:10 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
#ifdef DEBUG
|
2000-06-30 02:03:42 +04:00
|
|
|
nscoord oldDesiredWidth = aMetrics.width;
|
2001-10-25 05:08:40 +04:00
|
|
|
#endif
|
2000-06-30 02:03:42 +04:00
|
|
|
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 04:28:10 +04:00
|
|
|
}
|
1999-03-20 22:40:13 +03:00
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
|
|
|
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
|
|
|
if (aReflowState.parentReflowState) {
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
|
|
|
parentIsShrinkWrapWidth = PR_TRUE;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
}
|
1999-03-23 01:42:30 +03:00
|
|
|
|
2000-06-30 02:03:42 +04: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)) {
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aState.mY + aState.mPrevBottomMargin.get() != aMetrics.height) {
|
|
|
|
aState.mPrevBottomMargin.Zero();
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2001-10-25 05:08:40 +04:00
|
|
|
autoHeight += aState.mPrevBottomMargin.get();
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
autoHeight += borderPadding.bottom;
|
|
|
|
|
2002-01-14 23:04:30 +03:00
|
|
|
if (NS_BLOCK_SPACE_MGR & mState) {
|
|
|
|
// Include the space manager's state to properly account for the
|
|
|
|
// bottom margin of any floated elements; e.g., inside a table cell.
|
|
|
|
nscoord ymost;
|
|
|
|
aReflowState.mSpaceManager->YMost(ymost);
|
|
|
|
if (ymost > autoHeight)
|
|
|
|
autoHeight = ymost;
|
|
|
|
}
|
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
// Apply min/max values
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxHeight) {
|
|
|
|
nscoord computedMaxHeight = aReflowState.mComputedMaxHeight +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
|
|
|
if (autoHeight > computedMaxHeight) {
|
|
|
|
autoHeight = computedMaxHeight;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMinHeight) {
|
|
|
|
nscoord computedMinHeight = aReflowState.mComputedMinHeight +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
|
|
|
if (autoHeight < computedMinHeight) {
|
|
|
|
autoHeight = computedMinHeight;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
aMetrics.height = autoHeight;
|
1999-03-23 01:42:30 +03:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
maxHeight = aState.mMaxElementSize.height +
|
|
|
|
borderPadding.top + borderPadding.bottom;
|
1999-03-20 22:40:13 +03:00
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
1999-03-20 22:40:13 +03:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
aMetrics.ascent = mAscent;
|
|
|
|
aMetrics.descent = aMetrics.height - aMetrics.ascent;
|
2000-07-28 13:18:15 +04:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
// Store away the final value
|
|
|
|
aMetrics.maxElementSize->width = maxWidth;
|
|
|
|
aMetrics.maxElementSize->height = maxHeight;
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf ("nsBlockFrame::CFS: %p returning MES %d\n",
|
|
|
|
this, aMetrics.maxElementSize->width);
|
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
1999-03-20 22:40:13 +03:00
|
|
|
|
2000-06-30 02:03:42 +04:00
|
|
|
// Return bottom margin information
|
2001-10-25 05:08:40 +04:00
|
|
|
// rbs says he hit this assertion occasionally (see bug 86947), so
|
|
|
|
// just set the margin to zero and we'll figure out why later
|
|
|
|
//NS_ASSERTION(aMetrics.mCarriedOutBottomMargin.IsZero(),
|
|
|
|
// "someone else set the margin");
|
|
|
|
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT))
|
|
|
|
aMetrics.mCarriedOutBottomMargin = aState.mPrevBottomMargin;
|
|
|
|
else
|
|
|
|
aMetrics.mCarriedOutBottomMargin.Zero();
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2000-06-04 13:44:08 +04:00
|
|
|
#ifdef DEBUG_blocks
|
2000-06-30 02:03:42 +04:00
|
|
|
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
2000-06-30 02:03:42 +04:00
|
|
|
}
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
|
|
|
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
2000-06-30 02:03:42 +04:00
|
|
|
maxWidth, maxHeight, aMetrics.width, aMetrics.height,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
aState.mReflowState.availableHeight);
|
|
|
|
}
|
1999-03-20 22:40:13 +03:00
|
|
|
#endif
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
|
|
|
printf("PASS1 ");
|
|
|
|
}
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
|
|
|
maxWidth, maxHeight, aMetrics.width, aMetrics.height,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
aState.mReflowState.availableHeight);
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
|
|
|
}
|
2000-06-30 02:03:42 +04:00
|
|
|
#endif
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1999-12-30 07:15:45 +03:00
|
|
|
// If we're requested to update our maximum width, then compute it
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
1999-12-30 07:15:45 +03:00
|
|
|
// We need to add in for the right border/padding
|
2001-10-30 09:02:05 +03:00
|
|
|
// XXXldb Why right and not left?
|
1999-12-30 07:15:45 +03:00
|
|
|
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
2000-05-14 08:56:25 +04:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame::ComputeFinalSize block %p setting aMetrics.mMaximumWidth to %d\n", this, aMetrics.mMaximumWidth);
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
1999-12-30 07:15:45 +03:00
|
|
|
}
|
|
|
|
|
2002-09-24 15:43:48 +04:00
|
|
|
ComputeCombinedArea(aReflowState, aMetrics);
|
|
|
|
|
|
|
|
// If the combined area of our children exceeds our bounding box
|
|
|
|
// then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_BLOCK_WRAP_SIZE & mState) {
|
|
|
|
// When the area frame is supposed to wrap around all in-flow
|
|
|
|
// children, make sure it is big enough to include those that stick
|
|
|
|
// outside the box.
|
|
|
|
if (NS_FRAME_OUTSIDE_CHILDREN & mState) {
|
|
|
|
nscoord xMost = aMetrics.mOverflowArea.XMost();
|
|
|
|
if (xMost > aMetrics.width) {
|
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": changing desired width from %d to %d\n", aMetrics.width, xMost);
|
|
|
|
#endif
|
|
|
|
aMetrics.width = xMost;
|
|
|
|
}
|
|
|
|
nscoord yMost = aMetrics.mOverflowArea.YMost();
|
|
|
|
if (yMost > aMetrics.height) {
|
|
|
|
#ifdef NOISY_FINAL_SIZE
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": changing desired height from %d to %d\n", aMetrics.height, yMost);
|
|
|
|
#endif
|
|
|
|
aMetrics.height = yMost;
|
|
|
|
// adjust descent to absorb any excess difference
|
|
|
|
aMetrics.descent = aMetrics.height - aMetrics.ascent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsBlockFrame::ComputeCombinedArea(const nsHTMLReflowState& aReflowState,
|
|
|
|
nsHTMLReflowMetrics& aMetrics)
|
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
// Compute the combined area of our children
|
2002-02-21 04:36:16 +03:00
|
|
|
// XXX_perf: This can be done incrementally. It is currently one of
|
|
|
|
// the things that makes incremental reflow O(N^2).
|
1999-05-13 04:55:38 +04:00
|
|
|
nscoord xa = 0, ya = 0, xb = aMetrics.width, yb = aMetrics.height;
|
1999-09-02 00:57:37 +04:00
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN != aReflowState.mStyleDisplay->mOverflow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
1999-09-02 00:57:37 +04:00
|
|
|
// Compute min and max x/y values for the reflowed frame's
|
|
|
|
// combined areas
|
1999-10-15 03:10:03 +04: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-02 00:57:37 +04:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
|
|
|
}
|
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
|
|
|
}
|
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
|
|
|
}
|
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
|
|
|
}
|
1999-05-04 00:51:02 +04:00
|
|
|
}
|
1999-09-15 04:28:10 +04: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).
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Can we just fix GetCombinedArea instead?
|
1999-09-15 04:28:10 +04:00
|
|
|
if (mBullet) {
|
1999-09-02 00:57:37 +04:00
|
|
|
nsRect r;
|
|
|
|
mBullet->GetRect(r);
|
1999-09-15 04:28:10 +04: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-21 00:57:03 +03:00
|
|
|
}
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
1999-03-23 01:42:30 +03:00
|
|
|
#ifdef NOISY_COMBINED_AREA
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": ca=%d,%d,%d,%d\n", xa, ya, xb-xa, yb-ya);
|
1999-03-23 01:42:30 +03:00
|
|
|
#endif
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-12-06 18:49:53 +03:00
|
|
|
aMetrics.mOverflowArea.x = xa;
|
|
|
|
aMetrics.mOverflowArea.y = ya;
|
|
|
|
aMetrics.mOverflowArea.width = xb - xa;
|
|
|
|
aMetrics.mOverflowArea.height = yb - ya;
|
2001-02-06 07:42:31 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PrepareInitialReflow(nsBlockReflowState& aState)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1999-02-09 20:31:33 +03:00
|
|
|
PrepareResizeReflow(aState);
|
|
|
|
return NS_OK;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-08-05 01:18:16 +04:00
|
|
|
|
1998-06-24 21:52:42 +04:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2002-05-10 22:22:41 +04:00
|
|
|
// XXXwaterson this is non-optimal. We'd rather do this in
|
|
|
|
// ReflowDirtyLines; however, I'm not quite ready to figure out how
|
|
|
|
// to deal with reflow path retargeting yet.
|
|
|
|
nsReflowPath *path = aState.mReflowState.path;
|
|
|
|
|
|
|
|
nsReflowPath::iterator iter = path->FirstChild();
|
|
|
|
nsReflowPath::iterator end = path->EndChildren();
|
|
|
|
|
|
|
|
for ( ; iter != end; ++iter) {
|
|
|
|
// Determine the line being impacted
|
|
|
|
line_iterator line = FindLineFor(*iter);
|
|
|
|
if (line == end_lines()) {
|
|
|
|
// This assertion actually fires on lots of pages
|
|
|
|
// (e.g., bugzilla, bugzilla query page), so limit it
|
|
|
|
// to a few people until we fix the problem causing it.
|
|
|
|
//
|
|
|
|
// I think waterson explained once why it was happening -- I think
|
|
|
|
// it has something to do with the interaction of the unconstrained
|
|
|
|
// reflow in multi-pass reflow with the reflow command's chain, but
|
|
|
|
// I don't remember the details.
|
2001-07-04 06:00:05 +04:00
|
|
|
#if defined(DEBUG_dbaron) || defined(DEBUG_waterson)
|
2002-05-10 22:22:41 +04:00
|
|
|
NS_NOTREACHED("We don't have a line for the target of the reflow. "
|
|
|
|
"Being inefficient");
|
2001-07-04 06:00:05 +04:00
|
|
|
#endif
|
2002-05-10 22:22:41 +04:00
|
|
|
// This can't happen, but just in case it does...
|
|
|
|
PrepareResizeReflow(aState);
|
|
|
|
continue;
|
2002-01-05 04:42:36 +03:00
|
|
|
}
|
2001-05-04 00:11:50 +04:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
if (line->IsInline()) {
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
|
|
|
// We've been asked to compute the maximum width of the block
|
|
|
|
// frame, which ReflowLine() will handle by performing an
|
|
|
|
// unconstrained reflow on the line. If this incremental
|
|
|
|
// reflow is targeted at a continuing frame, we may have to
|
|
|
|
// retarget it, as the unconstrained reflow can destroy some
|
|
|
|
// of the continuations. This will allow the incremental
|
|
|
|
// reflow to arrive at the target frame during the first-pass
|
|
|
|
// unconstrained reflow.
|
|
|
|
nsIFrame *prevInFlow;
|
|
|
|
(*iter)->GetPrevInFlow(&prevInFlow);
|
|
|
|
if (prevInFlow)
|
|
|
|
RetargetInlineIncrementalReflow(iter, line, prevInFlow);
|
|
|
|
}
|
|
|
|
}
|
2000-01-12 11:28:24 +03:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
// Just mark this line dirty. We never need to mark the
|
|
|
|
// previous line dirty since either:
|
|
|
|
// * the line is a block, and there would never be a chance to pull
|
|
|
|
// something up
|
|
|
|
// * It's an incremental reflow to something within an inline, which
|
|
|
|
// we know must be very limited.
|
|
|
|
line->MarkDirty();
|
|
|
|
}
|
2000-01-12 11:28:24 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-01-05 04:42:36 +03:00
|
|
|
void
|
2002-05-10 22:22:41 +04:00
|
|
|
nsBlockFrame::RetargetInlineIncrementalReflow(nsReflowPath::iterator &aTarget,
|
2002-01-05 04:42:36 +03:00
|
|
|
line_iterator &aLine,
|
|
|
|
nsIFrame *aPrevInFlow)
|
|
|
|
{
|
|
|
|
// To retarget the reflow, we'll walk back through the continuations
|
|
|
|
// until we reach the primary frame, or we reach a continuation that
|
|
|
|
// is preceded by a ``hard'' line break.
|
2002-05-10 22:22:41 +04:00
|
|
|
NS_ASSERTION(aLine->Contains(*aTarget),
|
2002-01-05 04:42:36 +03:00
|
|
|
"line doesn't contain the target of the incremental reflow");
|
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
// Now fix the iterator, keeping track of how many lines we walk
|
|
|
|
// back through.
|
2002-01-05 04:42:36 +03:00
|
|
|
PRInt32 lineCount = 0;
|
|
|
|
do {
|
|
|
|
// XXX this might happen if the block is split; e.g.,
|
|
|
|
// printing or print preview. For now, panic.
|
|
|
|
NS_ASSERTION(aLine != begin_lines(),
|
|
|
|
"ran out of lines before we ran out of prev-in-flows");
|
|
|
|
|
|
|
|
// Is the previous line a ``hard'' break? If so, stop: these
|
|
|
|
// continuations will be preserved during an unconstrained reflow.
|
|
|
|
// XXXwaterson should this be `!= NS_STYLE_CLEAR_NONE'?
|
|
|
|
--aLine;
|
|
|
|
if (aLine->GetBreakType() == NS_STYLE_CLEAR_LINE)
|
|
|
|
break;
|
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
*aTarget = aPrevInFlow;
|
|
|
|
aPrevInFlow->GetPrevInFlow(&aPrevInFlow);
|
2002-01-05 04:42:36 +03:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Paranoia. Ensure that the prev-in-flow is really in the
|
|
|
|
// previous line.
|
2002-05-10 22:22:41 +04:00
|
|
|
line_iterator check = FindLineFor(*aTarget);
|
2002-01-05 04:42:36 +03:00
|
|
|
NS_ASSERTION(check == aLine, "prev-in-flow not in previous linebox");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
++lineCount;
|
|
|
|
} while (aPrevInFlow);
|
|
|
|
|
|
|
|
if (lineCount > 0) {
|
|
|
|
// Fix any frames deeper in the reflow path.
|
2002-05-10 22:22:41 +04:00
|
|
|
#if 0
|
|
|
|
// XXXwaterson fix me! we've got to recurse through the iterator's
|
|
|
|
// kids. This really shouldn't matter unless we want to implement
|
|
|
|
// `display: inline-block' or do XBL form controls. Why, you ask?
|
|
|
|
// Because what will happen is that inline frames will get flowed
|
|
|
|
// with a resize reflow, which will be sufficient to mask any
|
|
|
|
// glitches that would otherwise occur. However, as soon as boxes
|
|
|
|
// or blocks end up in the flow here (and aren't explicit reflow
|
|
|
|
// roots), they may optimize away the resize reflow.
|
2002-01-05 04:42:36 +03:00
|
|
|
|
|
|
|
// Get the reflow path, which is stored as a stack (i.e., the next
|
|
|
|
// frame in the reflow is at the _end_ of the array).
|
|
|
|
nsVoidArray *path = aState.mReflowState.reflowCommand->GetPath();
|
|
|
|
|
|
|
|
for (PRInt32 i = path->Count() - 1; i >= 0; --i) {
|
|
|
|
nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, path->ElementAt(i));
|
|
|
|
|
|
|
|
// Stop if we encounter a non-inline frame in the reflow path.
|
|
|
|
const nsStyleDisplay *display;
|
|
|
|
::GetStyleData(frame, &display);
|
|
|
|
|
|
|
|
if (NS_STYLE_DISPLAY_INLINE != display->mDisplay)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Walk back to the primary frame.
|
|
|
|
PRInt32 count = lineCount;
|
|
|
|
nsIFrame *prevInFlow;
|
|
|
|
do {
|
|
|
|
frame->GetPrevInFlow(&prevInFlow);
|
|
|
|
} while (--count >= 0 && prevInFlow && (frame = prevInFlow));
|
|
|
|
|
|
|
|
path->ReplaceElementAt(frame, i);
|
|
|
|
}
|
2002-05-10 22:22:41 +04:00
|
|
|
#else
|
|
|
|
NS_WARNING("blowing an incremental reflow targeted at a nested inline");
|
|
|
|
#endif
|
2002-01-05 04:42:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-12 11:28:24 +03:00
|
|
|
nsresult
|
2001-10-25 05:08:40 +04:00
|
|
|
nsBlockFrame::MarkLineDirty(line_iterator aLine)
|
2000-01-12 11:28:24 +03:00
|
|
|
{
|
2000-02-07 18:36:08 +03:00
|
|
|
// Mark aLine dirty
|
|
|
|
aLine->MarkDirty();
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2001-10-25 05:08:40 +04:00
|
|
|
printf(": mark line %p dirty\n", NS_STATIC_CAST(void*, aLine.get()));
|
2000-02-07 18:36:08 +03: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...
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aLine != mLines.front() &&
|
|
|
|
aLine->IsInline() &&
|
|
|
|
aLine.prev()->IsInline()) {
|
|
|
|
aLine.prev()->MarkDirty();
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2001-10-25 05:08:40 +04:00
|
|
|
printf(": mark prev-line %p dirty\n",
|
|
|
|
NS_STATIC_CAST(void*, aLine.prev().get()));
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
1999-04-21 23:58:38 +04:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1999-04-21 23:58:38 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-10-13 03:24:22 +04:00
|
|
|
nsresult
|
1999-10-20 03:04:19 +04:00
|
|
|
nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState)
|
1999-03-05 07:21:32 +03:00
|
|
|
{
|
1999-03-05 22:25:44 +03:00
|
|
|
if (nsnull == mBullet) {
|
|
|
|
// Don't bother if there is no bullet
|
1999-10-13 03:24:22 +04:00
|
|
|
return NS_OK;
|
1999-03-05 22:25:44 +03:00
|
|
|
}
|
1999-03-05 07:21:32 +03:00
|
|
|
const nsStyleList* styleList;
|
|
|
|
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
|
|
|
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE == styleList->mListStylePosition) {
|
2001-03-14 09:45:41 +03:00
|
|
|
if (mBullet && HaveOutsideBullet()) {
|
1999-03-05 07:21:32 +03:00
|
|
|
// We now have an inside bullet, but used to have an outside
|
1999-10-15 03:10:03 +04:00
|
|
|
// bullet. Adjust the frame line list
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! mLines.empty()) {
|
2001-04-10 03:13:31 +04:00
|
|
|
// if we have a line already, then move the bullet to the front of the
|
|
|
|
// first line
|
|
|
|
nsIFrame* child = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* firstLine = mLines.front();
|
2001-04-10 03:13:31 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// bullet should not have any siblings if it was an outside bullet
|
|
|
|
nsIFrame* next = nsnull;
|
|
|
|
mBullet->GetNextSibling(&next);
|
|
|
|
NS_ASSERTION(!next, "outside bullet should not have siblings");
|
|
|
|
#endif
|
|
|
|
// move bullet to front and chain the previous frames, and update the line count
|
2001-10-25 05:08:40 +04:00
|
|
|
child = firstLine->mFirstChild;
|
|
|
|
firstLine->mFirstChild = mBullet;
|
2001-04-10 03:13:31 +04:00
|
|
|
mBullet->SetNextSibling(child);
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 count = firstLine->GetChildCount();
|
|
|
|
firstLine->SetChildCount(count+1);
|
2001-04-10 03:13:31 +04:00
|
|
|
// dirty it here in case the caller does not
|
2001-10-25 05:08:40 +04:00
|
|
|
firstLine->MarkDirty();
|
2001-04-10 03:13:31 +04:00
|
|
|
} else {
|
|
|
|
// no prior lines, just create a new line for the bullet
|
|
|
|
nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE);
|
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.push_back(line);
|
1999-03-05 07:21:32 +03: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
if ((! mLines.empty()) && (mBullet == mLines.front()->mFirstChild)) {
|
1999-03-05 07:21:32 +03:00
|
|
|
nsIFrame* next;
|
|
|
|
mBullet->GetNextSibling(&next);
|
|
|
|
mBullet->SetNextSibling(nsnull);
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 count = mLines.front()->GetChildCount() - 1;
|
1999-10-15 03:10:03 +04:00
|
|
|
NS_ASSERTION(count >= 0, "empty line w/o bullet");
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.front()->SetChildCount(count);
|
1999-10-15 03:10:03 +04:00
|
|
|
if (0 == count) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* oldFront = mLines.front();
|
|
|
|
mLines.pop_front();
|
|
|
|
aState.FreeLineBox(oldFront);
|
|
|
|
if (! mLines.empty()) {
|
|
|
|
mLines.front()->MarkDirty();
|
1999-03-05 07:21:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.front()->mFirstChild = next;
|
|
|
|
mLines.front()->MarkDirty();
|
1999-03-05 07:21:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1999-10-13 03:24:22 +04:00
|
|
|
return NS_OK;
|
1999-03-05 07:21:32 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState)
|
1998-11-12 19:32:56 +03:00
|
|
|
{
|
1999-10-20 03:04:19 +04:00
|
|
|
nsresult rv = UpdateBulletPosition(aState);
|
1999-04-28 02:10:51 +04:00
|
|
|
|
|
|
|
// Mark everything dirty
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
1999-04-28 02:10:51 +04:00
|
|
|
line->MarkDirty();
|
|
|
|
}
|
1999-10-13 03:24:22 +04:00
|
|
|
return rv;
|
1998-11-12 19:32:56 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
1998-11-05 22:33:01 +03:00
|
|
|
{
|
1999-09-25 20:50:45 +04:00
|
|
|
// See if we can try and avoid marking all the lines as dirty
|
|
|
|
PRBool tryAndSkipLines = PR_FALSE;
|
|
|
|
|
2000-04-17 18:40:46 +04: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
|
2001-05-04 00:11:50 +04:00
|
|
|
if ((! aState.IsImpactedByFloater()) &&
|
2000-04-17 18:40:46 +04:00
|
|
|
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
1999-09-25 20:50:45 +04:00
|
|
|
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
|
|
|
|
|
|
|
// If the text is left-aligned, then we try and avoid reflowing the lines
|
1999-10-29 18:34:53 +04:00
|
|
|
const nsStyleText* styleText = (const nsStyleText*)
|
1999-09-25 20:50:45 +04:00
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
|
1999-10-29 18:34:53 +04:00
|
|
|
if ((NS_STYLE_TEXT_ALIGN_LEFT == styleText->mTextAlign) ||
|
|
|
|
((NS_STYLE_TEXT_ALIGN_DEFAULT == styleText->mTextAlign) &&
|
2001-06-01 02:19:43 +04:00
|
|
|
(NS_STYLE_DIRECTION_LTR == aState.mReflowState.mStyleVisibility->mDirection))) {
|
1999-09-25 20:50:45 +04:00
|
|
|
tryAndSkipLines = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
1999-10-29 18:34:53 +04:00
|
|
|
if (gDisableResizeOpt) {
|
|
|
|
tryAndSkipLines = PR_FALSE;
|
|
|
|
}
|
1999-10-16 03:35:10 +04:00
|
|
|
if (gNoisyReflow) {
|
|
|
|
if (!tryAndSkipLines) {
|
|
|
|
const nsStyleText* mStyleText = (const nsStyleText*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": marking all lines dirty: reason=%d availWidth=%d textAlign=%d\n",
|
1999-10-16 03:35:10 +04:00
|
|
|
aState.mReflowState.reason,
|
|
|
|
aState.mReflowState.availableWidth,
|
|
|
|
mStyleText->mTextAlign);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-09-25 20:50:45 +04:00
|
|
|
if (tryAndSkipLines) {
|
2000-01-03 07:32:13 +03:00
|
|
|
nscoord newAvailWidth = aState.mReflowState.mComputedBorderPadding.left;
|
|
|
|
|
|
|
|
if (NS_SHRINKWRAPWIDTH == aState.mReflowState.mComputedWidth) {
|
2000-10-10 01:19:36 +04:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedMaxWidth) {
|
|
|
|
newAvailWidth += aState.mReflowState.mComputedMaxWidth;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newAvailWidth += aState.mReflowState.availableWidth;
|
|
|
|
}
|
2000-01-03 07:32:13 +03:00
|
|
|
} else {
|
2001-05-19 03:14:36 +04:00
|
|
|
if (NS_UNCONSTRAINEDSIZE != aState.mReflowState.mComputedWidth) {
|
2000-10-10 01:19:36 +04:00
|
|
|
newAvailWidth += aState.mReflowState.mComputedWidth;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newAvailWidth += aState.mReflowState.availableWidth;
|
|
|
|
}
|
2000-01-03 07:32:13 +03:00
|
|
|
}
|
2000-10-10 01:19:36 +04:00
|
|
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != newAvailWidth, "bad math, newAvailWidth is infinite");
|
2000-01-03 07:32:13 +03:00
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": trying to avoid marking all lines dirty\n");
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
|
|
|
#endif
|
2001-10-09 01:51:48 +04:00
|
|
|
|
|
|
|
PRBool wrapping = !aState.GetFlag(BRS_NOWRAP);
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
2001-10-09 01:51:48 +04:00
|
|
|
// We let child blocks make their own decisions the same
|
|
|
|
// way we are here.
|
|
|
|
//
|
|
|
|
// For inline lines with no-wrap, the only way things
|
|
|
|
// could change is if there is a percentage-sized child.
|
2002-08-28 02:31:24 +04:00
|
|
|
// However, right floaters within such lines might need to be
|
|
|
|
// repositioned, so we check for floaters as well.
|
2001-10-09 01:51:48 +04:00
|
|
|
if (line->IsBlock() ||
|
|
|
|
line->HasPercentageChild() ||
|
2002-08-28 02:31:24 +04:00
|
|
|
line->HasFloaters() ||
|
2001-10-09 01:51:48 +04:00
|
|
|
(wrapping &&
|
2001-10-25 05:08:40 +04:00
|
|
|
((line != mLines.back() && !line->HasBreak()) ||
|
2001-10-09 01:51:48 +04:00
|
|
|
line->ResizeReflowOptimizationDisabled() ||
|
|
|
|
line->IsImpactedByFloater() ||
|
|
|
|
(line->mBounds.XMost() > newAvailWidth)))) {
|
1999-10-29 18:34:53 +04:00
|
|
|
line->MarkDirty();
|
|
|
|
}
|
2001-10-09 01:51:48 +04:00
|
|
|
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2001-10-09 01:51:48 +04:00
|
|
|
if (!line->IsBlock()) {
|
|
|
|
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
2000-10-29 02:17:53 +04:00
|
|
|
line, line->IsImpactedByFloater() ? "" : "not ");
|
2001-10-09 01:51:48 +04:00
|
|
|
}
|
2000-03-23 02:19:10 +03:00
|
|
|
#endif
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
2001-10-09 01:51:48 +04:00
|
|
|
if (gNoisyReflow && !line->IsDirty() && wrapping) {
|
|
|
|
IndentBy(stdout, gNoiseIndent + 1);
|
|
|
|
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_STATIC_CAST(void*, line.get()),
|
2002-01-09 06:01:13 +03:00
|
|
|
NS_STATIC_CAST(void*, (line.next() != end_lines() ? line.next().get() : nsnull)),
|
2001-10-09 01:51:48 +04:00
|
|
|
line->IsBlock() ? "block" : "inline",
|
|
|
|
"wrapping",
|
|
|
|
line->HasBreak() ? "has-break " : "",
|
|
|
|
line->HasFloaters() ? "has-floaters " : "",
|
|
|
|
line->IsImpactedByFloater() ? "impacted " : "",
|
|
|
|
line->GetBreakType(),
|
|
|
|
line->mBounds.XMost());
|
1999-09-25 20:50:45 +04:00
|
|
|
}
|
2001-10-09 01:51:48 +04:00
|
|
|
#endif
|
1999-09-25 20:50:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Mark everything dirty
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
1999-09-25 20:50:45 +04:00
|
|
|
line->MarkDirty();
|
|
|
|
}
|
1998-11-05 22:33:01 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-11-05 22:33:01 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//----------------------------------------
|
1998-11-05 22:33:01 +03:00
|
|
|
|
2002-04-26 23:19:39 +04:00
|
|
|
nsBlockFrame::line_iterator
|
|
|
|
nsBlockFrame::FindLineFor(nsIFrame* aFrame)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
// This assertion actually fires on lots of pages (e.g., bugzilla,
|
|
|
|
// bugzilla query page), so limit it to a few people until we fix the
|
|
|
|
// problem causing it. It's related to the similarly |#ifdef|ed
|
|
|
|
// assertion in |PrepareChildIncrementalReflow|.
|
2001-07-04 06:00:05 +04:00
|
|
|
#if defined(DEBUG_dbaron) || defined(DEBUG_waterson)
|
|
|
|
NS_PRECONDITION(aFrame, "why pass a null frame?");
|
|
|
|
#endif
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator line = begin_lines(),
|
|
|
|
line_end = end_lines();
|
|
|
|
for ( ; line != line_end; ++line) {
|
2002-04-26 23:19:39 +04:00
|
|
|
// If the target frame is in-flow, and this line contains the it,
|
|
|
|
// then we've found our line.
|
|
|
|
if (line->Contains(aFrame))
|
|
|
|
return line;
|
|
|
|
|
|
|
|
// If the target frame is floated, and this line contains the
|
|
|
|
// floater's placeholder, then we've found our line.
|
1999-10-15 03:10:03 +04:00
|
|
|
if (line->HasFloaters()) {
|
2002-04-26 23:19:39 +04:00
|
|
|
for (nsFloaterCache *fc = line->GetFirstFloater();
|
|
|
|
fc != nsnull;
|
|
|
|
fc = fc->Next()) {
|
|
|
|
if (aFrame == fc->mPlaceholder->GetOutOfFlowFrame())
|
|
|
|
return line;
|
1998-11-05 22:33:01 +03:00
|
|
|
}
|
2002-04-26 23:19:39 +04:00
|
|
|
}
|
1998-11-05 22:33:01 +03:00
|
|
|
}
|
1999-09-15 04:28:10 +04:00
|
|
|
|
2002-04-26 23:19:39 +04:00
|
|
|
return line_end;
|
1998-11-05 22:33:01 +03:00
|
|
|
}
|
|
|
|
|
2000-08-24 08:26:43 +04: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;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
2001-10-25 05:08:40 +04:00
|
|
|
* Propagate reflow "damage" from from earlier lines to the current
|
|
|
|
* line. The reflow damage comes from the following sources:
|
2002-04-26 23:19:39 +04:00
|
|
|
* 1. The regions of floater damage remembered during reflow.
|
2001-10-25 05:08:40 +04:00
|
|
|
* 2. The combination of nonzero |aDeltaY| and any impact by a floater,
|
|
|
|
* either the previous reflow or now.
|
2001-07-04 06:00:05 +04:00
|
|
|
*
|
2001-10-25 05:08:40 +04:00
|
|
|
* When entering this function, |aLine| is still at its old position and
|
|
|
|
* |aDeltaY| indicates how much it will later be slid (assuming it
|
|
|
|
* doesn't get marked dirty and reflowed entirely).
|
1998-12-05 19:02:08 +03:00
|
|
|
*/
|
|
|
|
void
|
2001-10-25 05:08:40 +04:00
|
|
|
nsBlockFrame::PropagateFloaterDamage(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine,
|
|
|
|
nscoord aDeltaY)
|
1998-08-28 07:02:39 +04:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_PRECONDITION(!aLine->IsDirty(), "should never be called on dirty lines");
|
|
|
|
|
|
|
|
// Check the damage region recorded in the float damage.
|
2001-10-26 09:06:07 +04:00
|
|
|
nsSpaceManager *spaceManager = aState.mReflowState.mSpaceManager;
|
2001-10-25 05:08:40 +04:00
|
|
|
if (spaceManager->HasFloatDamage()) {
|
|
|
|
nscoord lineYA = aLine->mBounds.y + aDeltaY;
|
|
|
|
nscoord lineYB = lineYA + aLine->mBounds.height;
|
|
|
|
if (spaceManager->IntersectsDamage(lineYA, lineYB)) {
|
|
|
|
aLine->MarkDirty();
|
1999-09-15 04:28:10 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1998-08-28 07:02:39 +04:00
|
|
|
|
1999-09-15 04:28:10 +04:00
|
|
|
if (aDeltaY) {
|
2001-10-25 05:08:40 +04:00
|
|
|
// 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
|
|
|
|
// 3. the line is impacted by a floater both before and after and
|
|
|
|
// the floater has changed position relative to the line (or it's
|
|
|
|
// a different floater). (XXXPerf we don't currently
|
|
|
|
// check whether the floater changed size. We currently just
|
|
|
|
// mark blocks dirty and ignore any possibility of damage to
|
|
|
|
// inlines by it being a different floater with a different
|
|
|
|
// size.)
|
|
|
|
//
|
|
|
|
// 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(aLine->mBounds.y + aDeltaY);
|
|
|
|
PRBool wasImpactedByFloater = aLine->IsImpactedByFloater();
|
|
|
|
PRBool isImpactedByFloater = aState.IsImpactedByFloater();
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2001-10-25 05:08:40 +04:00
|
|
|
printf("nsBlockFrame::PropagateFloaterDamage %p was = %d, is=%d\n",
|
|
|
|
this, wasImpactedByFloater, isImpactedByFloater);
|
2000-03-23 02:19:10 +03:00
|
|
|
#endif
|
2001-10-25 05:08:40 +04:00
|
|
|
// Mark the line dirty if:
|
|
|
|
// 1. It used to be impacted by a floater and now isn't, or vice
|
|
|
|
// versa.
|
|
|
|
// 2. It is impacted by a floater and it is a block, which means
|
|
|
|
// that more or less of the line could be impacted than was in
|
|
|
|
// the past. (XXXPerf This could be optimized further, since
|
|
|
|
// we're marking the whole line dirty.)
|
|
|
|
if ((wasImpactedByFloater != isImpactedByFloater) ||
|
|
|
|
(isImpactedByFloater && aLine->IsBlock())) {
|
|
|
|
aLine->MarkDirty();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// NOTE: The first parameter *must* be passed by value.
|
2000-01-08 06:58:27 +03:00
|
|
|
static PRBool
|
2001-10-25 05:08:40 +04:00
|
|
|
WrappedLinesAreDirty(nsLineList::iterator aLine,
|
|
|
|
const nsLineList::iterator aLineEnd)
|
2000-01-08 06:58:27 +03:00
|
|
|
{
|
|
|
|
if (aLine->IsInline()) {
|
|
|
|
while (aLine->IsLineWrapped()) {
|
2001-10-25 05:08:40 +04:00
|
|
|
++aLine;
|
|
|
|
if (aLine == aLineEnd) {
|
2000-01-08 06:58:27 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
static void PlaceFrameView(nsIPresContext* aPresContext, nsIFrame* aFrame);
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
|
|
|
* Reflow the dirty lines
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
1998-06-24 21:52:42 +04:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
PRBool keepGoing = PR_TRUE;
|
2002-04-09 03:57:37 +04:00
|
|
|
PRBool repositionViews = PR_FALSE; // should we really need this?
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
if (aState.mReflowState.reason == eReflowReason_Incremental) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2002-05-10 22:22:41 +04:00
|
|
|
printf(": incrementally reflowing dirty lines");
|
|
|
|
|
|
|
|
nsHTMLReflowCommand *command = aState.mReflowState.path->mReflowCommand;
|
|
|
|
if (command) {
|
|
|
|
nsReflowType type;
|
|
|
|
command->GetType(type);
|
|
|
|
printf(": type=%s(%d)", kReflowCommandType[type], type);
|
|
|
|
}
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflowing dirty lines");
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" computedWidth=%d\n", aState.mReflowState.mComputedWidth);
|
1999-10-16 03:35:10 +04:00
|
|
|
gNoiseIndent++;
|
1999-09-18 03:16:43 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
1998-11-14 22:28:11 +03:00
|
|
|
|
1999-07-14 19:16:56 +04:00
|
|
|
// Check whether this is an incremental reflow
|
|
|
|
PRBool incrementalReflow = aState.mReflowState.reason ==
|
2000-01-12 11:28:24 +03:00
|
|
|
eReflowReason_Incremental ||
|
|
|
|
aState.mReflowState.reason ==
|
|
|
|
eReflowReason_Dirty;
|
1999-07-14 19:16:56 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// the amount by which we will slide the current line if it is not
|
|
|
|
// dirty
|
2000-02-23 01:06:19 +03:00
|
|
|
nscoord deltaY = 0;
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// whether we did NOT reflow the previous line and thus we need to
|
|
|
|
// recompute the carried out margin before the line if we want to
|
|
|
|
// reflow it or if its previous margin is dirty
|
2001-12-06 03:30:06 +03:00
|
|
|
PRBool needToRecoverState = PR_FALSE;
|
2000-02-23 01:06:19 +03:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// Reflow the lines that are already ours
|
|
|
|
line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) {
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsRect lca;
|
|
|
|
line->GetCombinedArea(&lca);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_STATIC_CAST(void*, line.get()), aState.mY,
|
|
|
|
line->IsDirty() ? "yes" : "no",
|
1999-10-16 03:35:10 +04:00
|
|
|
line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
|
|
|
lca.x, lca.y, lca.width, lca.height,
|
2001-10-25 05:08:40 +04:00
|
|
|
deltaY, aState.mPrevBottomMargin.get());
|
1999-10-16 03:35:10 +04:00
|
|
|
gNoiseIndent++;
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
1999-10-16 03:35:10 +04:00
|
|
|
|
2000-01-08 06:58:27 +03: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
|
2002-06-12 07:21:00 +04:00
|
|
|
// are dirty. If we are printing (constrained height), always reflow
|
|
|
|
// the line.
|
2001-11-01 18:31:13 +03:00
|
|
|
if ((NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableHeight) ||
|
|
|
|
(!line->IsDirty() &&
|
|
|
|
aState.GetFlag(BRS_COMPUTEMAXWIDTH) &&
|
2001-10-25 05:08:40 +04:00
|
|
|
::WrappedLinesAreDirty(line, line_end))) {
|
|
|
|
line->MarkDirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure |aState.mPrevBottomMargin| is at the correct position
|
|
|
|
// before calling PropagateFloaterDamage.
|
2001-12-06 03:30:06 +03:00
|
|
|
if (needToRecoverState &&
|
|
|
|
(line->IsDirty() || line->IsPreviousMarginDirty())) {
|
2001-10-25 05:08:40 +04:00
|
|
|
// We need to reconstruct the bottom margin only if we didn't
|
|
|
|
// reflow the previous line and we do need to reflow (or repair
|
|
|
|
// the top position of) the next line.
|
2001-12-06 03:30:06 +03:00
|
|
|
aState.ReconstructMarginAbove(line);
|
2001-10-25 05:08:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (line->IsPreviousMarginDirty() && !line->IsDirty()) {
|
|
|
|
// If the previous margin is dirty and we're not going to reflow
|
|
|
|
// the line we need to pull out the correct top margin and set
|
|
|
|
// |deltaY| correctly.
|
|
|
|
// If there's float damage we might end up doing this work twice,
|
|
|
|
// but whatever...
|
|
|
|
if (line->IsBlock()) {
|
|
|
|
// XXXPerf We could actually make this faster by stealing code
|
|
|
|
// from the top of nsBlockFrame::ReflowBlockFrame, but it's an
|
|
|
|
// edge case that will generally happen at most once in a given
|
|
|
|
// reflow (insertion of a new line before a block)
|
|
|
|
line->MarkDirty();
|
|
|
|
} else {
|
|
|
|
deltaY = aState.mY + aState.mPrevBottomMargin.get() - line->mBounds.y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
line->ClearPreviousMarginDirty();
|
|
|
|
|
|
|
|
// See if there's any reflow damage that requires that we mark the
|
|
|
|
// line dirty.
|
|
|
|
if (!line->IsDirty()) {
|
|
|
|
PropagateFloaterDamage(aState, line, deltaY);
|
|
|
|
}
|
|
|
|
|
2001-12-06 03:30:06 +03:00
|
|
|
if (needToRecoverState) {
|
|
|
|
needToRecoverState = PR_FALSE;
|
|
|
|
|
|
|
|
// Update aState.mPrevChild as if we had reflowed all of the frames in
|
|
|
|
// this line. This is expensive in some cases, since it requires
|
|
|
|
// walking |GetNextSibling|.
|
|
|
|
if (line->IsDirty())
|
|
|
|
aState.mPrevChild = line.prev()->LastChild();
|
|
|
|
}
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// Now repair the line and update |aState.mY| by calling
|
|
|
|
// |ReflowLine| or |SlideLine|.
|
|
|
|
if (line->IsDirty()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Compute the dirty lines "before" YMost, after factoring in
|
|
|
|
// the running deltaY value - the running value is implicit in
|
|
|
|
// aState.mY.
|
2001-10-25 05:08:40 +04:00
|
|
|
nscoord oldY = line->mBounds.y;
|
|
|
|
nscoord oldYMost = line->mBounds.YMost();
|
1999-10-15 03:10:03 +04:00
|
|
|
nsRect oldCombinedArea;
|
|
|
|
line->GetCombinedArea(&oldCombinedArea);
|
1998-12-05 19:02:08 +03:00
|
|
|
|
2000-06-12 02:14:33 +04:00
|
|
|
// Reflow the dirty line. If it's an incremental reflow, then force
|
|
|
|
// it to invalidate the dirty area if necessary
|
2002-03-12 18:48:52 +03:00
|
|
|
PRBool forceInvalidate = incrementalReflow && !aState.GetFlag(BRS_DAMAGECONSTRAINED);
|
2000-06-12 02:14:33 +04:00
|
|
|
rv = ReflowLine(aState, line, &keepGoing, forceInvalidate);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!keepGoing) {
|
1999-10-15 03:10:03 +04:00
|
|
|
if (0 == line->GetChildCount()) {
|
2001-10-25 05:08:40 +04:00
|
|
|
DeleteLine(aState, line, line_end);
|
1998-12-08 01:28:55 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
break;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
if (oldY == 0 && deltaY != line->mBounds.y) {
|
|
|
|
// This means the current line was just reflowed for the first
|
|
|
|
// time. Thus we must mark the the previous margin of the next
|
|
|
|
// line dirty.
|
|
|
|
// XXXldb Move this into where we insert the line! (or will
|
|
|
|
// that mess up deltaY manipulation?)
|
|
|
|
if (line.next() != end_lines()) {
|
|
|
|
line.next()->MarkPreviousMarginDirty();
|
|
|
|
// since it's marked dirty, nobody will care about |deltaY|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
deltaY = line->mBounds.YMost() - oldYMost;
|
1999-07-14 19:16:56 +04:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
} else {
|
|
|
|
if (deltaY != 0)
|
|
|
|
SlideLine(aState, line, deltaY);
|
2002-04-09 03:57:37 +04:00
|
|
|
else
|
|
|
|
repositionViews = PR_TRUE;
|
2001-10-25 05:08:40 +04:00
|
|
|
|
|
|
|
// XXX EVIL O(N^2) EVIL
|
|
|
|
aState.RecoverStateFrom(line, deltaY);
|
|
|
|
|
|
|
|
// Keep mY up to date in case we're propagating reflow damage.
|
|
|
|
aState.mY = line->mBounds.YMost();
|
2001-12-06 03:30:06 +03:00
|
|
|
needToRecoverState = PR_TRUE;
|
1998-09-03 01:59:54 +04:00
|
|
|
}
|
1999-10-16 03:35:10 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
gNoiseIndent--;
|
|
|
|
nsRect lca;
|
|
|
|
line->GetCombinedArea(&lca);
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("line=%p mY=%d newBounds={%d,%d,%d,%d} newCombinedArea={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_STATIC_CAST(void*, line.get()), aState.mY,
|
1999-10-16 03:35:10 +04:00
|
|
|
line->mBounds.x, line->mBounds.y,
|
|
|
|
line->mBounds.width, line->mBounds.height,
|
|
|
|
lca.x, lca.y, lca.width, lca.height,
|
2001-10-25 05:08:40 +04:00
|
|
|
deltaY, aState.mPrevBottomMargin.get());
|
1999-10-16 03:35:10 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
2001-10-25 05:08:40 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
2001-12-06 03:30:06 +03:00
|
|
|
if (needToRecoverState) {
|
2001-10-25 05:08:40 +04:00
|
|
|
// Is this expensive?
|
|
|
|
aState.ReconstructMarginAbove(line);
|
2001-12-06 03:30:06 +03:00
|
|
|
|
|
|
|
// Update aState.mPrevChild as if we had reflowed all of the frames in
|
|
|
|
// this line. This is expensive in some cases, since it requires
|
|
|
|
// walking |GetNextSibling|.
|
|
|
|
aState.mPrevChild = line.prev()->LastChild();
|
1998-06-25 20:33:10 +04:00
|
|
|
}
|
|
|
|
|
2002-04-09 03:57:37 +04:00
|
|
|
// Should we really have to do this?
|
|
|
|
if (repositionViews)
|
|
|
|
::PlaceFrameView(aState.mPresContext, this);
|
|
|
|
|
2001-09-06 00:27:19 +04:00
|
|
|
// Pull data from a next-in-flow if there's still room for more
|
|
|
|
// content here.
|
1998-12-05 19:02:08 +03:00
|
|
|
while (keepGoing && (nsnull != aState.mNextInFlow)) {
|
|
|
|
// Grab first line from our next-in-flow
|
2001-10-25 05:08:40 +04:00
|
|
|
nsBlockFrame* nextInFlow = aState.mNextInFlow;
|
|
|
|
line_iterator nifLine = nextInFlow->begin_lines();
|
|
|
|
if (nifLine == nextInFlow->end_lines()) {
|
1999-02-09 20:31:33 +03:00
|
|
|
aState.mNextInFlow = (nsBlockFrame*) aState.mNextInFlow->mNextInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
continue;
|
1998-11-14 22:28:11 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
// XXX See if the line is not dirty; if it's not maybe we can
|
|
|
|
// avoid the pullup if it can't fit?
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox *toMove = nifLine;
|
|
|
|
nextInFlow->mLines.erase(nifLine);
|
|
|
|
if (0 == toMove->GetChildCount()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// The line is empty. Try the next one.
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(nsnull == toMove->mFirstChild, "bad empty line");
|
|
|
|
aState.FreeLineBox(toMove);
|
1998-12-05 19:02:08 +03:00
|
|
|
continue;
|
1998-11-14 22:28:11 +03:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// XXX move to a subroutine: run-in, overflow, pullframe and this do this
|
|
|
|
// Make the children in the line ours.
|
2001-10-25 05:08:40 +04:00
|
|
|
nsIFrame* frame = toMove->mFirstChild;
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* lastFrame = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 n = toMove->GetChildCount();
|
1998-12-05 19:02:08 +03:00
|
|
|
while (--n >= 0) {
|
1999-01-14 08:16:23 +03:00
|
|
|
frame->SetParent(this);
|
1999-04-11 08:22:00 +04:00
|
|
|
// When pushing and pulling frames we need to check for whether any
|
|
|
|
// views need to be reparented
|
1999-10-26 08:44:41 +04:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, mNextInFlow, this);
|
1998-12-05 19:02:08 +03:00
|
|
|
lastFrame = frame;
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
lastFrame->SetNextSibling(nsnull);
|
1998-11-14 22:28:11 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Add line to our line list
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aState.mPrevChild)
|
|
|
|
aState.mPrevChild->SetNextSibling(toMove->mFirstChild);
|
|
|
|
line = mLines.before_insert(end_lines(), toMove);
|
1998-06-18 20:25:41 +04:00
|
|
|
|
2001-09-21 17:41:52 +04:00
|
|
|
// If line contains floaters, remove them from aState.mNextInFlow's
|
|
|
|
// floater list. They will be pushed onto this blockframe's floater
|
|
|
|
// list, via BuildFloaterList(), when we are done reflowing dirty lines.
|
|
|
|
//
|
|
|
|
// XXX: If the call to BuildFloaterList() is removed from
|
|
|
|
// nsBlockFrame::Reflow(), we'll probably need to manually
|
|
|
|
// append the floaters to |this|'s floater list.
|
|
|
|
|
|
|
|
if (line->HasFloaters()) {
|
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
|
|
|
while (fc) {
|
|
|
|
if (fc->mPlaceholder) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
|
|
|
if (floater)
|
|
|
|
aState.mNextInFlow->mFloaters.RemoveFrame(floater);
|
|
|
|
}
|
|
|
|
fc = fc->Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03: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).
|
2001-10-25 05:08:40 +04:00
|
|
|
while (line != end_lines()) {
|
|
|
|
rv = ReflowLine(aState, line, &keepGoing,
|
|
|
|
incrementalReflow /* force invalidate */);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (!keepGoing) {
|
1999-10-15 03:10:03 +04:00
|
|
|
if (0 == line->GetChildCount()) {
|
2001-10-25 05:08:40 +04:00
|
|
|
DeleteLine(aState, line, line_end);
|
1998-12-08 01:28:55 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
break;
|
|
|
|
}
|
1998-11-14 22:28:11 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// If this is an inline frame then its time to stop
|
2001-10-25 05:08:40 +04:00
|
|
|
++line;
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.AdvanceToNextLine();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
1998-11-14 22:28:11 +03:00
|
|
|
|
1999-07-14 21:26:20 +04:00
|
|
|
// Handle an odd-ball case: a list-item with no lines
|
2001-10-25 05:08:40 +04:00
|
|
|
if (mBullet && HaveOutsideBullet() && mLines.empty()) {
|
1999-08-28 01:45:37 +04: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 21:26:20 +04:00
|
|
|
}
|
|
|
|
|
1999-10-16 03:35:10 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
gNoiseIndent--;
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": done reflowing dirty lines (status=%x)\n",
|
1999-10-16 03:35:10 +04:00
|
|
|
aState.mReflowStatus);
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
1998-06-28 02:56:09 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1998-12-08 01:28:55 +03:00
|
|
|
void
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList::iterator aLine,
|
|
|
|
nsLineList::iterator aLineEnd)
|
1998-12-08 01:28:55 +03:00
|
|
|
{
|
1999-10-15 03:10:03 +04:00
|
|
|
NS_PRECONDITION(0 == aLine->GetChildCount(), "can't delete !empty line");
|
|
|
|
if (0 == aLine->GetChildCount()) {
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(aState.mCurrentLine == aLine,
|
|
|
|
"using function more generally than designed, "
|
|
|
|
"but perhaps OK now");
|
|
|
|
nsLineBox *line = aLine;
|
|
|
|
aLine = mLines.erase(aLine);
|
|
|
|
aState.FreeLineBox(line);
|
|
|
|
// Mark the previous margin of the next line dirty since we need to
|
|
|
|
// recompute its top position.
|
|
|
|
if (aLine != aLineEnd)
|
|
|
|
aLine->MarkPreviousMarginDirty();
|
1998-12-08 01:28:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
|
|
|
* Reflow a line. The line will either contain a single block frame
|
2000-03-23 02:19:10 +03:00
|
|
|
* or contain 1 or more inline frames. aKeepReflowGoing indicates
|
1998-12-05 19:02:08 +03:00
|
|
|
* whether or not the caller should continue to reflow more lines.
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-07-14 19:16:56 +04:00
|
|
|
PRBool* aKeepReflowGoing,
|
1999-08-01 20:50:52 +04:00
|
|
|
PRBool aDamageDirtyArea)
|
1998-11-19 21:09:57 +03:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult rv = NS_OK;
|
1998-11-11 06:55:55 +03:00
|
|
|
|
1999-10-15 03:10:03 +04:00
|
|
|
NS_ABORT_IF_FALSE(aLine->GetChildCount(), "reflowing empty line");
|
1998-11-11 06:55:55 +03:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
// Setup the line-layout for the new line
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mCurrentLine = aLine;
|
|
|
|
aLine->ClearDirty();
|
1998-11-11 06:55:55 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Now that we know what kind of line we have, reflow it
|
1999-10-15 03:10:03 +04:00
|
|
|
nsRect oldCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&oldCombinedArea);
|
1999-07-14 19:16:56 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (aLine->IsBlock()) {
|
1999-03-19 00:03:25 +03:00
|
|
|
rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
|
2002-03-26 23:03:41 +03:00
|
|
|
|
1999-07-14 19:16:56 +04: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 20:50:52 +04:00
|
|
|
if (aDamageDirtyArea) {
|
1999-10-15 03:10:03 +04:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
if ((oldCombinedArea.x != lineCombinedArea.x) ||
|
|
|
|
(oldCombinedArea.y != lineCombinedArea.y)) {
|
2000-06-12 02:14:33 +04:00
|
|
|
// The block has moved, and so to be safe we need to repaint
|
1999-07-14 19:16:56 +04:00
|
|
|
// XXX We need to improve on this...
|
1999-08-01 20:50:52 +04:00
|
|
|
nsRect dirtyRect;
|
1999-10-15 03:10:03 +04:00
|
|
|
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
2000-04-17 18:40:46 +04:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
2000-04-17 18:40:46 +04:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
2001-11-06 04:44:20 +03:00
|
|
|
if (!dirtyRect.IsEmpty()) {
|
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
|
|
|
}
|
1999-07-14 19:16:56 +04:00
|
|
|
|
|
|
|
} else {
|
1999-10-15 03:10:03 +04:00
|
|
|
if (oldCombinedArea.width != lineCombinedArea.width) {
|
1999-08-01 20:50:52 +04:00
|
|
|
nsRect dirtyRect;
|
|
|
|
|
1999-07-14 19:16:56 +04:00
|
|
|
// Just damage the vertical strip that was either added or went
|
|
|
|
// away
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.x = PR_MIN(oldCombinedArea.XMost(),
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.XMost());
|
|
|
|
dirtyRect.y = lineCombinedArea.y;
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.width = PR_MAX(oldCombinedArea.XMost(),
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.XMost()) -
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.x;
|
|
|
|
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.height);
|
2000-04-17 18:40:46 +04:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
2000-04-17 18:40:46 +04:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
2001-11-06 04:44:20 +03:00
|
|
|
if (!dirtyRect.IsEmpty()) {
|
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
|
|
|
}
|
1999-07-14 19:16:56 +04:00
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
if (oldCombinedArea.height != lineCombinedArea.height) {
|
1999-08-01 20:50:52 +04:00
|
|
|
nsRect dirtyRect;
|
|
|
|
|
1999-07-14 19:16:56 +04:00
|
|
|
// Just damage the horizontal strip that was either added or went
|
|
|
|
// away
|
1999-10-15 03:10:03 +04:00
|
|
|
dirtyRect.x = lineCombinedArea.x;
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.y = PR_MIN(oldCombinedArea.YMost(),
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.YMost());
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.width = PR_MAX(oldCombinedArea.width,
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.width);
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.YMost()) -
|
1999-08-01 20:50:52 +04:00
|
|
|
dirtyRect.y;
|
2000-04-17 18:40:46 +04:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
2000-04-17 18:40:46 +04:00
|
|
|
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
|
|
|
#endif
|
2001-11-06 04:44:20 +03:00
|
|
|
if (!dirtyRect.IsEmpty()) {
|
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
|
|
|
}
|
1999-07-14 19:16:56 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
else {
|
2000-01-03 07:32:13 +03:00
|
|
|
aLine->SetLineWrapped(PR_FALSE);
|
2000-01-08 06:58:27 +03: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...
|
2001-10-25 05:08:40 +04:00
|
|
|
PRBool isBeginningLine = aState.mCurrentLine == begin_lines() ||
|
|
|
|
!aState.mCurrentLine.prev()->IsLineWrapped();
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
2001-12-20 04:56:17 +03:00
|
|
|
// First reflow the line with an unconstrained width.
|
2000-01-08 06:58:27 +03:00
|
|
|
nscoord oldY = aState.mY;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCollapsingMargin oldPrevBottomMargin(aState.mPrevBottomMargin);
|
2000-04-17 18:40:46 +04:00
|
|
|
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
2000-01-30 21:42:23 +03:00
|
|
|
|
2002-01-05 04:42:36 +03:00
|
|
|
#ifdef DEBUG_waterson
|
|
|
|
if (oldUnconstrainedWidth)
|
|
|
|
printf("*** oldUnconstrainedWidth was already set.\n");
|
|
|
|
#endif
|
2001-12-20 04:56:17 +03:00
|
|
|
|
|
|
|
// 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 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
2000-04-19 07:12:13 +04:00
|
|
|
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea, PR_TRUE);
|
2000-01-30 21:42:23 +03:00
|
|
|
aState.mY = oldY;
|
|
|
|
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
2000-01-08 06:58:27 +03:00
|
|
|
|
2001-12-20 04:56:17 +03:00
|
|
|
#ifdef DEBUG_waterson
|
|
|
|
// XXXwaterson if oldUnconstrainedWidth was set, why do we need
|
|
|
|
// to do the second reflow, below?
|
|
|
|
if (oldUnconstrainedWidth)
|
|
|
|
printf("+++ possibly doing an unnecessary second-pass unconstrained reflow\n");
|
|
|
|
#endif
|
|
|
|
|
2000-01-08 06:58:27 +03:00
|
|
|
// Update the line's maximum width
|
|
|
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
2000-05-14 08:56:25 +04:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n",
|
2002-09-12 07:44:37 +04:00
|
|
|
this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth);
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
2000-01-08 06:58:27 +03: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 06:12:30 +03: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 18:40:46 +04:00
|
|
|
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
|
|
|
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
2000-05-14 08:56:25 +04:00
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
|
|
|
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
2000-04-19 07:12:13 +04:00
|
|
|
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea);
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
|
|
|
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
2000-01-08 06:58:27 +03:00
|
|
|
|
|
|
|
} else {
|
2000-04-19 07:12:13 +04:00
|
|
|
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing, aDamageDirtyArea);
|
2000-05-14 08:56:25 +04:00
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH))
|
|
|
|
{
|
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaximumWidth to %d\n",
|
2002-09-12 07:44:37 +04:00
|
|
|
this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaximumWidth);
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
|
|
|
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
}
|
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE))
|
|
|
|
{
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf("nsBlockFrame::ReflowLine block %p line %p setting aLine.mMaxElementWidth to %d\n",
|
2002-09-12 07:44:37 +04:00
|
|
|
this, NS_STATIC_CAST(void*, aLine.get()), aLine->mMaxElementWidth);
|
2002-07-01 21:43:02 +04:00
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
|
|
|
aState.UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
|
|
|
}
|
|
|
|
}
|
2000-01-08 06:58:27 +03:00
|
|
|
}
|
1999-07-14 19:16:56 +04: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 08:26:43 +04: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-15 03:10:03 +04:00
|
|
|
nsRect combinedArea;
|
|
|
|
aLine->GetCombinedArea(&combinedArea);
|
1999-08-01 20:50:52 +04:00
|
|
|
|
1999-10-15 03:10:03 +04:00
|
|
|
nsRect dirtyRect;
|
|
|
|
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
2000-04-17 18:40:46 +04:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p invalidate because %s is true (%d, %d, %d, %d)\n",
|
2000-09-15 10:20:07 +04:00
|
|
|
this, aDamageDirtyArea ? "aDamageDirtyArea" : "aLine->IsForceInvalidate",
|
|
|
|
dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
2000-10-27 18:14:36 +04:00
|
|
|
if (aLine->IsForceInvalidate())
|
2002-09-12 07:44:37 +04:00
|
|
|
printf(" dirty line is %p\n", NS_STATIC_CAST(void*, aLine.get());
|
2000-04-17 18:40:46 +04:00
|
|
|
#endif
|
2001-11-06 04:44:20 +03:00
|
|
|
if (!dirtyRect.IsEmpty()) {
|
|
|
|
Invalidate(aState.mPresContext, dirtyRect);
|
|
|
|
}
|
1999-07-14 19:16:56 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1998-11-14 22:28:11 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
|
|
|
* Pull frame from the next available location (one of our lines or
|
|
|
|
* one of our next-in-flows lines).
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PullFrame(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
2000-04-19 07:12:13 +04:00
|
|
|
PRBool aDamageDeletedLines,
|
1999-03-16 22:36:00 +03:00
|
|
|
nsIFrame*& aFrameResult)
|
1998-11-14 22:28:11 +03:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
aFrameResult = nsnull;
|
|
|
|
|
|
|
|
// First check our remaining lines
|
2002-01-03 01:10:13 +03:00
|
|
|
if (end_lines() != aLine.next()) {
|
|
|
|
return PullFrameFrom(aState, aLine, mLines, aLine.next(), PR_FALSE,
|
|
|
|
aDamageDeletedLines, aFrameResult);
|
1998-11-14 22:28:11 +03:00
|
|
|
}
|
1998-11-17 04:04:45 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Pull frames from the next-in-flow(s) until we can't
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame* nextInFlow = aState.mNextInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != nextInFlow) {
|
2002-01-03 01:10:13 +03:00
|
|
|
if (! nextInFlow->mLines.empty()) {
|
|
|
|
return PullFrameFrom(aState, aLine, nextInFlow->mLines,
|
|
|
|
nextInFlow->mLines.begin(), PR_TRUE,
|
|
|
|
aDamageDeletedLines, aFrameResult);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
2002-01-03 01:10:13 +03:00
|
|
|
|
|
|
|
nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
|
|
|
|
aState.mNextInFlow = nextInFlow;
|
1998-11-17 04:04:45 +03:00
|
|
|
}
|
2002-01-03 01:10:13 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
1998-11-14 22:28:11 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
2001-10-25 05:08:40 +04:00
|
|
|
* Try to pull a frame out of a line pointed at by aFromLine. If a frame
|
|
|
|
* is pulled then aPulled will be set to PR_TRUE. In addition, if
|
|
|
|
* aUpdateGeometricParent is set then the pulled frames geometric parent
|
|
|
|
* will be updated (e.g. when pulling from a next-in-flows line list).
|
1998-12-05 19:02:08 +03:00
|
|
|
*
|
|
|
|
* 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
|
2001-07-04 06:00:05 +04:00
|
|
|
nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine,
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList& aFromContainer,
|
|
|
|
nsLineList::iterator aFromLine,
|
2001-07-04 06:00:05 +04:00
|
|
|
PRBool aUpdateGeometricParent,
|
|
|
|
PRBool aDamageDeletedLines,
|
2002-01-03 01:10:13 +03:00
|
|
|
nsIFrame*& aFrameResult)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* fromLine = aFromLine;
|
1999-10-15 03:10:03 +04: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 19:02:08 +03: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.
|
|
|
|
aFrameResult = nsnull;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Take frame from fromLine
|
|
|
|
nsIFrame* frame = fromLine->mFirstChild;
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
|
|
|
|
|
|
|
PRInt32 fromLineChildCount = fromLine->GetChildCount();
|
|
|
|
if (0 != --fromLineChildCount) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Mark line dirty now that we pulled a child
|
1999-10-15 03:10:03 +04:00
|
|
|
fromLine->SetChildCount(fromLineChildCount);
|
1998-12-05 19:02:08 +03:00
|
|
|
fromLine->MarkDirty();
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&fromLine->mFirstChild);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
else {
|
2002-03-26 23:03:41 +03:00
|
|
|
nsRect combinedArea;
|
|
|
|
fromLine->GetCombinedArea(&combinedArea);
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Free up the fromLine now that it's empty
|
2000-04-19 07:12:13 +04:00
|
|
|
// Its bounds might need to be redrawn, though.
|
2001-11-06 04:44:20 +03:00
|
|
|
if (aDamageDeletedLines && !fromLine->mBounds.IsEmpty()) {
|
2000-04-19 07:12:13 +04:00
|
|
|
Invalidate(aState.mPresContext, fromLine->mBounds);
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aFromLine.next() != end_lines())
|
|
|
|
aFromLine.next()->MarkPreviousMarginDirty();
|
2002-03-26 23:03:41 +03:00
|
|
|
Invalidate(aState.mPresContext, combinedArea);
|
2001-10-25 05:08:40 +04:00
|
|
|
aFromContainer.erase(aFromLine);
|
1999-10-20 03:04:19 +04:00
|
|
|
aState.FreeLineBox(fromLine);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Change geometric parents
|
|
|
|
if (aUpdateGeometricParent) {
|
1999-04-11 08:22:00 +04:00
|
|
|
// Before we set the new parent frame get the current parent
|
|
|
|
nsIFrame* oldParentFrame;
|
|
|
|
frame->GetParent(&oldParentFrame);
|
1999-01-14 08:16:23 +03:00
|
|
|
frame->SetParent(this);
|
1998-12-05 19:02:08 +03:00
|
|
|
|
1999-04-11 08:22:00 +04: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 08:44:41 +04:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aState.mPresContext, frame, oldParentFrame, this);
|
1999-04-11 08:22:00 +04:00
|
|
|
|
1998-12-05 19:02:08 +03: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 21:52:42 +04:00
|
|
|
}
|
1998-09-24 00:10:40 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Stop pulling because we found a frame to pull
|
|
|
|
aFrameResult = frame;
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-09-24 00:10:40 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-09-24 00:10:40 +04:00
|
|
|
|
1999-11-19 18:33:29 +03:00
|
|
|
static void
|
|
|
|
PlaceFrameView(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsIView* view;
|
|
|
|
aFrame->GetView(aPresContext, &view);
|
2001-09-21 04:53:29 +04:00
|
|
|
if (view)
|
1999-11-19 18:33:29 +03:00
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull);
|
2001-09-21 04:53:29 +04:00
|
|
|
|
|
|
|
nsContainerFrame::PositionChildViews(aPresContext, aFrame);
|
1999-11-19 18:33:29 +03:00
|
|
|
}
|
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
void
|
1999-09-16 23:56:36 +04:00
|
|
|
nsBlockFrame::SlideLine(nsBlockReflowState& aState,
|
1999-04-03 22:59:01 +04:00
|
|
|
nsLineBox* aLine, nscoord aDY)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_PRECONDITION(aDY != 0, "why slide a line nowhere?");
|
|
|
|
|
2002-06-04 01:35:54 +04:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
|
|
|
|
PRBool doInvalidate = !lineCombinedArea.IsEmpty();
|
2001-10-25 05:08:40 +04:00
|
|
|
if (doInvalidate)
|
2002-06-04 01:35:54 +04:00
|
|
|
Invalidate(aState.mPresContext, lineCombinedArea);
|
1999-09-15 04:28:10 +04:00
|
|
|
// Adjust line state
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SlideBy(aDY);
|
2002-06-04 01:35:54 +04:00
|
|
|
if (doInvalidate) {
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
Invalidate(aState.mPresContext, lineCombinedArea);
|
|
|
|
}
|
1999-09-15 04:28:10 +04:00
|
|
|
|
|
|
|
// Adjust the frames in the line
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* kid = aLine->mFirstChild;
|
1999-09-15 04:28:10 +04:00
|
|
|
if (!kid) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aLine->IsBlock()) {
|
1999-09-16 23:56:36 +04:00
|
|
|
if (aDY) {
|
2002-01-06 21:14:00 +03:00
|
|
|
nsPoint p;
|
|
|
|
kid->GetOrigin(p);
|
|
|
|
p.y += aDY;
|
|
|
|
kid->MoveTo(aState.mPresContext, p.x, p.y);
|
1999-09-16 23:56:36 +04:00
|
|
|
}
|
1998-11-21 01:24:20 +03:00
|
|
|
|
1999-11-19 18:33:29 +03:00
|
|
|
// Make sure the frame's view and any child views are updated
|
|
|
|
::PlaceFrameView(aState.mPresContext, kid);
|
1998-09-23 06:25:26 +04:00
|
|
|
}
|
1999-09-15 04:28:10 +04:00
|
|
|
else {
|
1999-11-19 18:33:29 +03: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
|
|
|
|
PRInt32 n = aLine->GetChildCount();
|
|
|
|
while (--n >= 0) {
|
|
|
|
if (aDY) {
|
2002-01-06 21:14:00 +03:00
|
|
|
nsPoint p;
|
|
|
|
kid->GetOrigin(p);
|
|
|
|
p.y += aDY;
|
|
|
|
kid->MoveTo(aState.mPresContext, p.x, p.y);
|
1999-09-15 04:28:10 +04:00
|
|
|
}
|
1999-11-19 18:33:29 +03:00
|
|
|
// Make sure the frame's view and any child views are updated
|
|
|
|
::PlaceFrameView(aState.mPresContext, kid);
|
|
|
|
kid->GetNextSibling(&kid);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-09-23 06:25:26 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
|
1999-02-23 22:18:12 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::AttributeChanged(nsIPresContext* aPresContext,
|
|
|
|
nsIContent* aChild,
|
1999-10-16 03:16:45 +04:00
|
|
|
PRInt32 aNameSpaceID,
|
1999-02-23 22:18:12 +03:00
|
|
|
nsIAtom* aAttribute,
|
2001-08-25 06:01:08 +04:00
|
|
|
PRInt32 aModType,
|
1999-02-23 22:18:12 +03:00
|
|
|
PRInt32 aHint)
|
|
|
|
{
|
|
|
|
nsresult rv = nsBlockFrameSuper::AttributeChanged(aPresContext, aChild,
|
2001-08-25 06:01:08 +04:00
|
|
|
aNameSpaceID, aAttribute, aModType, aHint);
|
1999-02-23 22:18:12 +03:00
|
|
|
|
2001-07-04 06:00:05 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
1999-02-23 22:18:12 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (nsHTMLAtoms::start == aAttribute) {
|
1999-03-05 22:25:44 +03:00
|
|
|
// XXX Not sure if this is necessary anymore
|
2000-01-22 04:16:50 +03:00
|
|
|
RenumberLists(aPresContext);
|
1999-02-23 22:18:12 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
|
2001-12-18 01:39:59 +03:00
|
|
|
nsHTMLReflowCommand* reflowCmd;
|
1999-02-23 22:18:12 +03:00
|
|
|
rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
|
2001-12-18 01:39:59 +03:00
|
|
|
eReflowType_ContentChanged,
|
1999-02-23 22:18:12 +03:00
|
|
|
nsnull,
|
|
|
|
aAttribute);
|
2001-12-18 01:39:59 +03:00
|
|
|
if (NS_SUCCEEDED(rv))
|
1999-02-23 22:18:12 +03:00
|
|
|
shell->AppendReflowCommand(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.
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb I think that's a bad assumption.
|
2001-10-25 05:08:40 +04:00
|
|
|
while (nextAncestor) {
|
1999-02-23 22:18:12 +03:00
|
|
|
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 22:25:44 +03:00
|
|
|
// XXX Not sure if this is necessary anymore
|
2000-01-22 04:16:50 +03:00
|
|
|
blockParent->RenumberLists(aPresContext);
|
1999-02-23 22:18:12 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
|
2001-12-18 01:39:59 +03:00
|
|
|
nsHTMLReflowCommand* reflowCmd;
|
1999-02-23 22:18:12 +03:00
|
|
|
rv = NS_NewHTMLReflowCommand(&reflowCmd, blockParent,
|
2001-12-18 01:39:59 +03:00
|
|
|
eReflowType_ContentChanged,
|
1999-02-23 22:18:12 +03:00
|
|
|
nsnull,
|
|
|
|
aAttribute);
|
2001-12-18 01:39:59 +03:00
|
|
|
if (NS_SUCCEEDED(rv))
|
1999-02-23 22:18:12 +03:00
|
|
|
shell->AppendReflowCommand(reflowCmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
inline PRBool
|
|
|
|
IsBorderZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
|
|
|
|
{
|
|
|
|
return ((aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PRBool
|
|
|
|
IsPaddingZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
|
|
|
|
{
|
|
|
|
return (aUnit == eStyleUnit_Null ||
|
|
|
|
(aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
|
|
|
|
(aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline PRBool
|
|
|
|
IsMarginZero(nsStyleUnit aUnit, nsStyleCoord &aCoord)
|
|
|
|
{
|
|
|
|
return (aUnit == eStyleUnit_Null ||
|
|
|
|
aUnit == eStyleUnit_Auto ||
|
|
|
|
(aUnit == eStyleUnit_Coord && aCoord.GetCoordValue() == 0) ||
|
|
|
|
(aUnit == eStyleUnit_Percent && aCoord.GetPercentValue() == 0.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2002-06-26 01:16:17 +04:00
|
|
|
nsBlockFrame::IsEmpty(nsCompatibility aCompatMode, PRBool aIsPre,
|
|
|
|
PRBool *aResult)
|
2001-10-25 05:08:40 +04:00
|
|
|
{
|
|
|
|
// XXXldb In hindsight, I'm not sure why I made this check the margin,
|
|
|
|
// but it seems to work right and I'm a little hesitant to change it.
|
|
|
|
const nsStyleMargin* margin = NS_STATIC_CAST(const nsStyleMargin*,
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Margin));
|
|
|
|
const nsStyleBorder* border = NS_STATIC_CAST(const nsStyleBorder*,
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Border));
|
|
|
|
const nsStylePadding* padding = NS_STATIC_CAST(const nsStylePadding*,
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Padding));
|
|
|
|
nsStyleCoord coord;
|
|
|
|
if ((border->IsBorderSideVisible(NS_SIDE_TOP) &&
|
|
|
|
!IsBorderZero(border->mBorder.GetTopUnit(),
|
|
|
|
border->mBorder.GetTop(coord))) ||
|
|
|
|
(border->IsBorderSideVisible(NS_SIDE_BOTTOM) &&
|
|
|
|
!IsBorderZero(border->mBorder.GetTopUnit(),
|
|
|
|
border->mBorder.GetTop(coord))) ||
|
|
|
|
!IsPaddingZero(padding->mPadding.GetTopUnit(),
|
|
|
|
padding->mPadding.GetTop(coord)) ||
|
|
|
|
!IsPaddingZero(padding->mPadding.GetBottomUnit(),
|
|
|
|
padding->mPadding.GetBottom(coord)) ||
|
|
|
|
!IsMarginZero(margin->mMargin.GetTopUnit(),
|
|
|
|
margin->mMargin.GetTop(coord)) ||
|
|
|
|
!IsMarginZero(margin->mMargin.GetBottomUnit(),
|
|
|
|
margin->mMargin.GetBottom(coord))) {
|
|
|
|
*aResult = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const nsStyleText* styleText = NS_STATIC_CAST(const nsStyleText*,
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text));
|
|
|
|
PRBool isPre =
|
|
|
|
((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
|
|
|
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace));
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
2002-06-26 01:16:17 +04:00
|
|
|
line->IsEmpty(aCompatMode, isPre, aResult);
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! *aResult)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-03-27 04:22:14 +03:00
|
|
|
PRBool
|
|
|
|
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
|
|
|
nsLineBox* aLine)
|
|
|
|
{
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
1999-03-27 04:22:14 +03: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 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
1999-03-27 04:22:14 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if this line is "essentially" the first line
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines();
|
|
|
|
line != aLine;
|
|
|
|
++line) {
|
1999-03-27 04:22:14 +03:00
|
|
|
if (line->IsBlock()) {
|
|
|
|
// A line which preceeds aLine contains a block; therefore the
|
|
|
|
// top margin applies.
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb this is wrong if that block is empty and the margin
|
|
|
|
// is collapsed outside the parent
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
1999-03-27 04:22:14 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2000-09-05 01:44:48 +04:00
|
|
|
// No need to apply the top margin if the line has floaters. We
|
|
|
|
// should collapse anyway (bug 44419)
|
1999-03-27 04:22:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
nsIFrame* firstChild = mLines.empty() ? nsnull : mLines.front()->mFirstChild;
|
1999-03-27 04:22:14 +03:00
|
|
|
if (firstChild) {
|
2001-10-25 05:08:40 +04:00
|
|
|
if (mLines.front()->IsBlock()) {
|
1999-03-27 04:22:14 +03:00
|
|
|
// 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.
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator next = begin_lines();
|
|
|
|
++next;
|
|
|
|
if ((next == end_lines()) || !next->IsBlock()) {
|
1999-03-27 04:22:14 +03:00
|
|
|
// 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 08:10:27 +04:00
|
|
|
if ((NS_STYLE_WHITESPACE_PRE == styleText->mWhiteSpace) ||
|
|
|
|
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == styleText->mWhiteSpace)) {
|
1999-03-27 04:22:14 +03:00
|
|
|
// Whitespace is significant
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if each frame is a text frame that contains nothing but
|
|
|
|
// whitespace.
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 n = mLines.front()->GetChildCount();
|
1999-03-27 04:22:14 +03:00
|
|
|
while (--n >= 0) {
|
2002-05-23 04:00:34 +04:00
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
firstChild->GetContent(getter_AddRefs(content));
|
|
|
|
if (!content) {
|
2001-05-19 15:26:46 +04:00
|
|
|
return nsnull;
|
|
|
|
}
|
2002-05-23 04:00:34 +04:00
|
|
|
|
2001-05-19 15:26:46 +04:00
|
|
|
if (!content->IsContentOfType(nsIContent::eTEXT)) {
|
1999-03-27 04:22:14 +03:00
|
|
|
return nsnull;
|
|
|
|
}
|
2002-05-23 04:00:34 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsITextContent> tc(do_QueryInterface(content));
|
|
|
|
|
|
|
|
NS_ASSERTION(tc, "Huh, eTEXT content not an nsITextContent!");
|
|
|
|
|
|
|
|
if (!tc) {
|
1999-03-27 05:56:52 +03:00
|
|
|
return nsnull;
|
1999-03-27 04:22:14 +03:00
|
|
|
}
|
2002-05-23 04:00:34 +04:00
|
|
|
|
1999-03-27 04:22:14 +03:00
|
|
|
PRBool isws = PR_FALSE;
|
|
|
|
tc->IsOnlyWhitespace(&isws);
|
2002-05-23 04:00:34 +04:00
|
|
|
|
1999-03-27 04:22:14 +03:00
|
|
|
if (!isws) {
|
1999-03-27 05:56:52 +03:00
|
|
|
return nsnull;
|
1999-03-27 04:22:14 +03:00
|
|
|
}
|
2002-05-23 04:00:34 +04:00
|
|
|
|
1999-03-27 04:22:14 +03: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;
|
|
|
|
}
|
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
// If placeholders/floaters split during reflowing a line, but that line will
|
|
|
|
// be put on the next page, then put the placeholders/floaters back the way
|
|
|
|
// they were before the line was reflowed.
|
|
|
|
static void
|
|
|
|
UndoPlaceholders(nsBlockReflowState& aState,
|
|
|
|
nsIFrame* aLastPlaceholder)
|
|
|
|
{
|
|
|
|
nsIFrame* undoPlaceholder = nsnull;
|
|
|
|
if (aLastPlaceholder) {
|
|
|
|
aLastPlaceholder->GetNextSibling(&undoPlaceholder);
|
|
|
|
aLastPlaceholder->SetNextSibling(nsnull);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
undoPlaceholder = aState.mOverflowFloaters.FirstChild();
|
|
|
|
aState.mOverflowFloaters.SetFrames(nsnull);
|
|
|
|
}
|
|
|
|
// remove the next in flows of the placeholders that need to be removed
|
|
|
|
for (nsIFrame* placeholder = undoPlaceholder; placeholder; ) {
|
|
|
|
nsSplittableFrame::RemoveFromFlow(placeholder);
|
|
|
|
nsIFrame* savePlaceholder = placeholder;
|
|
|
|
placeholder->GetNextSibling(&placeholder);
|
|
|
|
savePlaceholder->Destroy(aState.mPresContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine aNewBreakType with aOrigBreakType, but limit the break types
|
|
|
|
// to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT. When there is a <BR> right
|
|
|
|
// after a floater and the floater splits, then the <BR>'s break type is combined
|
|
|
|
// with the break type of the frame right after the floaters next-in-flow.
|
|
|
|
static PRUint8
|
|
|
|
CombineBreakType(PRUint8 aOrigBreakType,
|
|
|
|
PRUint8 aNewBreakType)
|
|
|
|
{
|
|
|
|
PRUint8 breakType = aOrigBreakType;
|
|
|
|
switch(breakType) {
|
|
|
|
case NS_STYLE_CLEAR_LEFT:
|
|
|
|
if ((NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
|
|
|
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
|
|
|
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_STYLE_CLEAR_RIGHT:
|
|
|
|
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
|
|
|
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
|
|
|
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_STYLE_CLEAR_NONE:
|
|
|
|
if ((NS_STYLE_CLEAR_LEFT == aNewBreakType) ||
|
|
|
|
(NS_STYLE_CLEAR_RIGHT == aNewBreakType) ||
|
|
|
|
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == aNewBreakType)) {
|
|
|
|
breakType = NS_STYLE_CLEAR_LEFT_AND_RIGHT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return breakType;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-02-12 20:45:58 +03:00
|
|
|
PRBool* aKeepReflowGoing)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-02-12 20:45:58 +03:00
|
|
|
NS_PRECONDITION(*aKeepReflowGoing, "bad caller");
|
1998-07-11 01:45:30 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult rv = NS_OK;
|
1998-11-18 01:28:51 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
2002-04-26 00:53:32 +04:00
|
|
|
if (!frame) {
|
|
|
|
NS_ASSERTION(PR_FALSE, "program error - unexpected empty line");
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
|
1999-03-24 18:42:19 +03:00
|
|
|
// Prepare the block reflow engine
|
1998-12-05 19:02:08 +03:00
|
|
|
const nsStyleDisplay* display;
|
|
|
|
frame->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&) display);
|
1999-03-05 07:21:32 +03:00
|
|
|
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
|
|
|
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
1998-12-05 19:02:08 +03:00
|
|
|
|
1999-03-27 04:22:14 +03: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-10-13 03:24:22 +04:00
|
|
|
PRUint8 breakType = display->mBreakType;
|
2002-07-17 05:48:56 +04:00
|
|
|
// If a floater split and its prev-in-flow was followed by a <BR>, then combine
|
|
|
|
// the <BR>'s break type with the block's break type (the block will be the very
|
|
|
|
// next frame after the split floater).
|
|
|
|
if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
|
|
|
|
breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
|
|
|
|
aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
|
|
|
|
}
|
|
|
|
// Clear past floaters before the block if the clear style is not none
|
1999-10-13 03:24:22 +04:00
|
|
|
aLine->SetBreakType(breakType);
|
|
|
|
if (NS_STYLE_CLEAR_NONE != breakType) {
|
|
|
|
PRBool alsoApplyTopMargin = aState.ClearPastFloaters(breakType);
|
1999-09-18 03:16:43 +04:00
|
|
|
if (alsoApplyTopMargin) {
|
|
|
|
applyTopMargin = PR_TRUE;
|
|
|
|
}
|
1999-09-16 23:56:36 +04:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": y=%d child ", aState.mY);
|
1999-09-16 23:56:36 +04:00
|
|
|
ListTag(stdout, frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" has clear of %d => %s, mPrevBottomMargin=%d\n",
|
1999-10-15 03:10:03 +04:00
|
|
|
breakType,
|
1999-09-16 23:56:36 +04:00
|
|
|
applyTopMargin ? "applyTopMargin" : "nope",
|
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-08-05 01:18:16 +04:00
|
|
|
|
1999-10-16 03:35:10 +04: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
|
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
// Setup a reflowState to get the style computed margin-top
|
|
|
|
// value. We'll use a reason of `resize' so that we don't fudge
|
|
|
|
// any incremental reflow state.
|
1999-10-16 03:35:10 +04:00
|
|
|
|
|
|
|
// 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 09:03:41 +03:00
|
|
|
nsHTMLReflowState reflowState(aState.mPresContext, aState.mReflowState,
|
2002-05-10 22:22:41 +04:00
|
|
|
frame, availSpace, eReflowReason_Resize);
|
1999-10-16 03:35:10 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// Now compute the collapsed margin-top value into aState.mPrevBottomMargin
|
|
|
|
nsCollapsingMargin oldPrevBottomMargin = aState.mPrevBottomMargin;
|
|
|
|
nsBlockReflowContext::ComputeCollapsedTopMargin(aState.mPresContext,
|
|
|
|
reflowState,
|
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
topMargin = aState.mPrevBottomMargin.get();
|
|
|
|
aState.mPrevBottomMargin = oldPrevBottomMargin; // perhaps not needed
|
1999-10-16 03:35:10 +04:00
|
|
|
|
|
|
|
// 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 19:02:08 +03:00
|
|
|
// Compute the available space for the block
|
1999-10-16 03:35:10 +04:00
|
|
|
aState.GetAvailableSpace();
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false");
|
2000-03-23 02:19:10 +03:00
|
|
|
#endif
|
|
|
|
PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE;
|
|
|
|
aLine->SetLineIsImpactedByFloater(isImpacted);
|
1999-04-03 22:59:01 +04:00
|
|
|
nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE;
|
|
|
|
frame->IsSplittable(splitType);
|
|
|
|
nsRect availSpace;
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.ComputeBlockAvailSpace(frame, splitType, display, availSpace);
|
1998-11-18 01:28:51 +03:00
|
|
|
|
1999-10-16 03:35:10 +04: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
// keep track of the last overflow floater in case we need to undo any new additions
|
|
|
|
nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Reflow the block into the available space
|
1999-06-08 04:30:26 +04:00
|
|
|
nsReflowStatus frameReflowStatus=NS_FRAME_COMPLETE;
|
1999-01-16 23:58:17 +03:00
|
|
|
nsMargin computedOffsets;
|
2002-09-04 10:55:40 +04:00
|
|
|
// construct the html reflow state for the block. ReflowBlock
|
|
|
|
// will initialize it and set its reason.
|
|
|
|
nsHTMLReflowState blockHtmlRS(aState.mPresContext, aState.mReflowState, frame,
|
|
|
|
nsSize(availSpace.width, availSpace.height),
|
|
|
|
aState.mReflowState.reason, PR_FALSE);
|
|
|
|
rv = brc.ReflowBlock(availSpace, applyTopMargin, aState.mPrevBottomMargin,
|
|
|
|
aState.IsAdjacentWithTop(), computedOffsets,
|
|
|
|
blockHtmlRS, frameReflowStatus);
|
2002-07-17 05:48:56 +04:00
|
|
|
|
2001-11-06 04:44:20 +03:00
|
|
|
if (brc.BlockShouldInvalidateItself() && !mRect.IsEmpty()) {
|
2000-05-09 09:06:16 +04:00
|
|
|
Invalidate(aState.mPresContext, mRect);
|
|
|
|
}
|
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
// Remove the frame from the reflow tree.
|
|
|
|
if (aState.mReflowState.path)
|
|
|
|
aState.mReflowState.path->RemoveChild(frame);
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
aState.mPrevChild = frame;
|
1998-11-18 01:28:51 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
#if defined(REFLOW_STATUS_COVERAGE)
|
1999-02-09 20:31:33 +03:00
|
|
|
RecordReflowStatus(PR_TRUE, frameReflowStatus);
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
1998-11-18 01:28:51 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
|
|
|
|
// None of the child block fits.
|
2002-07-17 05:48:56 +04:00
|
|
|
::UndoPlaceholders(aState, lastPlaceholder);
|
2001-10-25 05:08:40 +04:00
|
|
|
PushLines(aState, aLine.prev());
|
1999-02-12 20:45:58 +03:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
else {
|
1998-12-11 18:49:07 +03:00
|
|
|
// Note: line-break-after a block is a nop
|
1998-12-05 19:02:08 +03:00
|
|
|
|
|
|
|
// Try to place the child block
|
|
|
|
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCollapsingMargin collapsedBottomMargin;
|
2000-02-23 01:06:19 +03:00
|
|
|
nsRect combinedArea(0,0,0,0);
|
2002-09-04 10:55:40 +04:00
|
|
|
*aKeepReflowGoing = brc.PlaceBlock(blockHtmlRS, isAdjacentWithTop, computedOffsets,
|
2001-12-07 17:51:12 +03:00
|
|
|
collapsedBottomMargin, aLine->mBounds, combinedArea);
|
2001-10-25 05:08:40 +04:00
|
|
|
aLine->SetCarriedOutBottomMargin(collapsedBottomMargin);
|
2000-03-14 07:03:33 +03:00
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2001-07-04 06:00:05 +04:00
|
|
|
// Mark the line as dirty so once we known the final shrink wrap width
|
2000-01-03 07:32:13 +03:00
|
|
|
// we can reflow the block to the correct size
|
|
|
|
// XXX We don't always need to do this...
|
|
|
|
aLine->MarkDirty();
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-03-14 07:03:33 +03:00
|
|
|
}
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2001-07-04 06:00:05 +04:00
|
|
|
// Add the right margin to the line's bounds. That way it will be
|
|
|
|
// taken into account when we compute our shrink wrap size.
|
2000-01-03 07:32:13 +03:00
|
|
|
nscoord marginRight = brc.GetMargin().right;
|
|
|
|
if (marginRight != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
aLine->mBounds.width += marginRight;
|
|
|
|
}
|
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SetCombinedArea(combinedArea);
|
1999-02-12 20:45:58 +03:00
|
|
|
if (*aKeepReflowGoing) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Some of the child block fit
|
|
|
|
|
|
|
|
// Advance to new Y position
|
|
|
|
nscoord newY = aLine->mBounds.YMost();
|
|
|
|
aState.mY = newY;
|
|
|
|
|
|
|
|
// Continue the block frame now if it didn't completely fit in
|
|
|
|
// the available space.
|
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
PRBool madeContinuation;
|
2002-05-29 02:50:43 +04:00
|
|
|
rv = CreateContinuationFor(aState, nsnull, frame, madeContinuation);
|
|
|
|
if (NS_FAILED(rv))
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
1998-11-20 20:18:58 +03:00
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
// Push continuation to a new line, but only if we actually made one.
|
1998-12-05 19:02:08 +03:00
|
|
|
if (madeContinuation) {
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1999-10-20 03:04:19 +04:00
|
|
|
nsLineBox* line = aState.NewLineBox(frame, 1, PR_TRUE);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (nsnull == line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1998-10-17 00:22:39 +04:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.after_insert(aLine, line);
|
2002-05-29 02:50:43 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
|
|
|
|
// Advance to next line since some of the block fit. That way
|
|
|
|
// only the following lines will be pushed.
|
2001-10-25 05:08:40 +04:00
|
|
|
PushLines(aState, aLine);
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
1999-02-12 20:45:58 +03:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-12-05 19:02:08 +03: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 22:52:56 +04:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflow incomplete, frame=");
|
1999-09-10 22:52:56 +04:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" prevBottomMargin=%d, setting to zero\n",
|
1999-09-10 22:52:56 +04:00
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
2001-10-25 05:08:40 +04:00
|
|
|
aState.mPrevBottomMargin.Zero();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-09-10 22:52:56 +04:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflow complete for ");
|
1999-09-10 22:52:56 +04:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" prevBottomMargin=%d collapsedBottomMargin=%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
aState.mPrevBottomMargin, collapsedBottomMargin.get());
|
1999-09-10 22:52:56 +04:00
|
|
|
#endif
|
2000-06-30 02:03:42 +04:00
|
|
|
aState.mPrevBottomMargin = collapsedBottomMargin;
|
1998-11-06 05:09:21 +03:00
|
|
|
}
|
1999-03-27 04:22:14 +03:00
|
|
|
#ifdef NOISY_VERTICAL_MARGINS
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": frame=");
|
1999-03-27 04:22:14 +03:00
|
|
|
nsFrame::ListTag(stdout, frame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
brc.GetCarriedOutBottomMargin(), collapsedBottomMargin.get(),
|
1999-03-27 04:22:14 +03:00
|
|
|
aState.mPrevBottomMargin);
|
|
|
|
#endif
|
1998-11-06 05:09:21 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Post-process the "line"
|
1999-04-10 21:31:45 +04:00
|
|
|
nsSize maxElementSize(0, 0);
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
1999-04-10 21:31:45 +04:00
|
|
|
maxElementSize = brc.GetMaxElementSize();
|
1999-10-15 03:10:03 +04:00
|
|
|
if (aState.IsImpactedByFloater() &&
|
1999-04-10 21:31:45 +04: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-23 01:42:30 +03:00
|
|
|
}
|
1999-12-30 07:15:45 +03: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 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
1999-12-30 07:15:45 +03:00
|
|
|
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
2000-06-12 02:14:33 +04: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 08:56:25 +04:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-29 02:17:53 +04: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 08:56:25 +04:00
|
|
|
#endif
|
1999-12-30 07:15:45 +03:00
|
|
|
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
|
|
|
|
|
|
|
}
|
1999-03-23 01:42:30 +03:00
|
|
|
PostPlaceLine(aState, aLine, maxElementSize);
|
1998-12-05 19:02:08 +03:00
|
|
|
|
2001-05-19 13:53:59 +04:00
|
|
|
// If the block frame that we just reflowed happens to be our
|
|
|
|
// first block, then its computed ascent is ours
|
|
|
|
if (frame == GetTopBlockChild()) {
|
|
|
|
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
|
|
|
|
mAscent = metrics.ascent;
|
|
|
|
}
|
|
|
|
|
1999-02-19 01:22:55 +03: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.
|
2001-03-14 09:45:41 +03:00
|
|
|
if (mBullet && HaveOutsideBullet() &&
|
2001-10-25 05:08:40 +04:00
|
|
|
((aLine == mLines.front()) ||
|
|
|
|
((0 == mLines.front()->mBounds.height) &&
|
|
|
|
(aLine == begin_lines().next())))) {
|
1999-02-19 01:22:55 +03:00
|
|
|
// Reflow the bullet
|
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
|
|
|
ReflowBullet(aState, metrics);
|
|
|
|
|
2002-03-07 01:22:24 +03:00
|
|
|
// Doing the alignment using |mAscent| will also cater for bullets
|
|
|
|
// that are placed next to a child block (bug 92896)
|
|
|
|
// (Note that mAscent should be set by now, otherwise why would
|
|
|
|
// we be placing the bullet yet?)
|
1999-02-19 01:22:55 +03:00
|
|
|
|
|
|
|
// Tall bullets won't look particularly nice here...
|
|
|
|
nsRect bbox;
|
|
|
|
mBullet->GetRect(bbox);
|
2001-10-25 05:08:40 +04:00
|
|
|
nscoord bulletTopMargin = applyTopMargin
|
|
|
|
? collapsedBottomMargin.get()
|
|
|
|
: 0;
|
2002-03-07 01:22:24 +03:00
|
|
|
bbox.y = aState.BorderPadding().top + mAscent -
|
1999-10-16 03:35:10 +04:00
|
|
|
metrics.ascent + bulletTopMargin;
|
1999-10-26 08:44:41 +04:00
|
|
|
mBullet->SetRect(aState.mPresContext, bbox);
|
1999-02-19 01:22:55 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// None of the block fits. Determine the correct reflow status.
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aLine == mLines.front()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// 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.
|
2002-07-17 05:48:56 +04:00
|
|
|
::UndoPlaceholders(aState, lastPlaceholder);
|
2001-10-25 05:08:40 +04:00
|
|
|
PushLines(aState, aLine.prev());
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
}
|
1998-06-25 20:33:10 +04:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
|
|
|
}
|
1998-10-31 01:10:10 +03:00
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
#define LINE_REFLOW_OK 0
|
|
|
|
#define LINE_REFLOW_STOP 1
|
|
|
|
#define LINE_REFLOW_REDO 2
|
|
|
|
// a frame was complete, but truncated and not at the top of a page
|
|
|
|
#define LINE_REFLOW_TRUNCATED 3
|
1999-03-21 04:15:12 +03:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::ReflowInlineFrames(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
2000-01-08 06:58:27 +03:00
|
|
|
PRBool* aKeepReflowGoing,
|
2000-04-19 07:12:13 +04:00
|
|
|
PRBool aDamageDirtyArea,
|
2000-01-08 06:58:27 +03:00
|
|
|
PRBool aUpdateMaximumWidth)
|
1999-03-21 04:15:12 +03:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
*aKeepReflowGoing = PR_TRUE;
|
|
|
|
|
1999-03-24 18:42:19 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
PRInt32 spins = 0;
|
|
|
|
#endif
|
1999-08-28 01:45:37 +04: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 06:58:27 +03:00
|
|
|
&lineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-03-24 18:42:19 +03:00
|
|
|
}
|
1999-08-28 01:45:37 +04:00
|
|
|
else {
|
|
|
|
rv = DoReflowInlineFramesAuto(aState, aLine, aKeepReflowGoing,
|
2000-01-08 06:58:27 +03:00
|
|
|
&lineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-28 01:45:37 +04:00
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
spins++;
|
|
|
|
if (1000 == spins) {
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": yikes! spinning on a line over 1000 times!\n");
|
1999-08-28 01:45:37 +04:00
|
|
|
NS_ABORT();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
1999-03-24 18:42:19 +03:00
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-08-28 01:45:37 +04:00
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 06:58:27 +03:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-28 01:45:37 +04:00
|
|
|
{
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Using the PresShell arena here would be nice.
|
1999-11-24 09:03:41 +03:00
|
|
|
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.mReflowState.mSpaceManager,
|
|
|
|
&aState.mReflowState,
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
1999-08-28 01:45:37 +04: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 07:12:13 +04:00
|
|
|
aLineReflowStatus, aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-28 01:45:37 +04:00
|
|
|
ll->EndLineReflow();
|
|
|
|
delete ll;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-08-28 01:45:37 +04:00
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 06:58:27 +03:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-28 01:45:37 +04:00
|
|
|
{
|
1999-11-24 09:03:41 +03:00
|
|
|
nsLineLayout lineLayout(aState.mPresContext,
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.mReflowState.mSpaceManager,
|
|
|
|
&aState.mReflowState,
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
1999-08-28 01:45:37 +04:00
|
|
|
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
|
|
|
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
2000-01-08 06:58:27 +03:00
|
|
|
aKeepReflowGoing, aLineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
aUpdateMaximumWidth, aDamageDirtyArea);
|
1999-08-28 01:45:37 +04:00
|
|
|
lineLayout.EndLineReflow();
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-08 06:58:27 +03:00
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
// If at least one floater on the line was complete, not at the top of page, but was
|
|
|
|
// truncated, then restore the overflow floaters to what they were before and push the line.
|
|
|
|
// The floaters that will be removed from the list aren't yet known by the block's next in flow.
|
|
|
|
void
|
|
|
|
nsBlockFrame::PushTruncatedPlaceholderLine(nsBlockReflowState& aState,
|
|
|
|
line_iterator aLine,
|
|
|
|
nsIFrame* aLastPlaceholder,
|
|
|
|
PRBool& aKeepReflowGoing)
|
|
|
|
{
|
2002-07-17 05:48:56 +04:00
|
|
|
::UndoPlaceholders(aState, aLastPlaceholder);
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
line_iterator prevLine = aLine;
|
|
|
|
--prevLine;
|
|
|
|
PushLines(aState, prevLine);
|
|
|
|
aKeepReflowGoing = PR_FALSE;
|
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
|
|
|
}
|
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|
|
|
nsLineLayout& aLineLayout,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-08-28 01:45:37 +04:00
|
|
|
PRBool* aKeepReflowGoing,
|
2000-01-08 06:58:27 +03:00
|
|
|
PRUint8* aLineReflowStatus,
|
2000-04-19 07:12:13 +04:00
|
|
|
PRBool aUpdateMaximumWidth,
|
|
|
|
PRBool aDamageDirtyArea)
|
1999-08-28 01:45:37 +04:00
|
|
|
{
|
1999-09-15 04:28:10 +04:00
|
|
|
// Forget all of the floaters on the line
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->FreeFloaters(aState.mFloaterCacheFreeList);
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.mFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
1999-10-15 03:10:03 +04:00
|
|
|
aState.mRightFloaterCombinedArea.SetRect(0, 0, 0, 0);
|
1999-03-27 04:22:14 +03:00
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
// Setup initial coordinate system for reflowing the inline frames
|
|
|
|
// into. Apply a previous block frame's bottom margin first.
|
2001-10-25 05:08:40 +04:00
|
|
|
aState.mY += aState.mPrevBottomMargin.get();
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.GetAvailableSpace();
|
2000-03-23 02:19:10 +03:00
|
|
|
PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE;
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SetLineIsImpactedByFloater(impactedByFloaters);
|
2000-03-23 02:19:10 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
|
2000-03-23 02:19:10 +03:00
|
|
|
this, impactedByFloaters);
|
|
|
|
#endif
|
1999-08-28 01:45:37 +04:00
|
|
|
|
|
|
|
const nsMargin& borderPadding = aState.BorderPadding();
|
|
|
|
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
|
|
|
nscoord availWidth = aState.mAvailSpaceRect.width;
|
|
|
|
nscoord availHeight;
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
1999-08-28 01:45:37 +04:00
|
|
|
availHeight = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* XXX get the height right! */
|
|
|
|
availHeight = aState.mAvailSpaceRect.height;
|
|
|
|
}
|
2000-01-08 06:58:27 +03:00
|
|
|
if (aUpdateMaximumWidth) {
|
|
|
|
availWidth = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
else {
|
|
|
|
nscoord rightEdge = aState.mReflowState.mRightEdge;
|
|
|
|
if ( (rightEdge != NS_UNCONSTRAINEDSIZE)
|
|
|
|
&& (availWidth < rightEdge) ) {
|
|
|
|
availWidth = rightEdge;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
1999-08-28 01:45:37 +04:00
|
|
|
aLineLayout.BeginLineReflow(x, aState.mY,
|
|
|
|
availWidth, availHeight,
|
|
|
|
impactedByFloaters,
|
|
|
|
PR_FALSE /*XXX isTopOfPage*/);
|
1999-08-31 07:09:40 +04:00
|
|
|
|
|
|
|
// XXX Unfortunately we need to know this before reflowing the first
|
|
|
|
// inline frame in the line. FIX ME.
|
1999-08-28 01:45:37 +04:00
|
|
|
if ((0 == aLineLayout.GetLineNumber()) &&
|
|
|
|
(NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
|
|
|
|
aLineLayout.SetFirstLetterStyleOK(PR_TRUE);
|
|
|
|
}
|
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
// keep track of the last overflow floater in case we need to undo any new additions
|
2002-05-29 02:50:43 +04:00
|
|
|
nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
|
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
// 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 04:52:22 +03: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-12 01:15:02 +04: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-28 01:45:37 +04:00
|
|
|
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
|
|
|
&lineReflowStatus);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1999-03-21 04:15:12 +03:00
|
|
|
}
|
1999-08-28 01:45:37 +04: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
++aLine;
|
|
|
|
while ((aLine != end_lines()) && (0 == aLine->GetChildCount())) {
|
1999-08-28 01:45:37 +04:00
|
|
|
// XXX Is this still necessary now that DeleteChildsNextInFlow
|
|
|
|
// uses DoRemoveFrame?
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox *toremove = aLine;
|
|
|
|
aLine = mLines.erase(aLine);
|
|
|
|
NS_ASSERTION(nsnull == toremove->mFirstChild, "bad empty line");
|
|
|
|
aState.FreeLineBox(toremove);
|
1999-03-21 04:15:12 +03:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
--aLine;
|
2002-05-29 02:50:43 +04:00
|
|
|
|
|
|
|
if (LINE_REFLOW_TRUNCATED == lineReflowStatus) {
|
|
|
|
// Push the line with the truncated floater
|
|
|
|
PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
|
|
|
|
}
|
1999-08-28 01:45:37 +04:00
|
|
|
break;
|
1999-03-21 04:15:12 +03:00
|
|
|
}
|
1999-08-28 01:45:37 +04:00
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
1999-03-21 04:15:12 +03:00
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
// Pull frames and reflow them until we can't
|
|
|
|
while (LINE_REFLOW_OK == lineReflowStatus) {
|
2000-04-19 07:12:13 +04:00
|
|
|
rv = PullFrame(aState, aLine, aDamageDirtyArea, frame);
|
1999-08-28 01:45:37 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (nsnull == frame) {
|
|
|
|
break;
|
|
|
|
}
|
1999-03-21 04:15:12 +03:00
|
|
|
while (LINE_REFLOW_OK == lineReflowStatus) {
|
1999-10-15 03:10:03 +04:00
|
|
|
PRInt32 oldCount = aLine->GetChildCount();
|
1999-08-28 01:45:37 +04:00
|
|
|
rv = ReflowInlineFrame(aState, aLineLayout, aLine, frame,
|
|
|
|
&lineReflowStatus);
|
1999-03-21 04:15:12 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
if (aLine->GetChildCount() != oldCount) {
|
1999-08-28 01:45:37 +04: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 04:15:12 +03:00
|
|
|
}
|
1999-08-28 01:45:37 +04:00
|
|
|
else {
|
|
|
|
break;
|
1999-03-24 18:42:19 +03:00
|
|
|
}
|
1999-03-21 04:15:12 +03:00
|
|
|
}
|
1999-08-28 01:45:37 +04: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-15 03:10:03 +04:00
|
|
|
NS_ASSERTION(aState.IsImpactedByFloater(),
|
1999-08-28 01:45:37 +04:00
|
|
|
"redo line on totally empty line");
|
|
|
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mAvailSpaceRect.height,
|
|
|
|
"unconstrained height on totally empty line");
|
1999-10-29 18:34:53 +04:00
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
aState.mY += aState.mAvailSpaceRect.height;
|
2002-08-14 16:44:40 +04:00
|
|
|
|
|
|
|
// We don't want to advance by the bottom margin anymore (we did it
|
|
|
|
// once at the beginning of this function, which will just be called
|
|
|
|
// again), and we certainly don't want to go back if it's negative
|
|
|
|
// (infinite loop, bug 153429).
|
|
|
|
aState.mPrevBottomMargin.Zero();
|
|
|
|
|
1999-08-28 01:45:37 +04:00
|
|
|
// 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.
|
|
|
|
}
|
2002-05-29 02:50:43 +04:00
|
|
|
else if (LINE_REFLOW_TRUNCATED != lineReflowStatus) {
|
2001-12-24 02:23:41 +03:00
|
|
|
// If we are propagating out a break-before status then there is
|
1999-03-21 04:15:12 +03:00
|
|
|
// no point in placing the line.
|
1999-08-28 01:45:37 +04:00
|
|
|
if (!NS_INLINE_IS_BREAK_BEFORE(aState.mReflowStatus)) {
|
2002-07-17 05:48:56 +04:00
|
|
|
if (PlaceLine(aState, aLineLayout, aLine, aKeepReflowGoing, aUpdateMaximumWidth)) {
|
|
|
|
::UndoPlaceholders(aState, lastPlaceholder); // undo since we pushed the current line
|
|
|
|
}
|
1999-03-21 04:15:12 +03:00
|
|
|
}
|
|
|
|
}
|
1999-08-28 01:45:37 +04:00
|
|
|
*aLineReflowStatus = lineReflowStatus;
|
1999-03-21 04:15:12 +03:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03: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-15 03:10:03 +04:00
|
|
|
* has some sort of breaking affect then aLine's break-type will be set
|
1998-12-05 19:02:08 +03:00
|
|
|
* to something other than NS_STYLE_CLEAR_NONE.
|
|
|
|
*/
|
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState,
|
1999-08-28 01:45:37 +04:00
|
|
|
nsLineLayout& aLineLayout,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-02-12 20:45:58 +03:00
|
|
|
nsIFrame* aFrame,
|
1999-03-21 04:15:12 +03:00
|
|
|
PRUint8* aLineReflowStatus)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2001-10-03 04:01:04 +04:00
|
|
|
NS_ENSURE_ARG_POINTER(aFrame);
|
|
|
|
|
1999-03-21 04:15:12 +03:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_OK;
|
1998-10-31 01:10:10 +03:00
|
|
|
|
1998-12-05 19:02:08 +03: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-28 01:45:37 +04:00
|
|
|
PRBool reflowingFirstLetter = aLineLayout.GetFirstLetterStyleOK();
|
1999-04-28 02:10:51 +04:00
|
|
|
#ifdef NOISY_FIRST_LETTER
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": reflowing ");
|
1999-04-28 02:10:51 +04:00
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" reflowingFirstLetter=%s\n", reflowingFirstLetter ? "on" : "off");
|
1999-04-28 02:10:51 +04:00
|
|
|
#endif
|
1998-06-18 20:25:41 +04:00
|
|
|
|
2000-02-14 04:52:22 +03:00
|
|
|
// Remember if we have a percentage aware child on this line
|
|
|
|
if (IsPercentageAwareChild(aFrame)) {
|
|
|
|
aLine->SetHasPercentageChild(PR_TRUE);
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Reflow the inline frame
|
|
|
|
nsReflowStatus frameReflowStatus;
|
2000-01-03 07:32:13 +03:00
|
|
|
PRBool pushedFrame;
|
2002-05-10 22:22:41 +04:00
|
|
|
nsresult rv = aLineLayout.ReflowFrame(aFrame, frameReflowStatus,
|
|
|
|
nsnull, pushedFrame);
|
|
|
|
|
|
|
|
// If this is an incremental reflow, prune the child from the path
|
|
|
|
// so we don't incrementally reflow it again.
|
|
|
|
// XXX note that we don't currently have any incremental reflows
|
|
|
|
// that trace a path through an inline frame (thanks to reflow roots
|
|
|
|
// dealing with text inputs), but we may need to deal with this
|
|
|
|
// again, someday.
|
|
|
|
if (aState.mReflowState.path)
|
|
|
|
aState.mReflowState.path->RemoveChild(aFrame);
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-09-10 23:32:14 +04:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef REALLY_NOISY_REFLOW_CHILD
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": status=%x\n", frameReflowStatus);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-09-10 23:32:14 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
#if defined(REFLOW_STATUS_COVERAGE)
|
1999-02-09 20:31:33 +03:00
|
|
|
RecordReflowStatus(PR_FALSE, frameReflowStatus);
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
1998-09-10 23:32:14 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Send post-reflow notification
|
|
|
|
aState.mPrevChild = aFrame;
|
1998-09-10 23:32:14 +04:00
|
|
|
|
2000-06-15 03:15:59 +04: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 19:02:08 +03: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-13 03:24:22 +04:00
|
|
|
aLine->SetBreakType(NS_STYLE_CLEAR_NONE);
|
2002-07-17 05:48:56 +04:00
|
|
|
if (NS_INLINE_IS_BREAK(frameReflowStatus) ||
|
|
|
|
(NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType)) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Always abort the line reflow (because a line break is the
|
|
|
|
// minimal amount of break we do).
|
1999-03-21 04:15:12 +03:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
1998-12-05 19:02:08 +03:00
|
|
|
|
1999-10-15 03:10:03 +04:00
|
|
|
// XXX what should aLine's break-type be set to in all these cases?
|
1998-12-05 19:02:08 +03:00
|
|
|
PRUint8 breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
|
2002-07-17 05:48:56 +04:00
|
|
|
NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) ||
|
|
|
|
(NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType), "bad break type");
|
1998-12-05 19:02:08 +03:00
|
|
|
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 04:15:12 +03: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 19:02:08 +03: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-28 01:45:37 +04:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-03 07:32:13 +03: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 19:02:08 +03:00
|
|
|
}
|
1998-09-10 23:32:14 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
else {
|
2002-07-17 05:48:56 +04:00
|
|
|
// If a floater split and its prev-in-flow was followed by a <BR>, then combine
|
|
|
|
// the <BR>'s break type with the inline's break type (the inline will be the very
|
|
|
|
// next frame after the split floater).
|
|
|
|
if (NS_STYLE_CLEAR_NONE != aState.mFloaterBreakType) {
|
|
|
|
breakType = ::CombineBreakType(breakType, aState.mFloaterBreakType);
|
|
|
|
aState.mFloaterBreakType = NS_STYLE_CLEAR_NONE;
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
// Break-after cases
|
1999-10-29 18:34:53 +04:00
|
|
|
if (breakType == NS_STYLE_CLEAR_LINE) {
|
|
|
|
if (!aLineLayout.GetLineEndsInBR()) {
|
|
|
|
breakType = NS_STYLE_CLEAR_NONE;
|
|
|
|
}
|
|
|
|
}
|
1999-10-13 03:24:22 +04:00
|
|
|
aLine->SetBreakType(breakType);
|
1998-12-05 19:02:08 +03: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);
|
2002-05-29 02:50:43 +04:00
|
|
|
if (NS_FAILED(rv))
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
2000-01-03 07:32:13 +03:00
|
|
|
// Remember that the line has wrapped
|
|
|
|
aLine->SetLineWrapped(PR_TRUE);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-09-10 23:32:14 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Split line, but after the frame just reflowed
|
1999-03-16 22:36:00 +03:00
|
|
|
nsIFrame* nextFrame;
|
|
|
|
aFrame->GetNextSibling(&nextFrame);
|
1999-08-28 01:45:37 +04:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, nextFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-09-11 08:13:29 +04:00
|
|
|
}
|
2001-05-16 19:51:17 +04:00
|
|
|
|
2001-05-18 11:00:46 +04:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
// Mark next line dirty in case SplitLine didn't end up
|
|
|
|
// pushing any frames.
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* next = aLine.next();
|
2001-05-18 11:00:46 +04:00
|
|
|
if ((nsnull != next) && !next->IsBlock()) {
|
|
|
|
next->MarkDirty();
|
|
|
|
}
|
2001-05-16 19:51:17 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (NS_FRAME_IS_NOT_COMPLETE(frameReflowStatus)) {
|
|
|
|
// Frame is not-complete, no special breaking status
|
1998-09-10 23:32:14 +04:00
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
aFrame->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Create a continuation for the incomplete frame. Note that the
|
|
|
|
// frame may already have a continuation.
|
|
|
|
PRBool madeContinuation;
|
2002-05-29 02:50:43 +04:00
|
|
|
rv = (nsLayoutAtoms::placeholderFrame == frameType)
|
|
|
|
? SplitPlaceholder(aState, *aFrame)
|
|
|
|
: CreateContinuationFor(aState, aLine, aFrame, madeContinuation);
|
|
|
|
if (NS_FAILED(rv))
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
|
|
|
|
2000-01-03 07:32:13 +03:00
|
|
|
// Remember that the line has wrapped
|
|
|
|
aLine->SetLineWrapped(PR_TRUE);
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
// If we are reflowing the first letter frame or a placeholder then
|
|
|
|
// don't split the line and don't stop the line reflow...
|
|
|
|
PRBool splitLine = !reflowingFirstLetter &&
|
|
|
|
(nsLayoutAtoms::placeholderFrame != frameType);
|
1999-04-28 02:10:51 +04:00
|
|
|
if (reflowingFirstLetter) {
|
1999-11-01 18:24:57 +03:00
|
|
|
if ((nsLayoutAtoms::inlineFrame == frameType.get()) ||
|
|
|
|
(nsLayoutAtoms::lineFrame == frameType.get())) {
|
1999-04-28 02:10:51 +04:00
|
|
|
splitLine = PR_TRUE;
|
|
|
|
}
|
1999-03-26 03:39:04 +03:00
|
|
|
}
|
1998-09-11 08:13:29 +04:00
|
|
|
|
1999-04-28 02:10:51 +04:00
|
|
|
if (splitLine) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Split line after the current frame
|
1999-03-21 04:15:12 +03:00
|
|
|
*aLineReflowStatus = LINE_REFLOW_STOP;
|
1999-02-10 09:13:38 +03:00
|
|
|
aFrame->GetNextSibling(&aFrame);
|
1999-08-28 01:45:37 +04:00
|
|
|
rv = SplitLine(aState, aLineLayout, aLine, aFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1999-04-28 02:10:51 +04:00
|
|
|
|
1999-02-09 20:31:33 +03:00
|
|
|
// Mark next line dirty in case SplitLine didn't end up
|
|
|
|
// pushing any frames.
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* next = aLine.next();
|
1999-02-09 20:31:33 +03:00
|
|
|
if ((nsnull != next) && !next->IsBlock()) {
|
|
|
|
next->MarkDirty();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
1998-09-10 23:32:14 +04:00
|
|
|
}
|
2002-05-29 02:50:43 +04:00
|
|
|
else if (NS_FRAME_IS_TRUNCATED(frameReflowStatus)) {
|
|
|
|
// if the frame is a placeholder and was complete but truncated (and not at the top
|
|
|
|
// of page), the entire line will be pushed to give it another chance to not truncate.
|
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
aFrame->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
if (nsLayoutAtoms::placeholderFrame == frameType) {
|
|
|
|
*aLineReflowStatus = LINE_REFLOW_TRUNCATED;
|
|
|
|
}
|
|
|
|
}
|
1998-09-10 23:32:14 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
/**
|
2002-05-29 02:50:43 +04:00
|
|
|
* Create a continuation, if necessary, for aFrame. Place it in aLine
|
|
|
|
* if aLine is not null. Set aMadeNewFrame to PR_TRUE if a new frame is created.
|
1998-12-05 19:02:08 +03:00
|
|
|
*/
|
1998-07-01 00:14:04 +04:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::CreateContinuationFor(nsBlockReflowState& aState,
|
2002-05-29 02:50:43 +04:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
PRBool& aMadeNewFrame)
|
1998-07-01 00:14:04 +04:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
aMadeNewFrame = PR_FALSE;
|
|
|
|
nsresult rv;
|
|
|
|
nsIFrame* nextInFlow;
|
1999-11-24 09:03:41 +03:00
|
|
|
rv = CreateNextInFlow(aState.mPresContext, this, aFrame, nextInFlow);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
1998-07-01 00:14:04 +04:00
|
|
|
return rv;
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
if (nsnull != nextInFlow) {
|
|
|
|
aMadeNewFrame = PR_TRUE;
|
2002-05-29 02:50:43 +04:00
|
|
|
if (aLine) {
|
|
|
|
aLine->SetChildCount(aLine->GetChildCount() + 1);
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_FALSE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
return rv;
|
1998-07-01 00:14:04 +04:00
|
|
|
}
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::SplitPlaceholder(nsBlockReflowState& aState,
|
|
|
|
nsIFrame& aPlaceholder)
|
|
|
|
{
|
|
|
|
nsIFrame* nextInFlow;
|
|
|
|
nsresult rv = CreateNextInFlow(aState.mPresContext, this, &aPlaceholder, nextInFlow);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
// put the sibling list back to what it was before the continuation was created
|
|
|
|
nsIFrame *contFrame, *next;
|
|
|
|
aPlaceholder.GetNextSibling(&contFrame);
|
|
|
|
contFrame->GetNextSibling(&next);
|
|
|
|
aPlaceholder.SetNextSibling(next);
|
|
|
|
contFrame->SetNextSibling(nsnull);
|
|
|
|
// add the placehoder to the overflow floaters
|
|
|
|
aState.mOverflowFloaters.AppendFrames(this, contFrame);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::SplitLine(nsBlockReflowState& aState,
|
1999-08-28 01:45:37 +04:00
|
|
|
nsLineLayout& aLineLayout,
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator aLine,
|
1999-04-20 04:27:43 +04:00
|
|
|
nsIFrame* aFrame)
|
1998-10-03 01:50:53 +04:00
|
|
|
{
|
1999-10-15 03:10:03 +04: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 18:34:53 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, gNoiseIndent);
|
2001-10-25 05:08:40 +04:00
|
|
|
printf("split line: from line=%p pushCount=%d aFrame=",
|
|
|
|
NS_STATIC_CAST(void*, aLine.get()), pushCount);
|
1999-11-02 18:44:57 +03:00
|
|
|
if (aFrame) {
|
|
|
|
nsFrame::ListTag(stdout, aFrame);
|
|
|
|
}
|
|
|
|
else {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("(null)");
|
1999-11-02 18:44:57 +03:00
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-10-29 18:34:53 +04:00
|
|
|
if (gReallyNoisyReflow) {
|
|
|
|
aLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (0 != pushCount) {
|
1999-10-15 03:10:03 +04: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-20 03:04:19 +04:00
|
|
|
nsLineBox* newLine = aState.NewLineBox(aFrame, pushCount, PR_FALSE);
|
1999-10-15 03:10:03 +04:00
|
|
|
if (!newLine) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1998-10-03 01:50:53 +04:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.after_insert(aLine, newLine);
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SetChildCount(aLine->GetChildCount() - pushCount);
|
1999-10-29 18:34:53 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gReallyNoisyReflow) {
|
|
|
|
newLine->List(aState.mPresContext, stdout, gNoiseIndent+1);
|
|
|
|
}
|
|
|
|
#endif
|
1998-10-03 01:50:53 +04:00
|
|
|
|
1999-03-19 00:03:25 +03:00
|
|
|
// Let line layout know that some frames are no longer part of its
|
|
|
|
// state.
|
1999-10-15 03:10:03 +04:00
|
|
|
aLineLayout.SplitLineTo(aLine->GetChildCount());
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
1998-10-03 01:50:53 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
PRBool
|
2001-10-25 05:08:40 +04:00
|
|
|
nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
|
|
|
|
line_iterator aLine)
|
1998-06-24 21:52:42 +04:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
while (++aLine != end_lines()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// There is another line
|
2001-10-25 05:08:40 +04:00
|
|
|
if (0 != aLine->GetChildCount()) {
|
1998-12-05 19:02:08 +03: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
return !aLine->IsBlock();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
// The next line is empty, try the next one
|
1998-07-01 00:14:04 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// XXX Not sure about this part
|
|
|
|
// Try our next-in-flows lines to answer the question
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame* nextInFlow = (nsBlockFrame*) mNextInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != nextInFlow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = nextInFlow->begin_lines(),
|
|
|
|
line_end = nextInFlow->end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
|
|
|
if (0 != line->GetChildCount())
|
1998-12-11 18:49:07 +03:00
|
|
|
return !line->IsBlock();
|
1998-11-11 06:55:55 +03:00
|
|
|
}
|
1999-02-09 20:31:33 +03:00
|
|
|
nextInFlow = (nsBlockFrame*) nextInFlow->mNextInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-11-11 06:55:55 +03:00
|
|
|
|
1998-12-11 18:49:07 +03:00
|
|
|
// This is the last line - so don't allow justification
|
|
|
|
return PR_FALSE;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
PRBool
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
2002-07-17 05:48:56 +04:00
|
|
|
nsLineLayout& aLineLayout,
|
|
|
|
line_iterator aLine,
|
|
|
|
PRBool* aKeepReflowGoing,
|
|
|
|
PRBool aUpdateMaximumWidth)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-09-21 04:13:50 +04:00
|
|
|
// Trim extra white-space from the line before placing the frames
|
2001-10-25 05:08:40 +04:00
|
|
|
aLineLayout.TrimTrailingWhiteSpace();
|
1999-09-21 04:13:50 +04:00
|
|
|
|
1999-02-19 01:22:55 +03: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;
|
2001-10-25 05:08:40 +04:00
|
|
|
if (mBullet && HaveOutsideBullet() && (aLine == mLines.front()) &&
|
|
|
|
(!aLineLayout.IsZeroHeight() || (aLine == mLines.back()))) {
|
1999-08-28 01:45:37 +04:00
|
|
|
nsHTMLReflowMetrics metrics(nsnull);
|
|
|
|
ReflowBullet(aState, metrics);
|
|
|
|
aLineLayout.AddBulletFrame(mBullet, metrics);
|
1999-02-19 01:22:55 +03:00
|
|
|
addedBullet = PR_TRUE;
|
|
|
|
}
|
1999-03-19 00:03:25 +03:00
|
|
|
nsSize maxElementSize;
|
2000-06-05 12:24:18 +04:00
|
|
|
nscoord lineAscent;
|
2001-07-04 06:00:05 +04:00
|
|
|
aLineLayout.VerticalAlignLine(aLine, maxElementSize, lineAscent);
|
2000-06-05 12:24:18 +04:00
|
|
|
// Our ascent is the ascent of our first line
|
2001-10-25 05:08:40 +04:00
|
|
|
if (aLine == mLines.front()) {
|
2000-06-05 12:24:18 +04:00
|
|
|
mAscent = lineAscent;
|
|
|
|
}
|
2000-07-28 13:18:15 +04:00
|
|
|
|
2000-01-03 07:32:13 +03:00
|
|
|
// See if we're shrink wrapping the width
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 07:32:13 +03: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-21 00:57:03 +03:00
|
|
|
#ifdef DEBUG
|
2001-10-25 05:08:40 +04: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);
|
|
|
|
printf(": line=%p y=%d line.bounds.height=%d\n",
|
|
|
|
NS_STATIC_CAST(void*, aLine.get()),
|
|
|
|
aLine->mBounds.y, aLine->mBounds.height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lastHeight = 0;
|
|
|
|
}
|
1999-03-21 00:57:03 +03:00
|
|
|
}
|
1999-03-05 07:21:32 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03: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 18:40:46 +04:00
|
|
|
const nsStyleText* styleText = (const nsStyleText*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Text);
|
|
|
|
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
|
|
|
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
nsRect bounds(aLine->mBounds);
|
|
|
|
|
|
|
|
if (mRect.x) {
|
2001-06-01 02:19:43 +04:00
|
|
|
const nsStyleVisibility* vis;
|
|
|
|
GetStyleData(eStyleStruct_Visibility, (const nsStyleStruct*&)vis);
|
2001-03-09 06:29:00 +03:00
|
|
|
|
2001-06-01 02:19:43 +04:00
|
|
|
if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
|
2001-03-09 06:29:00 +03:00
|
|
|
bounds.x += mRect.x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PRBool successful = aLineLayout.HorizontalAlignFrames(bounds, allowJustify,
|
|
|
|
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
|
|
|
// XXX: not only bidi: right alignment can be broken after RelativePositionFrames!!!
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Is something here considering relatively positioned frames at
|
|
|
|
// other than their original positions?
|
2001-03-09 06:29:00 +03:00
|
|
|
#else
|
2000-04-17 18:40:46 +04:00
|
|
|
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
|
|
|
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
2001-03-09 06:29:00 +03:00
|
|
|
#endif // IBMBIDI
|
2000-01-03 07:32:13 +03: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 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-01-03 07:32:13 +03:00
|
|
|
}
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Why don't we do this earlier?
|
2001-03-09 06:29:00 +03:00
|
|
|
else {
|
|
|
|
PRBool bidiEnabled;
|
2001-05-16 17:40:08 +04:00
|
|
|
aState.mPresContext->GetBidiEnabled(&bidiEnabled);
|
2001-03-09 06:29:00 +03:00
|
|
|
|
|
|
|
if (bidiEnabled) {
|
|
|
|
PRBool isVisual;
|
|
|
|
aState.mPresContext->IsVisualMode(isVisual);
|
|
|
|
if (!isVisual) {
|
|
|
|
nsBidiPresUtils* bidiUtils;
|
|
|
|
aState.mPresContext->GetBidiUtils(&bidiUtils);
|
|
|
|
|
|
|
|
if (bidiUtils && bidiUtils->IsSuccessful() ) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsIFrame* nextInFlow = (aLine.next() != end_lines())
|
|
|
|
? aLine.next()->mFirstChild : nsnull;
|
2001-03-09 06:29:00 +03:00
|
|
|
|
|
|
|
bidiUtils->ReorderFrames(aState.mPresContext,
|
|
|
|
aState.mReflowState.rendContext,
|
|
|
|
aLine->mFirstChild, nextInFlow,
|
|
|
|
aLine->GetChildCount() );
|
|
|
|
} // bidiUtils
|
|
|
|
} // not visual mode
|
|
|
|
} // bidi enabled
|
|
|
|
} // successful
|
|
|
|
#endif // IBMBIDI
|
2000-04-17 18:40:46 +04:00
|
|
|
|
|
|
|
nsRect combinedArea;
|
2001-07-04 06:00:05 +04:00
|
|
|
aLineLayout.RelativePositionFrames(combinedArea); // XXXldb This returned width as -15, 2001-06-12, Bugzilla
|
2001-10-30 09:02:05 +03:00
|
|
|
// XXX Changing the combined area here seems wrong. - LDB
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SetCombinedArea(combinedArea);
|
1999-03-20 04:37:43 +03:00
|
|
|
if (addedBullet) {
|
1999-08-28 01:45:37 +04:00
|
|
|
aLineLayout.RemoveBulletFrame(mBullet);
|
1999-03-20 04:37:43 +03:00
|
|
|
}
|
1998-10-03 01:50:53 +04:00
|
|
|
|
1999-03-27 04:22:14 +03: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
aState.mPrevBottomMargin.Zero();
|
1999-04-03 22:59:01 +04:00
|
|
|
newY = aLine->mBounds.YMost();
|
1999-03-27 04:22:14 +03: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
nscoord dy = -aState.mPrevBottomMargin.get();
|
1999-04-01 05:37:36 +04:00
|
|
|
newY = aState.mY + dy;
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->SlideBy(dy);
|
2000-06-05 12:24:18 +04:00
|
|
|
// keep our ascent in sync
|
2001-10-25 05:08:40 +04:00
|
|
|
if (mLines.front() == aLine) {
|
2000-06-05 12:24:18 +04:00
|
|
|
mAscent += dy;
|
|
|
|
}
|
1999-03-27 04:22:14 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
|
|
|
|
// See if the line fit. If it doesn't we need to push it. Our first
|
|
|
|
// line will always fit.
|
2001-10-25 05:08:40 +04:00
|
|
|
if ((mLines.front() != aLine) && (newY > aState.mBottomEdge)) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Push this line and all of it's children and anything else that
|
|
|
|
// follows to our next-in-flow
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION((aState.mCurrentLine == aLine), "oops");
|
|
|
|
PushLines(aState, aLine.prev());
|
1998-12-05 19:02:08 +03:00
|
|
|
|
|
|
|
// Stop reflow and whack the reflow status if reflow hasn't
|
|
|
|
// already been stopped.
|
1999-02-12 20:45:58 +03:00
|
|
|
if (*aKeepReflowGoing) {
|
2000-02-23 01:06:19 +03:00
|
|
|
NS_ASSERTION(NS_FRAME_COMPLETE == aState.mReflowStatus,
|
1998-12-05 19:02:08 +03:00
|
|
|
"lost reflow status");
|
|
|
|
aState.mReflowStatus = NS_FRAME_NOT_COMPLETE;
|
1999-02-12 20:45:58 +03:00
|
|
|
*aKeepReflowGoing = PR_FALSE;
|
1998-10-06 04:38:56 +04:00
|
|
|
}
|
2002-07-17 05:48:56 +04:00
|
|
|
return PR_TRUE;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-10-03 01:50:53 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mY = newY;
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
|
|
|
printf("PASS1 ");
|
|
|
|
}
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": line.floaters=%s band.floaterCount=%d\n",
|
|
|
|
//aLine->mFloaters.NotEmpty() ? "yes" : "no",
|
|
|
|
aState.mHaveRightFloaters ? "(have right floaters)" : "",
|
|
|
|
aState.mBand.GetFloaterCount());
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
|
|
|
#endif
|
1999-04-10 21:31:45 +04:00
|
|
|
if (0 != aState.mBand.GetFloaterCount()) {
|
|
|
|
// Add in floater impacts to the lines max-element-size
|
|
|
|
ComputeLineMaxElementSize(aState, aLine, &maxElementSize);
|
|
|
|
}
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
2000-01-08 06:58:27 +03:00
|
|
|
|
2000-01-28 06:12:30 +03:00
|
|
|
// If we're reflowing the line just to incrementally update the
|
2000-01-08 06:58:27 +03: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 06:12:30 +03:00
|
|
|
if (aUpdateMaximumWidth) {
|
|
|
|
// However, we do need to update the max-element-size if requested
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
2000-01-28 06:12:30 +03:00
|
|
|
aState.UpdateMaxElementSize(maxElementSize);
|
|
|
|
// We also cache the max element width in the line. This is needed for
|
|
|
|
// incremental reflow
|
|
|
|
aLine->mMaxElementWidth = maxElementSize.width;
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf ("nsBlockFrame::PlaceLine: %p setting MES for line %p to %d\n",
|
2002-09-12 07:44:37 +04:00
|
|
|
this, NS_STATIC_CAST(void*, aLine.get()), maxElementSize.width);
|
2002-07-01 21:43:02 +04:00
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
2000-01-28 06:12:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2000-01-08 06:58:27 +03:00
|
|
|
PostPlaceLine(aState, aLine, maxElementSize);
|
|
|
|
}
|
1998-12-17 21:52:10 +03:00
|
|
|
|
1999-09-18 03:16:43 +04:00
|
|
|
// Add the already placed current-line floaters to the line
|
1999-10-15 03:10:03 +04:00
|
|
|
aLine->AppendFloaters(aState.mCurrentLineFloaters);
|
1999-09-15 04:28:10 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Any below current line floaters to place?
|
1999-09-15 04:28:10 +04:00
|
|
|
if (aState.mBelowCurrentLineFloaters.NotEmpty()) {
|
2002-05-29 02:50:43 +04:00
|
|
|
// keep track of the last overflow floater in case we need to undo and push the line
|
|
|
|
nsIFrame* lastPlaceholder = aState.mOverflowFloaters.LastChild();
|
1999-09-15 04:28:10 +04:00
|
|
|
// Reflow the below-current-line floaters, then add them to the
|
2002-05-29 02:50:43 +04:00
|
|
|
// lines floater list if there aren't any truncated floaters.
|
|
|
|
if (aState.PlaceBelowCurrentLineFloaters(aState.mBelowCurrentLineFloaters)) {
|
|
|
|
aLine->AppendFloaters(aState.mBelowCurrentLineFloaters);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// At least one floater is truncated, so fix up any placeholders that got split and
|
|
|
|
// push the line. XXX It may be better to put the floater on the next line, but this
|
|
|
|
// is not common enough to justify the complexity.
|
|
|
|
PushTruncatedPlaceholderLine(aState, aLine, lastPlaceholder, *aKeepReflowGoing);
|
|
|
|
}
|
1998-07-01 03:51:26 +04:00
|
|
|
}
|
|
|
|
|
1999-03-23 07:28:20 +03:00
|
|
|
// When a line has floaters, factor them into the combined-area
|
|
|
|
// computations.
|
1999-10-15 03:10:03 +04:00
|
|
|
if (aLine->HasFloaters()) {
|
1999-03-23 07:28:20 +03:00
|
|
|
// Combine the floater combined area (stored in aState) and the
|
|
|
|
// value computed by the line layout code.
|
1999-10-15 03:10:03 +04:00
|
|
|
nsRect lineCombinedArea;
|
|
|
|
aLine->GetCombinedArea(&lineCombinedArea);
|
|
|
|
#ifdef NOISY_COMBINED_AREA
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": lineCA=%d,%d,%d,%d floaterCA=%d,%d,%d,%d\n",
|
1999-10-15 03:10:03 +04: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 07:32:13 +03:00
|
|
|
if (aState.mHaveRightFloaters &&
|
2000-04-17 18:40:46 +04:00
|
|
|
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
2000-01-03 07:32:13 +03: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-15 03:10:03 +04:00
|
|
|
// which will cause the combined area to be unusable.
|
|
|
|
//
|
2000-01-03 07:32:13 +03: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-15 03:10:03 +04:00
|
|
|
#ifdef NOISY_COMBINED_AREA
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> rightFloaterCA=%d,%d,%d,%d lineXMost=%d\n",
|
1999-10-15 03:10:03 +04: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 07:32:13 +03:00
|
|
|
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
2000-01-03 07:32:13 +03: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 18:40:46 +04:00
|
|
|
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
2000-01-03 07:32:13 +03:00
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
}
|
|
|
|
aLine->SetCombinedArea(lineCombinedArea);
|
|
|
|
#ifdef NOISY_COMBINED_AREA
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" ==> final lineCA=%d,%d,%d,%d\n",
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
|
|
|
#endif
|
|
|
|
aState.mHaveRightFloaters = PR_FALSE;
|
1999-03-23 07:28:20 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Apply break-after clearing if necessary
|
1999-10-13 03:24:22 +04:00
|
|
|
PRUint8 breakType = aLine->GetBreakType();
|
|
|
|
switch (breakType) {
|
1998-12-05 19:02:08 +03:00
|
|
|
case NS_STYLE_CLEAR_LEFT:
|
|
|
|
case NS_STYLE_CLEAR_RIGHT:
|
|
|
|
case NS_STYLE_CLEAR_LEFT_AND_RIGHT:
|
1999-10-13 03:24:22 +04:00
|
|
|
aState.ClearFloaters(aState.mY, breakType);
|
1998-12-05 19:02:08 +03:00
|
|
|
break;
|
1998-11-11 06:55:55 +03:00
|
|
|
}
|
|
|
|
|
2002-07-17 05:48:56 +04:00
|
|
|
return PR_FALSE;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-11-05 22:33:01 +03:00
|
|
|
|
1998-12-17 21:52:10 +03: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 20:31:33 +03:00
|
|
|
nsBlockFrame::ComputeLineMaxElementSize(nsBlockReflowState& aState,
|
1999-03-20 22:40:13 +03:00
|
|
|
nsLineBox* aLine,
|
|
|
|
nsSize* aMaxElementSize)
|
1998-12-17 21:52:10 +03:00
|
|
|
{
|
|
|
|
nscoord maxWidth, maxHeight;
|
1999-10-22 00:43:48 +04:00
|
|
|
aState.mBand.GetMaxElementSize(aState.mPresContext, &maxWidth, &maxHeight);
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
|
|
|
printf("PASS1 ");
|
|
|
|
}
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": maxFloaterSize=%d,%d\n", maxWidth, maxHeight);
|
1999-03-23 02:03:31 +03:00
|
|
|
}
|
1999-03-20 22:40:13 +03:00
|
|
|
#endif
|
1998-12-17 21:52:10 +03:00
|
|
|
|
2001-09-12 02:17:21 +04:00
|
|
|
// To ensure that we always place some content next to a floater,
|
|
|
|
// _add_ the max floater width to our line's max element size.
|
|
|
|
aMaxElementSize->width += maxWidth;
|
1998-12-17 21:52:10 +03:00
|
|
|
|
1999-03-20 22:40:13 +03:00
|
|
|
// Only update the max-element-size's height value if the floater is
|
|
|
|
// part of the current line.
|
1999-10-15 03:10:03 +04:00
|
|
|
if (aLine->HasFloaters()) {
|
1999-03-20 22:40:13 +03: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 21:52:10 +03:00
|
|
|
}
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf ("nsBlockFrame::ComputeLineMaxElementSize: %p returning MES %d\n",
|
|
|
|
this, aMaxElementSize->width);
|
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
1998-12-17 21:52:10 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
1999-03-19 00:03:25 +03:00
|
|
|
nsLineBox* aLine,
|
|
|
|
const nsSize& aMaxElementSize)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-11-19 18:33:29 +03:00
|
|
|
// If it's inline elements, then make sure the views are correctly
|
|
|
|
// positioned and sized
|
|
|
|
if (aLine->IsInline()) {
|
|
|
|
nsIFrame* frame = aLine->mFirstChild;
|
2002-04-11 04:06:39 +04:00
|
|
|
for (PRInt32 i = 0; (i < aLine->GetChildCount() && frame); i++) {
|
|
|
|
::PlaceFrameView(aState.mPresContext, frame);
|
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
NS_ASSERTION(frame || (i+1) == aLine->GetChildCount(),
|
|
|
|
"Child count bigger than the number of linked frames!!!");
|
1999-11-19 18:33:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Update max-element-size
|
2000-04-17 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
1999-04-03 22:59:01 +04:00
|
|
|
aState.UpdateMaxElementSize(aMaxElementSize);
|
1999-08-28 04:39:55 +04:00
|
|
|
// We also cache the max element width in the line. This is needed for
|
|
|
|
// incremental reflow
|
|
|
|
aLine->mMaxElementWidth = aMaxElementSize.width;
|
2002-07-01 21:43:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyMaxElementSize) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf ("nsBlockFrame::PostPlaceLine: %p setting line %p MES %d\n",
|
|
|
|
this, aLine, aMaxElementSize.width);
|
|
|
|
}
|
2000-05-14 08:56:25 +04:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-11-05 22:33:01 +03:00
|
|
|
|
1999-12-30 07:15:45 +03: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 18:40:46 +04:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
2000-05-14 08:56:25 +04:00
|
|
|
#ifdef NOISY_MAXIMUM_WIDTH
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("nsBlockFrame::PostPlaceLine during UC Reflow of block %p line %p caching max width %d\n",
|
2000-05-14 08:56:25 +04:00
|
|
|
this, aLine, aLine->mBounds.XMost());
|
|
|
|
#endif
|
1999-12-30 07:15:45 +03:00
|
|
|
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Update xmost
|
2001-09-12 02:17:21 +04:00
|
|
|
nscoord xmost = aLine->mBounds.XMost();
|
2001-08-14 04:08:08 +04:00
|
|
|
|
1999-03-21 00:57:03 +03:00
|
|
|
#ifdef DEBUG
|
1999-09-18 03:16:43 +04:00
|
|
|
if (CRAZY_WIDTH(xmost)) {
|
|
|
|
ListTag(stdout);
|
2001-10-25 05:08:40 +04:00
|
|
|
printf(": line=%p xmost=%d\n", NS_STATIC_CAST(void*, aLine), xmost);
|
1999-09-18 03:16:43 +04:00
|
|
|
}
|
1999-03-05 07:21:32 +03:00
|
|
|
#endif
|
2001-05-22 03:03:46 +04:00
|
|
|
if (xmost > aState.mKidXMost) {
|
1998-12-05 19:02:08 +03:00
|
|
|
aState.mKidXMost = xmost;
|
2000-06-12 02:14:33 +04:00
|
|
|
#ifdef NOISY_KIDXMOST
|
2001-05-22 03:03:46 +04:00
|
|
|
printf("%p PostPlaceLine aState.mKidXMost=%d\n", this, aState.mKidXMost);
|
2000-06-12 02:14:33 +04:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-07-01 00:14:04 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
2002-07-17 05:48:56 +04:00
|
|
|
nsBlockFrame::PushLines(nsBlockReflowState& aState,
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList::iterator aLineBefore)
|
1998-07-07 01:37:08 +04:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList::iterator overBegin(aLineBefore.next());
|
|
|
|
NS_ASSERTION(overBegin != begin_lines(), "bad push");
|
|
|
|
|
|
|
|
if (overBegin != end_lines()) {
|
|
|
|
// XXXldb use presshell arena!
|
|
|
|
nsLineList* overflowLines = new nsLineList();
|
|
|
|
overflowLines->splice(overflowLines->end(), mLines, overBegin,
|
|
|
|
end_lines());
|
|
|
|
NS_ASSERTION(!overflowLines->empty(), "should not be empty");
|
|
|
|
// this takes ownership but it won't delete it immediately so we
|
|
|
|
// can keep using it.
|
|
|
|
SetOverflowLines(aState.mPresContext, overflowLines);
|
1999-12-08 02:41:48 +03:00
|
|
|
|
|
|
|
// Mark all the overflow lines dirty so that they get reflowed when
|
|
|
|
// they are pulled up by our next-in-flow.
|
2001-07-04 06:00:05 +04:00
|
|
|
|
|
|
|
// XXXldb Can this get called O(N) times making the whole thing O(N^2)?
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = overflowLines->begin(),
|
|
|
|
line_end = overflowLines->end();
|
|
|
|
line != line_end;
|
|
|
|
++line)
|
|
|
|
{
|
|
|
|
line->MarkDirty();
|
1999-12-08 02:41:48 +03:00
|
|
|
}
|
1998-09-25 09:13:06 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Break frame sibling list
|
2001-10-25 05:08:40 +04:00
|
|
|
aLineBefore->LastChild()->SetNextSibling(nsnull);
|
1998-09-25 09:13:06 +04:00
|
|
|
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-11-03 02:42:52 +03:00
|
|
|
VerifyOverflowSituation(aState.mPresContext);
|
1998-09-25 09:13:06 +04:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-09-25 09:13:06 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
|
|
|
|
// The overflowLines property is stored as a pointer to a line list,
|
|
|
|
// which must be deleted. However, the following functions all maintain
|
|
|
|
// the invariant that the property is never set if the list is empty.
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
PRBool
|
1999-10-26 08:44:41 +04:00
|
|
|
nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-11-03 02:42:52 +03:00
|
|
|
VerifyOverflowSituation(aPresContext);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
PRBool drained = PR_FALSE;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* overflowLines;
|
1998-11-17 04:04:45 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// First grab the prev-in-flows overflow lines
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame* prevBlock = (nsBlockFrame*) mPrevInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
if (nsnull != prevBlock) {
|
1999-11-03 02:42:52 +03:00
|
|
|
overflowLines = prevBlock->GetOverflowLines(aPresContext, PR_TRUE);
|
|
|
|
if (nsnull != overflowLines) {
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(! overflowLines->empty(),
|
|
|
|
"overflow lines should never be set and empty");
|
1998-12-05 19:02:08 +03:00
|
|
|
drained = PR_TRUE;
|
1998-09-25 09:13:06 +04:00
|
|
|
|
1999-11-03 02:42:52 +03:00
|
|
|
// Make all the frames on the overflow line list mine
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* lastFrame = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsIFrame* frame = overflowLines->front()->mFirstChild;
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != frame) {
|
1999-01-14 08:16:23 +03:00
|
|
|
frame->SetParent(this);
|
1999-04-11 08:22:00 +04:00
|
|
|
|
|
|
|
// When pushing and pulling frames we need to check for whether any
|
|
|
|
// views need to be reparented
|
1999-10-26 08:44:41 +04:00
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, prevBlock, this);
|
1999-04-11 08:22:00 +04:00
|
|
|
|
2001-09-28 17:59:23 +04:00
|
|
|
// If the frame we are looking at is a placeholder for a floater, we
|
|
|
|
// need to reparent both it's out-of-flow frame and any views it has.
|
|
|
|
//
|
|
|
|
// Note: A floating table (example: style="position: relative; float: right")
|
|
|
|
// is an example of an out-of-flow frame with a view
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> frameType;
|
|
|
|
frame->GetFrameType(getter_AddRefs(frameType));
|
|
|
|
|
|
|
|
if (nsLayoutAtoms::placeholderFrame == frameType.get()) {
|
|
|
|
nsIFrame *outOfFlowFrame = NS_STATIC_CAST(nsPlaceholderFrame*, frame)->GetOutOfFlowFrame();
|
|
|
|
if (outOfFlowFrame) {
|
|
|
|
const nsStyleDisplay* display = nsnull;
|
|
|
|
outOfFlowFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
|
|
|
if (display && !display->IsAbsolutelyPositioned()) {
|
|
|
|
// It's not an absolute or fixed positioned frame, so it
|
|
|
|
// must be a floater!
|
|
|
|
outOfFlowFrame->SetParent(this);
|
|
|
|
nsHTMLContainerFrame::ReparentFrameView(aPresContext, outOfFlowFrame, prevBlock, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-11 08:22:00 +04:00
|
|
|
// Get the next frame
|
1998-12-05 19:02:08 +03:00
|
|
|
lastFrame = frame;
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-09-25 09:13:06 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Join the line lists
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(lastFrame, "overflow list was created with no frames");
|
|
|
|
if (! mLines.empty()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
// Join the sibling lists together
|
2001-10-25 05:08:40 +04:00
|
|
|
lastFrame->SetNextSibling(mLines.front()->mFirstChild);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
// Place overflow lines at the front of our line list
|
|
|
|
mLines.splice(mLines.begin(), *overflowLines);
|
|
|
|
NS_ASSERTION(overflowLines->empty(), "splice should empty list");
|
|
|
|
delete overflowLines;
|
1998-09-25 09:13:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Now grab our own overflow lines
|
1999-11-03 02:42:52 +03:00
|
|
|
overflowLines = GetOverflowLines(aPresContext, PR_TRUE);
|
|
|
|
if (overflowLines) {
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(! overflowLines->empty(),
|
|
|
|
"overflow lines should never be set and empty");
|
1998-12-05 19:02:08 +03: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
|
|
|
|
if (! mLines.empty()) {
|
|
|
|
mLines.back()->LastChild()->SetNextSibling(
|
|
|
|
overflowLines->front()->mFirstChild );
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
// append the overflow to mLines
|
|
|
|
mLines.splice(mLines.end(), *overflowLines);
|
1998-12-05 19:02:08 +03:00
|
|
|
drained = PR_TRUE;
|
2001-10-25 05:08:40 +04:00
|
|
|
delete overflowLines;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
return drained;
|
1998-09-25 20:10:10 +04:00
|
|
|
}
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList*
|
1999-11-03 02:42:52 +03:00
|
|
|
nsBlockFrame::GetOverflowLines(nsIPresContext* aPresContext,
|
2000-01-22 04:16:50 +03:00
|
|
|
PRBool aRemoveProperty) const
|
1999-11-03 02:42:52 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
|
|
|
if (presShell) {
|
|
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
|
|
presShell->GetFrameManager(getter_AddRefs(frameManager));
|
|
|
|
|
|
|
|
if (frameManager) {
|
|
|
|
PRUint32 options = 0;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* value;
|
1999-11-03 02:42:52 +03:00
|
|
|
|
|
|
|
if (aRemoveProperty) {
|
|
|
|
options |= NS_IFRAME_MGR_REMOVE_PROP;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
frameManager->GetFrameProperty(NS_CONST_CAST(nsBlockFrame*, this),
|
|
|
|
nsLayoutAtoms::overflowLinesProperty,
|
|
|
|
options,
|
|
|
|
NS_REINTERPRET_CAST(void**, &value));
|
|
|
|
NS_ASSERTION(!value || !value->empty(),
|
|
|
|
"value should never be stored as empty");
|
|
|
|
return value;
|
1999-11-03 02:42:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor function for the overflowLines frame property
|
|
|
|
static void
|
|
|
|
DestroyOverflowLines(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsIAtom* aPropertyName,
|
|
|
|
void* aPropertyValue)
|
|
|
|
{
|
|
|
|
if (aPropertyValue) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* lines = NS_STATIC_CAST(nsLineList*, aPropertyValue);
|
|
|
|
nsLineBox::DeleteLineList(aPresContext, *lines);
|
|
|
|
delete lines;
|
1999-11-03 02:42:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
// This takes ownership of aOverflowLines.
|
|
|
|
// XXX We should allocate overflowLines from presShell arena!
|
1999-11-03 02:42:52 +03:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::SetOverflowLines(nsIPresContext* aPresContext,
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* aOverflowLines)
|
1999-11-03 02:42:52 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(aOverflowLines, "null lines");
|
|
|
|
NS_ASSERTION(! aOverflowLines->empty(), "empty lines");
|
|
|
|
|
1999-11-03 02:42:52 +03:00
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
if (presShell) {
|
|
|
|
nsCOMPtr<nsIFrameManager> frameManager;
|
|
|
|
presShell->GetFrameManager(getter_AddRefs(frameManager));
|
|
|
|
|
|
|
|
if (frameManager) {
|
2001-10-25 05:08:40 +04:00
|
|
|
rv = frameManager->SetFrameProperty(this,
|
|
|
|
nsLayoutAtoms::overflowLinesProperty,
|
|
|
|
aOverflowLines,
|
|
|
|
DestroyOverflowLines);
|
1999-11-03 02:42:52 +03:00
|
|
|
|
|
|
|
// 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 21:52:10 +03:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Frame list manipulation routines
|
|
|
|
|
1999-04-20 04:27:43 +04:00
|
|
|
nsIFrame*
|
|
|
|
nsBlockFrame::LastChild()
|
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! mLines.empty()) {
|
|
|
|
return mLines.back()->LastChild();
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
1999-02-02 20:31:09 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::AppendFrames(nsIPresContext* aPresContext,
|
1999-02-26 20:04:44 +03:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aFrameList)
|
1999-02-02 20:31:09 +03:00
|
|
|
{
|
1999-04-21 23:58:38 +04:00
|
|
|
if (nsnull == aFrameList) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-09 09:06:16 +04:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.AppendFrames(this, aPresContext, aPresShell, aListName,
|
|
|
|
aFrameList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 20:04:44 +03: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 22:09:24 +03:00
|
|
|
}
|
1999-02-26 20:04:44 +03:00
|
|
|
else if (nsnull != aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
1999-04-20 04:27:43 +04:00
|
|
|
// Find the proper last-child for where the append should go
|
|
|
|
nsIFrame* lastKid = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox* lastLine = mLines.empty() ? nsnull : mLines.back();
|
1999-04-20 04:27:43 +04:00
|
|
|
if (lastLine) {
|
|
|
|
lastKid = lastLine->LastChild();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add frames after the last child
|
1999-04-21 23:58:38 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": append ");
|
1999-04-21 23:58:38 +04:00
|
|
|
nsFrame::ListTag(stdout, aFrameList);
|
|
|
|
if (lastKid) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" after ");
|
1999-04-21 23:58:38 +04:00
|
|
|
nsFrame::ListTag(stdout, lastKid);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-04-21 23:58:38 +04:00
|
|
|
#endif
|
1999-11-24 09:03:41 +03:00
|
|
|
nsresult rv = AddFrames(aPresContext, aFrameList, lastKid);
|
1999-02-02 20:31:09 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 06:58:05 +03:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 20:31:09 +03:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::InsertFrames(nsIPresContext* aPresContext,
|
1999-02-26 20:04:44 +03:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aPrevFrame,
|
|
|
|
nsIFrame* aFrameList)
|
1999-02-02 20:31:09 +03:00
|
|
|
{
|
2000-05-09 09:06:16 +04:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.InsertFrames(this, aPresContext, aPresShell, aListName,
|
|
|
|
aPrevFrame, aFrameList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 20:04:44 +03:00
|
|
|
// XXX we don't *really* care about this right now because we are
|
1999-07-14 19:16:56 +04:00
|
|
|
// BuildFloaterList'ing still
|
1999-02-26 20:04:44 +03:00
|
|
|
mFloaters.AppendFrames(nsnull, aFrameList);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
else if (nsLayoutAtoms::nextBidi == aListName) {}
|
|
|
|
#endif // IBMBIDI
|
1999-02-26 20:04:44 +03:00
|
|
|
else if (nsnull != aListName) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
1999-02-03 22:09:24 +03:00
|
|
|
}
|
1999-02-26 20:04:44 +03:00
|
|
|
|
1999-04-21 23:58:38 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": insert ");
|
1999-04-21 23:58:38 +04:00
|
|
|
nsFrame::ListTag(stdout, aFrameList);
|
|
|
|
if (aPrevFrame) {
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" after ");
|
1999-04-21 23:58:38 +04:00
|
|
|
nsFrame::ListTag(stdout, aPrevFrame);
|
|
|
|
}
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-04-21 23:58:38 +04:00
|
|
|
#endif
|
1999-11-24 09:03:41 +03:00
|
|
|
nsresult rv = AddFrames(aPresContext, aFrameList, aPrevFrame);
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
if (aListName != nsLayoutAtoms::nextBidi)
|
|
|
|
#endif // IBMBIDI
|
1999-02-02 20:31:09 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 06:58:05 +03:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 20:31:09 +03:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-06-18 20:25:41 +04:00
|
|
|
nsresult
|
1999-04-20 04:27:43 +04:00
|
|
|
nsBlockFrame::AddFrames(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrameList,
|
|
|
|
nsIFrame* aPrevSibling)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1999-04-20 04:27:43 +04:00
|
|
|
if (nsnull == aFrameList) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-12 06:00:51 +03:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
1999-04-20 04:27:43 +04:00
|
|
|
// Attempt to find the line that contains the previous sibling
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList::iterator prevSibLine = end_lines();
|
1999-04-21 01:51:39 +04:00
|
|
|
PRInt32 prevSiblingIndex = -1;
|
1999-04-20 04:27:43 +04:00
|
|
|
if (aPrevSibling) {
|
2001-10-25 05:08:40 +04:00
|
|
|
// XXX_perf This is technically O(N^2) in some cases, but by using
|
|
|
|
// RFind instead of Find, we make it O(N) in the most common case,
|
|
|
|
// which is appending cotent.
|
|
|
|
|
1999-11-01 18:24:57 +03:00
|
|
|
// Find the line that contains the previous sibling
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! nsLineBox::RFindLineContaining(aPrevSibling,
|
|
|
|
begin_lines(), prevSibLine,
|
|
|
|
&prevSiblingIndex)) {
|
|
|
|
// Note: defensive code! RFindLineContaining must not return
|
|
|
|
// false in this case, so if it does...
|
|
|
|
NS_NOTREACHED("prev sibling not in line list");
|
1999-11-01 18:24:57 +03:00
|
|
|
aPrevSibling = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
prevSibLine = end_lines();
|
1999-02-01 20:29:37 +03:00
|
|
|
}
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
|
1999-04-21 01:51:39 +04:00
|
|
|
// Find the frame following aPrevSibling so that we can join up the
|
|
|
|
// two lists of frames.
|
1999-04-20 04:27:43 +04:00
|
|
|
nsIFrame* prevSiblingNextFrame = nsnull;
|
|
|
|
if (aPrevSibling) {
|
|
|
|
aPrevSibling->GetNextSibling(&prevSiblingNextFrame);
|
1999-04-21 01:51:39 +04:00
|
|
|
|
|
|
|
// Split line containing aPrevSibling in two if the insertion
|
|
|
|
// point is somewhere in the middle of the line.
|
1999-10-15 03:10:03 +04:00
|
|
|
PRInt32 rem = prevSibLine->GetChildCount() - prevSiblingIndex - 1;
|
1999-04-21 01:51:39 +04:00
|
|
|
if (rem) {
|
|
|
|
// Split the line in two where the frame(s) are being inserted.
|
2000-03-12 06:00:51 +03:00
|
|
|
nsLineBox* line = NS_NewLineBox(presShell, prevSiblingNextFrame, rem, PR_FALSE);
|
1999-04-21 01:51:39 +04:00
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.after_insert(prevSibLine, line);
|
1999-10-15 03:10:03 +04:00
|
|
|
prevSibLine->SetChildCount(prevSibLine->GetChildCount() - rem);
|
1999-04-21 01:51:39 +04:00
|
|
|
prevSibLine->MarkDirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now (partially) join the sibling lists together
|
1999-04-20 07:42:32 +04:00
|
|
|
aPrevSibling->SetNextSibling(aFrameList);
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
else if (! mLines.empty()) {
|
|
|
|
prevSiblingNextFrame = mLines.front()->mFirstChild;
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Walk through the new frames being added and update the line data
|
|
|
|
// structures to fit.
|
1999-04-21 01:51:39 +04:00
|
|
|
nsIFrame* newFrame = aFrameList;
|
|
|
|
while (newFrame) {
|
1999-10-13 03:24:22 +04:00
|
|
|
PRBool isBlock = nsLineLayout::TreatFrameAsBlock(newFrame);
|
|
|
|
|
1999-04-21 01:51:39 +04: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.
|
2001-10-25 05:08:40 +04:00
|
|
|
if (isBlock || prevSibLine == end_lines() || prevSibLine->IsBlock()) {
|
1999-04-21 01:51:39 +04:00
|
|
|
// Create a new line for the frame and add its line to the line
|
|
|
|
// list.
|
2000-03-12 06:00:51 +03:00
|
|
|
nsLineBox* line = NS_NewLineBox(presShell, newFrame, 1, isBlock);
|
1999-04-20 04:27:43 +04:00
|
|
|
if (!line) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
if (prevSibLine != end_lines()) {
|
1999-04-20 07:42:32 +04:00
|
|
|
// Append new line after prevSibLine
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.after_insert(prevSibLine, line);
|
|
|
|
++prevSibLine;
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// New line is going before the other lines
|
2001-10-25 05:08:40 +04:00
|
|
|
mLines.push_front(line);
|
|
|
|
prevSibLine = begin_lines();
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
1999-02-01 20:29:37 +03:00
|
|
|
}
|
1999-04-20 04:27:43 +04:00
|
|
|
else {
|
1999-10-15 03:10:03 +04:00
|
|
|
prevSibLine->SetChildCount(prevSibLine->GetChildCount() + 1);
|
1999-04-21 01:51:39 +04:00
|
|
|
prevSibLine->MarkDirty();
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
1999-04-21 01:51:39 +04:00
|
|
|
|
|
|
|
aPrevSibling = newFrame;
|
|
|
|
newFrame->GetNextSibling(&newFrame);
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
1999-04-20 07:42:32 +04:00
|
|
|
if (prevSiblingNextFrame) {
|
1999-04-21 01:51:39 +04:00
|
|
|
// Connect the last new frame to the remainder of the sibling list
|
|
|
|
aPrevSibling->SetNextSibling(prevSiblingNextFrame);
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1999-02-02 20:31:09 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::RemoveFrame(nsIPresContext* aPresContext,
|
1999-02-26 20:04:44 +03:00
|
|
|
nsIPresShell& aPresShell,
|
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aOldFrame)
|
1999-02-02 20:31:09 +03:00
|
|
|
{
|
1999-02-26 20:04:44 +03:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
1999-09-22 04:58:58 +04:00
|
|
|
#ifdef NOISY_REFLOW_REASON
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": remove ");
|
1999-09-22 04:58:58 +04:00
|
|
|
nsFrame::ListTag(stdout, aOldFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("\n");
|
1999-09-22 04:58:58 +04:00
|
|
|
#endif
|
|
|
|
|
2002-01-06 21:17:41 +03:00
|
|
|
if (nsnull == aListName) {
|
|
|
|
rv = DoRemoveFrame(aPresContext, aOldFrame);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
return mAbsoluteContainer.RemoveFrame(this, aPresContext, aPresShell,
|
|
|
|
aListName, aOldFrame);
|
2000-05-09 09:06:16 +04:00
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 20:04:44 +03:00
|
|
|
// Find which line contains the floater
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
for ( ; line != line_end; ++line) {
|
1999-10-29 18:34:53 +04:00
|
|
|
if (line->IsInline() && line->RemoveFloater(aOldFrame)) {
|
2001-10-25 05:08:40 +04:00
|
|
|
break;
|
1999-02-26 20:04:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-10 17:38:55 +03:00
|
|
|
mFloaters.DestroyFrame(aPresContext, aOldFrame);
|
|
|
|
|
1999-02-26 20:04:44 +03:00
|
|
|
// Mark every line at and below the line where the floater was dirty
|
2001-10-25 05:08:40 +04:00
|
|
|
// XXXldb This could be done more efficiently.
|
|
|
|
for ( ; line != line_end; ++line) {
|
1999-02-26 20:04:44 +03:00
|
|
|
line->MarkDirty();
|
|
|
|
}
|
|
|
|
}
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
else if (nsLayoutAtoms::nextBidi == aListName) {
|
2002-01-06 21:17:41 +03:00
|
|
|
// Skip the call to |ReflowDirtyChild| below by returning now.
|
|
|
|
return DoRemoveFrame(aPresContext, aOldFrame);
|
2001-03-09 06:29:00 +03:00
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
1999-09-22 04:58:58 +04:00
|
|
|
else {
|
2002-01-06 21:17:41 +03:00
|
|
|
rv = NS_ERROR_INVALID_ARG;
|
1999-02-03 22:09:24 +03:00
|
|
|
}
|
1999-02-23 22:18:12 +03:00
|
|
|
|
1999-02-02 20:31:09 +03:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-01-19 06:58:05 +03:00
|
|
|
// Ask the parent frame to reflow me.
|
|
|
|
ReflowDirtyChild(&aPresShell, nsnull);
|
1999-02-02 20:31:09 +03:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
void
|
|
|
|
nsBlockFrame::DoRemoveOutOfFlowFrame(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
// First remove aFrame's next in flow
|
|
|
|
nsIFrame* nextInFlow;
|
|
|
|
aFrame->GetNextInFlow(&nextInFlow);
|
|
|
|
if (nextInFlow) {
|
|
|
|
nsBlockFrame::DoRemoveOutOfFlowFrame(aPresContext, nextInFlow);
|
|
|
|
}
|
|
|
|
// Now remove aFrame
|
|
|
|
const nsStyleDisplay* display = nsnull;
|
|
|
|
aFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)display);
|
|
|
|
NS_ASSERTION(display, "program error");
|
2002-07-02 18:56:18 +04:00
|
|
|
// find the containing block, this is either the parent or the grandparent
|
|
|
|
// if the parent is an inline frame
|
2002-05-29 02:50:43 +04:00
|
|
|
nsIFrame* parent;
|
|
|
|
aFrame->GetParent(&parent);
|
|
|
|
nsCOMPtr<nsIAtom> parentType;
|
|
|
|
parent->GetFrameType(getter_AddRefs(parentType));
|
2002-07-02 18:56:18 +04:00
|
|
|
while (parent && (nsLayoutAtoms::blockFrame != parentType) &&
|
|
|
|
(nsLayoutAtoms::areaFrame != parentType)) {
|
|
|
|
parent->GetParent(&parent);
|
|
|
|
parent->GetFrameType(getter_AddRefs(parentType));
|
|
|
|
}
|
|
|
|
if (!parent) {
|
|
|
|
NS_ASSERTION(PR_FALSE, "null parent");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
nsBlockFrame* block = (nsBlockFrame*)parent;
|
|
|
|
// Remove aFrame from the appropriate list.
|
|
|
|
if (display->IsAbsolutelyPositioned()) {
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
block->mAbsoluteContainer.RemoveFrame(block, aPresContext, *presShell,
|
|
|
|
nsLayoutAtoms::absoluteList, aFrame);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
block->mFloaters.RemoveFrame(aFrame);
|
|
|
|
}
|
|
|
|
// Destroy aFrame
|
|
|
|
nsSplittableFrame::RemoveFromFlow(aFrame);
|
|
|
|
aFrame->Destroy(aPresContext);
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
nsresult
|
1999-04-20 04:27:43 +04:00
|
|
|
nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
1999-02-18 21:25:45 +03:00
|
|
|
nsIFrame* aDeletedFrame)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
2002-05-29 02:50:43 +04:00
|
|
|
nsFrameState state;
|
|
|
|
aDeletedFrame->GetFrameState(&state);
|
|
|
|
if (state & NS_FRAME_OUT_OF_FLOW) {
|
|
|
|
DoRemoveOutOfFlowFrame(aPresContext, aDeletedFrame);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-12 06:00:51 +03:00
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(presShell));
|
|
|
|
|
1999-01-06 02:01:54 +03:00
|
|
|
// Find the line and the previous sibling that contains
|
|
|
|
// deletedFrame; we also find the pointer to the line.
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame* flow = this;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList& lines = flow->mLines;
|
|
|
|
nsLineList::iterator line = lines.begin(),
|
|
|
|
line_end = lines.end();
|
1999-01-06 02:01:54 +03:00
|
|
|
nsIFrame* prevSibling = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
for ( ; line != line_end; ++line) {
|
1999-01-06 02:01:54 +03:00
|
|
|
nsIFrame* frame = line->mFirstChild;
|
1999-10-15 03:10:03 +04:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1999-01-06 02:01:54 +03:00
|
|
|
while (--n >= 0) {
|
|
|
|
if (frame == aDeletedFrame) {
|
|
|
|
goto found_frame;
|
|
|
|
}
|
|
|
|
prevSibling = frame;
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-10-17 00:22:39 +04:00
|
|
|
}
|
1998-08-05 01:18:16 +04:00
|
|
|
}
|
1999-01-06 02:01:54 +03:00
|
|
|
found_frame:;
|
|
|
|
#ifdef NS_DEBUG
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(line != line_end, "can't find deleted frame in lines");
|
1999-01-06 02:01:54 +03:00
|
|
|
if (nsnull != prevSibling) {
|
|
|
|
nsIFrame* tmp;
|
1999-02-10 09:13:38 +03:00
|
|
|
prevSibling->GetNextSibling(&tmp);
|
1999-01-06 02:01:54 +03:00
|
|
|
NS_ASSERTION(tmp == aDeletedFrame, "bad prevSibling");
|
|
|
|
}
|
|
|
|
#endif
|
2002-01-15 01:05:26 +03:00
|
|
|
if (line == line_end)
|
|
|
|
return NS_ERROR_FAILURE;
|
1998-08-05 01:18:16 +04:00
|
|
|
|
1999-01-06 02:01:54 +03:00
|
|
|
// Remove frame and all of its continuations
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != aDeletedFrame) {
|
2001-10-25 05:08:40 +04:00
|
|
|
while ((line != line_end) && (nsnull != aDeletedFrame)) {
|
1998-06-24 21:52:42 +04:00
|
|
|
#ifdef NS_DEBUG
|
1999-08-31 07:09:40 +04:00
|
|
|
nsIFrame* parent;
|
1999-02-10 04:36:30 +03:00
|
|
|
aDeletedFrame->GetParent(&parent);
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_ASSERTION(flow == parent, "messed up delete code");
|
1999-03-16 22:36:00 +03:00
|
|
|
NS_ASSERTION(line->Contains(aDeletedFrame), "frame not in line");
|
1998-12-05 19:02:08 +03:00
|
|
|
#endif
|
|
|
|
|
1999-03-16 22:36:00 +03:00
|
|
|
// See if the frame being deleted is the last one on the line
|
|
|
|
PRBool isLastFrameOnLine = PR_FALSE;
|
1999-10-15 03:10:03 +04:00
|
|
|
if (1 == line->GetChildCount()) {
|
1999-03-16 22:36:00 +03:00
|
|
|
isLastFrameOnLine = PR_TRUE;
|
|
|
|
}
|
|
|
|
else if (line->LastChild() == aDeletedFrame) {
|
|
|
|
isLastFrameOnLine = PR_TRUE;
|
|
|
|
}
|
1999-01-06 02:01:54 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Remove aDeletedFrame from the line
|
1999-03-16 22:36:00 +03:00
|
|
|
nsIFrame* nextFrame;
|
|
|
|
aDeletedFrame->GetNextSibling(&nextFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (line->mFirstChild == aDeletedFrame) {
|
|
|
|
line->mFirstChild = nextFrame;
|
1999-02-18 21:25:45 +03:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
|
|
|
|
--line;
|
|
|
|
if (line != line_end && !line->IsBlock()) {
|
1999-04-20 04:27:43 +04:00
|
|
|
// Since we just removed a frame that follows some inline
|
|
|
|
// frames, we need to reflow the previous line.
|
2001-10-25 05:08:40 +04:00
|
|
|
line->MarkDirty();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
++line;
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-01-06 02:01:54 +03:00
|
|
|
// Take aDeletedFrame out of the sibling list. Note that
|
|
|
|
// prevSibling will only be nsnull when we are deleting the very
|
|
|
|
// first frame.
|
2001-10-25 05:08:40 +04:00
|
|
|
if (prevSibling) {
|
1999-01-06 02:01:54 +03:00
|
|
|
prevSibling->SetNextSibling(nextFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
|
2002-02-25 22:23:48 +03:00
|
|
|
// Update the child count of the line to be accurate
|
|
|
|
PRInt32 lineChildCount = line->GetChildCount();
|
|
|
|
lineChildCount--;
|
|
|
|
line->SetChildCount(lineChildCount);
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Destroy frame; capture its next-in-flow first in case we need
|
|
|
|
// to destroy that too.
|
|
|
|
nsIFrame* nextInFlow;
|
1999-02-24 07:48:08 +03:00
|
|
|
aDeletedFrame->GetNextInFlow(&nextInFlow);
|
1999-03-16 22:36:00 +03:00
|
|
|
nsSplittableType st;
|
|
|
|
aDeletedFrame->IsSplittable(st);
|
|
|
|
if (NS_FRAME_NOT_SPLITTABLE != st) {
|
1999-10-22 18:53:52 +04:00
|
|
|
nsSplittableFrame::RemoveFromFlow(aDeletedFrame);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef NOISY_REMOVE_FRAME
|
2001-10-25 05:08:40 +04:00
|
|
|
printf("DoRemoveFrame: line=%p frame=", line);
|
1999-03-16 22:36:00 +03:00
|
|
|
nsFrame::ListTag(stdout, aDeletedFrame);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(" prevSibling=%p nextInFlow=%p\n", prevSibling, nextInFlow);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1999-11-24 09:03:41 +03:00
|
|
|
aDeletedFrame->Destroy(aPresContext);
|
1998-12-05 19:02:08 +03:00
|
|
|
aDeletedFrame = nextInFlow;
|
|
|
|
|
|
|
|
// If line is empty, remove it now
|
2002-02-25 22:23:48 +03:00
|
|
|
if (0 == lineChildCount) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineBox *cur = line;
|
|
|
|
line = lines.erase(line);
|
1999-09-21 09:15:39 +04: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-15 03:10:03 +04:00
|
|
|
nsRect lineCombinedArea;
|
2001-10-25 05:08:40 +04:00
|
|
|
cur->GetCombinedArea(&lineCombinedArea);
|
2000-04-17 18:40:46 +04:00
|
|
|
#ifdef NOISY_BLOCK_INVALIDATE
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
2000-04-17 18:40:46 +04:00
|
|
|
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
|
|
|
#endif
|
2001-11-06 04:44:20 +03:00
|
|
|
if (!lineCombinedArea.IsEmpty()) {
|
|
|
|
Invalidate(aPresContext, lineCombinedArea);
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
cur->Destroy(presShell);
|
|
|
|
|
|
|
|
// If we're removing a line, ReflowDirtyLines isn't going to
|
|
|
|
// know that it needs to slide lines unless something is marked
|
|
|
|
// dirty. So mark the previous margin of the next line dirty if
|
|
|
|
// there is one.
|
|
|
|
if (line != line_end)
|
|
|
|
line->MarkPreviousMarginDirty();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-03-16 22:36:00 +03:00
|
|
|
// Make the line that just lost a frame dirty
|
1999-01-06 02:01:54 +03:00
|
|
|
line->MarkDirty();
|
1999-03-16 22:36:00 +03:00
|
|
|
|
|
|
|
// If we just removed the last frame on the line then we need
|
|
|
|
// to advance to the next line.
|
|
|
|
if (isLastFrameOnLine) {
|
2001-10-25 05:08:40 +04:00
|
|
|
++line;
|
1999-03-16 22:36:00 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1999-01-06 02:01:54 +03: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 04:55:38 +04:00
|
|
|
nsIFrame* checkParent;
|
|
|
|
aDeletedFrame->GetParent(&checkParent);
|
|
|
|
NS_ASSERTION(checkParent != flow, "strange continuation");
|
1999-01-06 02:01:54 +03:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Advance to next flow block if the frame has more continuations
|
2000-10-27 18:14:36 +04:00
|
|
|
if (flow && aDeletedFrame) {
|
1999-02-09 20:31:33 +03:00
|
|
|
flow = (nsBlockFrame*) flow->mNextInFlow;
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_ASSERTION(nsnull != flow, "whoops, continuation without a parent");
|
2000-10-27 18:14:36 +04:00
|
|
|
// add defensive pointer check for bug 56894
|
|
|
|
if(flow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
lines = flow->mLines;
|
|
|
|
line = lines.begin();
|
|
|
|
line_end = lines.end();
|
2000-10-27 18:14:36 +04:00
|
|
|
prevSibling = nsnull;
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1999-04-20 04:27:43 +04:00
|
|
|
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
1999-04-20 04:27:43 +04:00
|
|
|
VerifyLines(PR_TRUE);
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-01-16 01:53:39 +03:00
|
|
|
void
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::DeleteChildsNextInFlow(nsIPresContext* aPresContext,
|
2002-05-29 02:50:43 +04:00
|
|
|
nsIFrame* aChild)
|
1998-09-23 06:25:26 +04:00
|
|
|
{
|
2002-05-29 02:50:43 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsFrameState childState;
|
|
|
|
aChild->GetFrameState(&childState);
|
|
|
|
NS_PRECONDITION((childState & NS_FRAME_OUT_OF_FLOW) || IsChild(aPresContext, aChild),
|
|
|
|
"bad geometric parent");
|
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* nextInFlow;
|
1999-02-24 07:48:08 +03:00
|
|
|
aChild->GetNextInFlow(&nextInFlow);
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_PRECONDITION(nsnull != nextInFlow, "null next-in-flow");
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
nsIFrame* nextBidi;
|
|
|
|
aChild->GetBidiProperty(aPresContext, nsLayoutAtoms::nextBidi,
|
2001-06-21 16:35:48 +04:00
|
|
|
(void**) &nextBidi,sizeof(nextBidi));
|
2001-03-09 06:29:00 +03:00
|
|
|
if (nextBidi != nextInFlow) {
|
|
|
|
#endif // IBMBIDI
|
1999-03-16 22:36:00 +03:00
|
|
|
nsBlockFrame* parent;
|
1999-02-10 04:36:30 +03:00
|
|
|
nextInFlow->GetParent((nsIFrame**)&parent);
|
1999-03-16 22:36:00 +03:00
|
|
|
NS_PRECONDITION(nsnull != parent, "next-in-flow with no parent");
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_PRECONDITION(! parent->mLines.empty(), "next-in-flow with weird parent");
|
1999-11-03 02:42:52 +03:00
|
|
|
// NS_PRECONDITION(nsnull == parent->mOverflowLines, "parent with overflow");
|
1999-11-24 09:03:41 +03:00
|
|
|
parent->DoRemoveFrame(aPresContext, nextInFlow);
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
|
|
|
}
|
|
|
|
#endif // IBMBIDI
|
1998-10-03 01:50:53 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Floater support
|
|
|
|
|
1999-04-01 05:37:36 +04:00
|
|
|
nsresult
|
1999-03-23 07:28:20 +03:00
|
|
|
nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
|
|
|
nsPlaceholderFrame* aPlaceholder,
|
2002-05-29 02:50:43 +04:00
|
|
|
nsRect& aCombinedRectResult,
|
|
|
|
nsMargin& aMarginResult,
|
|
|
|
nsMargin& aComputedOffsetsResult,
|
|
|
|
nsReflowStatus& aReflowStatus)
|
1998-10-03 01:50:53 +04:00
|
|
|
{
|
2002-05-29 02:50:43 +04:00
|
|
|
// Delete the placeholder's next in flows, if any
|
|
|
|
nsIFrame* nextInFlow;
|
|
|
|
aPlaceholder->GetNextInFlow(&nextInFlow);
|
|
|
|
if (nextInFlow) {
|
|
|
|
nsHTMLContainerFrame* parent;
|
|
|
|
aPlaceholder->GetParent((nsIFrame**)&parent);
|
|
|
|
NS_ASSERTION(parent, "no parent");
|
|
|
|
parent->DeleteChildsNextInFlow(aState.mPresContext, aPlaceholder);
|
|
|
|
}
|
2001-05-22 03:03:46 +04:00
|
|
|
// Reflow the floater.
|
|
|
|
nsIFrame* floater = aPlaceholder->GetOutOfFlowFrame();
|
2002-05-29 02:50:43 +04:00
|
|
|
aReflowStatus = NS_FRAME_COMPLETE;
|
2001-05-22 03:03:46 +04:00
|
|
|
|
2000-06-12 02:14:33 +04:00
|
|
|
#ifdef NOISY_FLOATER
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("Reflow Floater %p in parent %p, availSpace(%d,%d,%d,%d)\n",
|
2000-06-12 02:14:33 +04:00
|
|
|
aPlaceholder->GetOutOfFlowFrame(), this,
|
|
|
|
aState.mAvailSpaceRect.x, aState.mAvailSpaceRect.y,
|
|
|
|
aState.mAvailSpaceRect.width, aState.mAvailSpaceRect.height
|
2000-10-29 02:17:53 +04:00
|
|
|
);
|
2000-06-12 02:14:33 +04:00
|
|
|
#endif
|
1999-09-10 22:52:56 +04:00
|
|
|
|
2001-05-22 03:03:46 +04:00
|
|
|
// Compute the available width. By default, assume the width of the
|
2001-07-19 06:33:43 +04:00
|
|
|
// containing block.
|
2002-03-08 23:25:54 +03:00
|
|
|
nscoord availWidth;
|
2002-05-29 02:50:43 +04:00
|
|
|
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
2002-03-08 23:25:54 +03:00
|
|
|
availWidth = NS_UNCONSTRAINEDSIZE;
|
2002-05-29 02:50:43 +04:00
|
|
|
}
|
|
|
|
else {
|
2002-03-08 23:25:54 +03:00
|
|
|
const nsStyleDisplay* floaterDisplay;
|
|
|
|
floater->GetStyleData(eStyleStruct_Display,
|
|
|
|
(const nsStyleStruct*&)floaterDisplay);
|
|
|
|
nsCompatibility mode;
|
|
|
|
aState.mPresContext->GetCompatibilityMode(&mode);
|
|
|
|
|
2002-05-29 02:50:43 +04:00
|
|
|
nsIFrame* prevInFlow;
|
|
|
|
floater->GetPrevInFlow(&prevInFlow);
|
|
|
|
// if the floater is continued, constrain its width to the prev-in-flow's width
|
|
|
|
if (prevInFlow) {
|
|
|
|
nsRect rect;
|
|
|
|
prevInFlow->GetRect(rect);
|
|
|
|
availWidth = rect.width;
|
|
|
|
}
|
|
|
|
else if (NS_STYLE_DISPLAY_TABLE != floaterDisplay->mDisplay ||
|
|
|
|
eCompatibility_NavQuirks != mode ) {
|
2002-03-08 23:25:54 +03:00
|
|
|
availWidth = aState.mContentArea.width;
|
2002-05-29 02:50:43 +04:00
|
|
|
}
|
|
|
|
else {
|
2002-03-08 23:25:54 +03:00
|
|
|
// give tables only the available space
|
|
|
|
// if they can shrink we may not be constrained to place
|
|
|
|
// them in the next line
|
|
|
|
availWidth = aState.mAvailSpaceRect.width;
|
|
|
|
// round down to twips per pixel so that we fit
|
|
|
|
// needed when prev. floater has procentage width
|
|
|
|
// (maybe is a table flaw that makes table chose to round up
|
|
|
|
// but i don't want to change that, too risky)
|
|
|
|
nscoord twp;
|
|
|
|
float p2t;
|
|
|
|
aState.mPresContext->GetScaledPixelsToTwips(&p2t);
|
|
|
|
twp = NSIntPixelsToTwips(1,p2t);
|
|
|
|
availWidth -= availWidth % twp;
|
|
|
|
}
|
|
|
|
}
|
2002-06-04 08:37:06 +04:00
|
|
|
nscoord availHeight = ((NS_UNCONSTRAINEDSIZE == aState.mAvailSpaceRect.height) ||
|
|
|
|
(NS_UNCONSTRAINEDSIZE == aState.mContentArea.height))
|
2002-05-29 02:50:43 +04:00
|
|
|
? NS_UNCONSTRAINEDSIZE
|
|
|
|
: PR_MAX(0, aState.mContentArea.height - aState.mY);
|
2001-05-22 03:03:46 +04:00
|
|
|
|
|
|
|
// If the floater's width is automatic, we can't let the floater's
|
|
|
|
// width shrink below its maxElementSize.
|
|
|
|
const nsStylePosition* position;
|
2001-07-19 06:33:43 +04:00
|
|
|
floater->GetStyleData(eStyleStruct_Position,
|
|
|
|
NS_REINTERPRET_CAST(const nsStyleStruct*&, position));
|
2001-05-22 03:03:46 +04:00
|
|
|
PRBool isAutoWidth = (eStyleUnit_Auto == position->mWidth.GetUnit());
|
|
|
|
|
|
|
|
// We'll need to compute the max element size if either 1) we're
|
2001-07-19 06:33:43 +04:00
|
|
|
// auto-width or 2) the state wanted us to compute it anyway.
|
2001-05-22 03:03:46 +04:00
|
|
|
PRBool computeMaxElementSize =
|
2001-07-19 06:33:43 +04:00
|
|
|
isAutoWidth || aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
|
|
|
|
|
|
|
nsRect availSpace(aState.BorderPadding().left,
|
|
|
|
aState.BorderPadding().top,
|
2002-05-29 02:50:43 +04:00
|
|
|
availWidth, availHeight);
|
1999-04-01 05:37:36 +04:00
|
|
|
|
2002-09-04 10:55:40 +04:00
|
|
|
// construct the html reflow state for the floater. ReflowBlock will
|
|
|
|
// initialize it and set its reason.
|
|
|
|
nsHTMLReflowState floaterRS(aState.mPresContext, aState.mReflowState, floater,
|
|
|
|
nsSize(availSpace.width, availSpace.height),
|
|
|
|
aState.mReflowState.reason, PR_FALSE);
|
2001-05-22 03:03:46 +04:00
|
|
|
// Setup a block reflow state to reflow the floater.
|
1999-04-01 05:37:36 +04:00
|
|
|
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
2001-05-22 03:03:46 +04:00
|
|
|
computeMaxElementSize,
|
2000-04-17 18:40:46 +04:00
|
|
|
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
2001-05-22 03:03:46 +04:00
|
|
|
|
1999-04-01 05:37:36 +04:00
|
|
|
// Reflow the floater
|
2001-05-22 03:03:46 +04:00
|
|
|
PRBool isAdjacentWithTop = aState.IsAdjacentWithTop();
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCollapsingMargin margin;
|
2002-09-04 10:55:40 +04:00
|
|
|
nsresult rv = brc.ReflowBlock(availSpace, PR_TRUE, margin, isAdjacentWithTop,
|
|
|
|
aComputedOffsetsResult, floaterRS, aReflowStatus);
|
2002-06-14 18:30:33 +04:00
|
|
|
// An incomplete reflow status means we should split the floater
|
|
|
|
// if the height is constrained (bug 145305).
|
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(aReflowStatus) && (NS_UNCONSTRAINEDSIZE == availHeight))
|
|
|
|
aReflowStatus = NS_FRAME_COMPLETE;
|
|
|
|
|
2001-07-19 06:33:43 +04:00
|
|
|
if (NS_SUCCEEDED(rv) && isAutoWidth) {
|
|
|
|
nscoord maxElementWidth = brc.GetMaxElementSize().width;
|
|
|
|
if (maxElementWidth > availSpace.width) {
|
2001-05-22 03:03:46 +04:00
|
|
|
// The floater's maxElementSize is larger than the available
|
|
|
|
// width. Reflow it again, this time pinning the width to the
|
|
|
|
// maxElementSize.
|
2001-07-19 06:33:43 +04:00
|
|
|
availSpace.width = maxElementWidth;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCollapsingMargin marginMES;
|
2002-09-04 10:55:40 +04:00
|
|
|
// construct the html reflow state for the floater.
|
|
|
|
// ReflowBlock will initialize it and set its reason.
|
|
|
|
nsHTMLReflowState redoFloaterRS(aState.mPresContext, aState.mReflowState, floater,
|
|
|
|
nsSize(availSpace.width, availSpace.height),
|
|
|
|
aState.mReflowState.reason, PR_FALSE);
|
|
|
|
rv = brc.ReflowBlock(availSpace, PR_TRUE, marginMES, isAdjacentWithTop,
|
|
|
|
aComputedOffsetsResult, redoFloaterRS, aReflowStatus);
|
2001-05-22 03:03:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-11-06 04:44:20 +03:00
|
|
|
if (brc.BlockShouldInvalidateItself() && !mRect.IsEmpty()) {
|
2000-05-09 09:06:16 +04:00
|
|
|
Invalidate(aState.mPresContext, mRect);
|
|
|
|
}
|
2001-05-22 03:03:46 +04:00
|
|
|
|
2002-05-10 22:22:41 +04:00
|
|
|
// Remove the floater from the reflow tree.
|
|
|
|
if (aState.mReflowState.path)
|
|
|
|
aState.mReflowState.path->RemoveChild(floater);
|
2001-05-22 03:03:46 +04:00
|
|
|
|
1999-04-01 05:37:36 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
1998-11-11 06:55:55 +03:00
|
|
|
}
|
1999-04-01 05:37:36 +04:00
|
|
|
|
|
|
|
// Capture the margin information for the caller
|
|
|
|
const nsMargin& m = brc.GetMargin();
|
|
|
|
aMarginResult.top = brc.GetTopMargin();
|
|
|
|
aMarginResult.right = m.right;
|
2001-10-25 05:08:40 +04:00
|
|
|
brc.GetCarriedOutBottomMargin().Include(m.bottom);
|
|
|
|
aMarginResult.bottom = brc.GetCarriedOutBottomMargin().get();
|
1999-04-01 05:37:36 +04:00
|
|
|
aMarginResult.left = m.left;
|
|
|
|
|
|
|
|
const nsHTMLReflowMetrics& metrics = brc.GetMetrics();
|
2001-05-22 03:03:46 +04:00
|
|
|
aCombinedRectResult = metrics.mOverflowArea;
|
|
|
|
|
1999-11-30 08:09:08 +03:00
|
|
|
// Set the rect, make sure the view is properly sized and positioned,
|
|
|
|
// and tell the frame we're done reflowing it
|
2001-10-25 05:08:40 +04:00
|
|
|
// XXXldb This seems like the wrong place to be doing this -- shouldn't
|
|
|
|
// we be doing this in nsBlockReflowState::FlowAndPlaceFloater after
|
|
|
|
// we've positioned the floater, and shouldn't we be doing the equivalent
|
|
|
|
// of |::PlaceFrameView| here?
|
1999-10-26 08:44:41 +04:00
|
|
|
floater->SizeTo(aState.mPresContext, metrics.width, metrics.height);
|
1999-11-30 08:09:08 +03:00
|
|
|
nsIView* view;
|
|
|
|
floater->GetView(aState.mPresContext, &view);
|
|
|
|
if (view) {
|
|
|
|
nsContainerFrame::SyncFrameViewAfterReflow(aState.mPresContext, floater, view,
|
1999-12-06 18:49:53 +03:00
|
|
|
&metrics.mOverflowArea,
|
1999-11-30 08:09:08 +03:00
|
|
|
NS_FRAME_NO_MOVE_VIEW);
|
|
|
|
}
|
2002-09-04 10:55:40 +04:00
|
|
|
// Pass floaterRS so the frame hierarchy can be used (redoFloaterRS has the same hierarchy)
|
|
|
|
floater->DidReflow(aState.mPresContext, &floaterRS, NS_FRAME_REFLOW_FINISHED);
|
1999-10-22 00:43:48 +04:00
|
|
|
|
2000-01-28 06:12:30 +03:00
|
|
|
// If we computed it, then stash away the max-element-size for later
|
2001-07-19 06:33:43 +04:00
|
|
|
if (computeMaxElementSize) {
|
2000-05-09 09:06:16 +04:00
|
|
|
nsSize mes = brc.GetMaxElementSize();
|
|
|
|
mes.SizeBy(aMarginResult.left + aMarginResult.right,
|
|
|
|
aMarginResult.top + aMarginResult.bottom);
|
|
|
|
aState.StoreMaxElementSize(floater, mes);
|
2001-01-28 20:00:19 +03:00
|
|
|
aState.UpdateMaxElementSize(mes); // fix for bug 13553
|
2000-01-28 06:12:30 +03:00
|
|
|
}
|
2000-06-12 02:14:33 +04:00
|
|
|
#ifdef NOISY_FLOATER
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("end ReflowFloater %p, sized to %d,%d\n", floater, metrics.width, metrics.height);
|
2000-06-12 02:14:33 +04:00
|
|
|
#endif
|
2002-07-17 05:48:56 +04:00
|
|
|
|
|
|
|
// If the placeholder was continued and its first-in-flow was followed by a
|
|
|
|
// <BR>, then cache the <BR>'s break type in aState.mFloaterBreakType so that
|
|
|
|
// the next frame after the placeholder can combine that break type with its own
|
|
|
|
nsIFrame* prevPlaceholder = nsnull;
|
|
|
|
aPlaceholder->GetPrevInFlow(&prevPlaceholder);
|
|
|
|
if (prevPlaceholder) {
|
|
|
|
// the break occurs only after the last continued placeholder
|
|
|
|
PRBool lastPlaceholder = PR_TRUE;
|
|
|
|
nsIFrame* next;
|
|
|
|
aPlaceholder->GetNextSibling(&next);
|
|
|
|
if (next) {
|
|
|
|
nsCOMPtr<nsIAtom> nextType;
|
|
|
|
next->GetFrameType(getter_AddRefs(nextType));
|
|
|
|
if (nsLayoutAtoms::placeholderFrame == nextType) {
|
|
|
|
lastPlaceholder = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lastPlaceholder) {
|
|
|
|
// get the containing block of prevPlaceholder which is our prev-in-flow
|
|
|
|
if (mPrevInFlow) {
|
|
|
|
// get the break type of the last line in mPrevInFlow
|
|
|
|
line_iterator endLine = --((nsBlockFrame*)mPrevInFlow)->end_lines();
|
|
|
|
PRUint8 breakType = endLine->GetBreakType();
|
|
|
|
if ((NS_STYLE_CLEAR_LEFT == breakType) ||
|
|
|
|
(NS_STYLE_CLEAR_RIGHT == breakType) ||
|
|
|
|
(NS_STYLE_CLEAR_LEFT_AND_RIGHT == breakType)) {
|
|
|
|
aState.mFloaterBreakType = breakType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else NS_ASSERTION(PR_FALSE, "no prev in flow");
|
|
|
|
}
|
|
|
|
}
|
1999-04-01 05:37:36 +04:00
|
|
|
return NS_OK;
|
1998-11-11 06:55:55 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Painting, event handling
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
PRIntn
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::GetSkipSides() const
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
|
|
|
PRIntn skip = 0;
|
|
|
|
if (nsnull != mPrevInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_TOP;
|
1998-09-30 02:32:56 +04:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
if (nsnull != mNextInFlow) {
|
|
|
|
skip |= 1 << NS_SIDE_BOTTOM;
|
1998-11-11 06:55:55 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
return skip;
|
|
|
|
}
|
1998-09-30 02:32:56 +04:00
|
|
|
|
1999-10-20 03:04:19 +04:00
|
|
|
#ifdef DEBUG
|
2001-10-25 05:08:40 +04:00
|
|
|
static void ComputeCombinedArea(nsLineList& aLines,
|
1999-03-23 01:42:30 +03:00
|
|
|
nscoord aWidth, nscoord aHeight,
|
|
|
|
nsRect& aResult)
|
|
|
|
{
|
1999-05-13 04:55:38 +04:00
|
|
|
nscoord xa = 0, ya = 0, xb = aWidth, yb = aHeight;
|
2001-10-25 05:08:40 +04:00
|
|
|
for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-03-23 01:42:30 +03:00
|
|
|
// Compute min and max x/y values for the reflowed frame's
|
|
|
|
// combined areas
|
1999-10-20 03:04:19 +04:00
|
|
|
nsRect lineCombinedArea;
|
2001-10-25 05:08:40 +04:00
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
1999-10-20 03:04:19 +04:00
|
|
|
nscoord x = lineCombinedArea.x;
|
|
|
|
nscoord y = lineCombinedArea.y;
|
|
|
|
nscoord xmost = x + lineCombinedArea.width;
|
|
|
|
nscoord ymost = y + lineCombinedArea.height;
|
1999-05-13 04:55:38 +04:00
|
|
|
if (x < xa) {
|
|
|
|
xa = x;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (xmost > xb) {
|
|
|
|
xb = xmost;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (y < ya) {
|
|
|
|
ya = y;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
1999-05-13 04:55:38 +04:00
|
|
|
if (ymost > yb) {
|
|
|
|
yb = ymost;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-05-13 04:55:38 +04:00
|
|
|
aResult.x = xa;
|
|
|
|
aResult.y = ya;
|
|
|
|
aResult.width = xb - xa;
|
|
|
|
aResult.height = yb - ya;
|
1999-03-23 01:42:30 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-03-08 05:46:44 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::IsVisibleForPainting(nsIPresContext * aPresContext,
|
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
PRBool aCheckVis,
|
|
|
|
PRBool* aIsVisible)
|
|
|
|
{
|
|
|
|
// first check to see if we are visible
|
|
|
|
if (aCheckVis) {
|
2001-06-01 02:19:43 +04:00
|
|
|
const nsStyleVisibility* vis =
|
|
|
|
(const nsStyleVisibility*)((nsIStyleContext*)mStyleContext)->GetStyleData(eStyleStruct_Visibility);
|
|
|
|
if (!vis->IsVisible()) {
|
2001-03-08 05:46:44 +03:00
|
|
|
*aIsVisible = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start by assuming we are visible and need to be painted
|
|
|
|
*aIsVisible = PR_TRUE;
|
|
|
|
|
|
|
|
// NOTE: GetSelectionforVisCheck checks the pagination to make sure we are printing
|
|
|
|
// In otherwords, the selection will ALWAYS be null if we are not printing, meaning
|
|
|
|
// the visibility will be TRUE in that case
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
nsresult rv = GetSelectionForVisCheck(aPresContext, getter_AddRefs(selection));
|
|
|
|
if (NS_SUCCEEDED(rv) && selection) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMHTMLHtmlElement> html(do_QueryInterface(mContent));
|
|
|
|
nsCOMPtr<nsIDOMHTMLBodyElement> body(do_QueryInterface(mContent));
|
|
|
|
|
|
|
|
if (!html && !body) {
|
|
|
|
rv = selection->ContainsNode(node, PR_TRUE, aIsVisible);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::Paint(nsIPresContext* aPresContext,
|
1999-03-26 03:39:04 +03:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect,
|
2001-09-19 16:35:19 +04:00
|
|
|
nsFramePaintLayer aWhichLayer,
|
|
|
|
PRUint32 aFlags)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-08-28 01:45:37 +04:00
|
|
|
if (NS_FRAME_IS_UNFLOWABLE & mState) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-10-20 03:04:19 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyDamageRepair) {
|
|
|
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
|
|
|
PRInt32 depth = GetDepth();
|
|
|
|
nsRect ca;
|
2002-09-24 15:43:48 +04:00
|
|
|
::ComputeCombinedArea(mLines, mRect.width, mRect.height, ca);
|
1999-10-20 03:04:19 +04:00
|
|
|
nsFrame::IndentBy(stdout, depth);
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
1999-10-20 03:04:19 +04: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 23:46:09 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-03-08 05:46:44 +03:00
|
|
|
PRBool isVisible;
|
|
|
|
if (NS_FAILED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible))) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2001-01-27 17:09:34 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Only paint the border and background if we're visible
|
2001-03-08 05:46:44 +03:00
|
|
|
if (isVisible && (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) &&
|
1999-03-20 02:05:56 +03:00
|
|
|
(0 != mRect.width) && (0 != mRect.height)) {
|
1998-12-05 19:02:08 +03:00
|
|
|
PRIntn skipSides = GetSkipSides();
|
2001-02-07 12:57:26 +03:00
|
|
|
const nsStyleBorder* border = (const nsStyleBorder*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Border);
|
|
|
|
const nsStyleOutline* outline = (const nsStyleOutline*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Outline);
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1999-10-20 03:04:19 +04:00
|
|
|
// Paint background, border and outline
|
1998-12-05 19:02:08 +03:00
|
|
|
nsRect rect(0, 0, mRect.width, mRect.height);
|
|
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
|
2002-01-08 02:46:07 +03:00
|
|
|
aDirtyRect, rect, *border, 0, 0);
|
1998-12-05 19:02:08 +03:00
|
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
|
2001-02-07 12:57:26 +03:00
|
|
|
aDirtyRect, rect, *border, mStyleContext,
|
1999-02-09 20:31:33 +03:00
|
|
|
skipSides);
|
1999-10-20 03:04:19 +04:00
|
|
|
nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
|
2002-01-08 02:46:07 +03:00
|
|
|
aDirtyRect, rect, *border, *outline,
|
|
|
|
mStyleContext, 0);
|
1998-10-31 01:10:10 +03:00
|
|
|
}
|
|
|
|
|
2001-04-25 23:52:49 +04:00
|
|
|
PRBool paintingSuppressed = PR_FALSE;
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
shell->IsPaintingSuppressed(&paintingSuppressed);
|
|
|
|
if (paintingSuppressed)
|
|
|
|
return NS_OK;
|
|
|
|
|
2001-03-08 05:46:44 +03:00
|
|
|
const nsStyleDisplay* disp = (const nsStyleDisplay*)
|
|
|
|
mStyleContext->GetStyleData(eStyleStruct_Display);
|
|
|
|
|
2000-04-25 08:43:11 +04: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 19:02:08 +03:00
|
|
|
// Child elements have the opportunity to override the visibility
|
|
|
|
// property and display even if the parent is hidden
|
1999-03-26 03:39:04 +03:00
|
|
|
if (NS_FRAME_PAINT_LAYER_FLOATERS == aWhichLayer) {
|
|
|
|
PaintFloaters(aPresContext, aRenderingContext, aDirtyRect);
|
|
|
|
}
|
1998-12-18 18:54:23 +03:00
|
|
|
PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
|
1998-10-03 01:50:53 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
if (NS_STYLE_OVERFLOW_HIDDEN == disp->mOverflow) {
|
|
|
|
PRBool clipState;
|
|
|
|
aRenderingContext.PopState(clipState);
|
1998-07-09 21:06:35 +04:00
|
|
|
}
|
1998-12-18 18:54:23 +03:00
|
|
|
|
1999-10-08 08:45:12 +04:00
|
|
|
#if 0
|
|
|
|
if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
|
|
|
|
// Render the bands in the spacemanager
|
2001-10-26 09:06:07 +04:00
|
|
|
nsSpaceManager* sm = mSpaceManager;
|
1999-10-08 08:45:12 +04:00
|
|
|
|
|
|
|
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 19:02:08 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-07-09 21:06:35 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::PaintFloaters(nsIPresContext* aPresContext,
|
1999-03-26 03:39:04 +03:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
|
|
|
const nsRect& aDirtyRect)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-10-15 03:10:03 +04:00
|
|
|
if (!line->HasFloaters()) {
|
1998-12-05 19:02:08 +03:00
|
|
|
continue;
|
1998-06-25 20:33:10 +04:00
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 04:28:10 +04:00
|
|
|
while (fc) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
1998-12-05 19:02:08 +03:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 04:28:10 +04:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_BACKGROUND);
|
1999-03-26 03:39:04 +03:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 04:28:10 +04:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_FLOATERS);
|
1999-03-26 03:39:04 +03:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect,
|
1999-09-15 04:28:10 +04:00
|
|
|
floater, NS_FRAME_PAINT_LAYER_FOREGROUND);
|
|
|
|
fc = fc->Next();
|
1998-06-25 20:33:10 +04:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-06-25 20:33:10 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
2001-09-19 16:35:19 +04:00
|
|
|
nsBlockFrame::PaintChildren(nsIPresContext* aPresContext,
|
1999-03-22 23:46:09 +03:00
|
|
|
nsIRenderingContext& aRenderingContext,
|
2001-09-19 16:35:19 +04:00
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsFramePaintLayer aWhichLayer,
|
|
|
|
PRUint32 aFlags)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-10-20 03:04:19 +04:00
|
|
|
#ifdef DEBUG
|
1999-03-22 23:46:09 +03:00
|
|
|
PRInt32 depth = 0;
|
1999-10-20 03:04:19 +04:00
|
|
|
if (gNoisyDamageRepair) {
|
|
|
|
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
|
|
|
|
depth = GetDepth();
|
|
|
|
}
|
|
|
|
}
|
2000-11-28 02:23:28 +03: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-20 03:04:19 +04:00
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
start = PR_Now();
|
|
|
|
drawnLines = 0;
|
1999-03-22 23:46:09 +03:00
|
|
|
}
|
|
|
|
#endif
|
1999-10-20 03:04:19 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-10-20 03:04:19 +04: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 23:46:09 +03:00
|
|
|
nsFrame::IndentBy(stdout, depth+1);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("draw line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_STATIC_CAST(void*, line.get()),
|
|
|
|
line->mBounds.x, line->mBounds.y,
|
1999-03-22 23:46:09 +03:00
|
|
|
line->mBounds.width, line->mBounds.height,
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
1999-03-22 23:46:09 +03:00
|
|
|
}
|
1999-10-20 03:04:19 +04:00
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
drawnLines++;
|
|
|
|
}
|
1999-03-22 23:46:09 +03:00
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* kid = line->mFirstChild;
|
1999-10-15 03:10:03 +04:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1998-12-05 19:02:08 +03:00
|
|
|
while (--n >= 0) {
|
1998-12-18 18:54:23 +03:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect, kid,
|
|
|
|
aWhichLayer);
|
1999-02-10 09:13:38 +03:00
|
|
|
kid->GetNextSibling(&kid);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
1999-10-20 03:04:19 +04:00
|
|
|
#ifdef DEBUG
|
1999-03-22 23:46:09 +03:00
|
|
|
else {
|
1999-10-20 03:04:19 +04:00
|
|
|
if (gNoisyDamageRepair &&
|
|
|
|
(NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
|
|
|
|
nsRect lineCombinedArea;
|
|
|
|
line->GetCombinedArea(&lineCombinedArea);
|
1999-03-22 23:46:09 +03:00
|
|
|
nsFrame::IndentBy(stdout, depth+1);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf("skip line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_STATIC_CAST(void*, line.get()),
|
|
|
|
line->mBounds.x, line->mBounds.y,
|
1999-03-22 23:46:09 +03:00
|
|
|
line->mBounds.width, line->mBounds.height,
|
1999-10-15 03:10:03 +04:00
|
|
|
lineCombinedArea.x, lineCombinedArea.y,
|
|
|
|
lineCombinedArea.width, lineCombinedArea.height);
|
1999-03-22 23:46:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
1999-02-09 20:31:33 +03:00
|
|
|
|
1999-03-26 03:39:04 +03:00
|
|
|
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
|
1999-02-19 01:22:55 +03:00
|
|
|
if ((nsnull != mBullet) && HaveOutsideBullet()) {
|
1999-02-09 20:31:33 +03:00
|
|
|
// Paint outside bullets manually
|
1999-02-19 01:22:55 +03:00
|
|
|
PaintChild(aPresContext, aRenderingContext, aDirtyRect, mBullet,
|
|
|
|
aWhichLayer);
|
1999-02-09 20:31:33 +03:00
|
|
|
}
|
|
|
|
}
|
1999-10-20 03:04:19 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gLamePaintMetrics) {
|
|
|
|
PRTime end = PR_Now();
|
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
PRInt32 numLines = mLines.size();
|
1999-10-20 03:04:19 +04:00
|
|
|
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-29 02:17:53 +04:00
|
|
|
printf("%s\n", buf);
|
1999-10-20 03:04:19 +04:00
|
|
|
}
|
|
|
|
#endif
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2001-07-04 06:00:05 +04:00
|
|
|
// XXXldb Does this handle all overlap cases correctly? (How?)
|
2001-05-11 12:04:29 +04:00
|
|
|
nsresult
|
|
|
|
nsBlockFrame::GetClosestLine(nsILineIterator *aLI,
|
|
|
|
const nsPoint &aOrigin,
|
|
|
|
const nsPoint &aPoint,
|
|
|
|
PRInt32 &aClosestLine)
|
|
|
|
{
|
|
|
|
if (!aLI)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
2001-06-25 18:06:19 +04:00
|
|
|
|
2001-05-11 12:04:29 +04:00
|
|
|
nsRect rect;
|
2001-06-25 18:06:19 +04:00
|
|
|
PRInt32 numLines;
|
2001-05-11 12:04:29 +04:00
|
|
|
PRInt32 lineFrameCount;
|
|
|
|
nsIFrame *firstFrame;
|
|
|
|
PRUint32 flags;
|
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
nsresult result = aLI->GetNumLines(&numLines);
|
2001-05-11 12:04:29 +04:00
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
if (NS_FAILED(result) || numLines < 0)
|
2001-05-11 12:04:29 +04:00
|
|
|
return NS_OK;//do not handle
|
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
PRInt32 shifted = numLines;
|
|
|
|
PRInt32 start = 0, midpoint = 0;
|
2001-05-11 12:04:29 +04:00
|
|
|
PRInt32 y = 0;
|
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
while(shifted > 0)
|
2001-05-11 12:04:29 +04:00
|
|
|
{
|
2001-06-25 18:06:19 +04:00
|
|
|
// Cut the number of lines to look at in half and
|
|
|
|
// calculate the midpoint of the region we are looking at.
|
|
|
|
|
2001-05-11 12:04:29 +04:00
|
|
|
shifted >>= 1; //divide by 2
|
2001-06-25 18:06:19 +04:00
|
|
|
midpoint = start + shifted;
|
|
|
|
|
|
|
|
// Get the dimensions of the line that is at the half
|
|
|
|
// point of the region we are looking at.
|
|
|
|
|
|
|
|
result = aLI->GetLine(midpoint, &firstFrame, &lineFrameCount,rect,&flags);
|
2001-05-11 12:04:29 +04:00
|
|
|
if (NS_FAILED(result))
|
|
|
|
break;//do not handle
|
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
// Check to see if our point lies with the line's Y bounds.
|
|
|
|
|
2001-05-11 12:04:29 +04:00
|
|
|
rect+=aOrigin; //offset origin to get comparative coordinates
|
|
|
|
|
|
|
|
y = aPoint.y - rect.y;
|
|
|
|
if (y >=0 && (aPoint.y < (rect.y+rect.height)))
|
|
|
|
{
|
2001-06-25 18:06:19 +04:00
|
|
|
aClosestLine = midpoint; //spot on!
|
2001-05-11 12:04:29 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-06-25 18:06:19 +04:00
|
|
|
|
|
|
|
if (y > 0)
|
|
|
|
{
|
|
|
|
// If we get here, no match was found above, so aPoint.y must
|
|
|
|
// be greater than the Y bounds of the current line rect. Move
|
|
|
|
// our starting point just beyond the midpoint of the current region.
|
|
|
|
|
|
|
|
start = midpoint;
|
|
|
|
|
|
|
|
if (numLines > 1 && start < (numLines - 1))
|
|
|
|
++start;
|
|
|
|
else
|
|
|
|
shifted = 0;
|
|
|
|
}
|
2001-05-11 12:04:29 +04:00
|
|
|
}
|
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
// Make sure we don't go off the edge in either direction!
|
|
|
|
|
|
|
|
NS_ASSERTION(start >=0 && start <= numLines, "Invalid start calculated.");
|
2001-05-11 12:04:29 +04:00
|
|
|
|
2001-06-25 18:06:19 +04:00
|
|
|
if (start < 0)
|
|
|
|
start = 0;
|
|
|
|
else if (start >= numLines)
|
|
|
|
start = numLines - 1;
|
2001-05-11 12:04:29 +04:00
|
|
|
|
|
|
|
aClosestLine = start; //close as we could come
|
2001-06-25 18:06:19 +04:00
|
|
|
|
2001-05-11 12:04:29 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-08-25 01:51:47 +04:00
|
|
|
|
1999-04-14 01:29:08 +04:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::HandleEvent(nsIPresContext* aPresContext,
|
1999-04-14 01:29:08 +04:00
|
|
|
nsGUIEvent* aEvent,
|
1999-11-24 09:03:41 +03:00
|
|
|
nsEventStatus* aEventStatus)
|
1999-04-14 01:29:08 +04:00
|
|
|
{
|
2000-05-11 08:25:43 +04:00
|
|
|
|
|
|
|
nsresult result;
|
2000-05-11 08:50:16 +04:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
1999-08-25 01:51:47 +04:00
|
|
|
if (aEvent->message == NS_MOUSE_MOVE) {
|
2000-05-11 08:50:16 +04:00
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
if (!shell)
|
|
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIFrameSelection> frameSelection;
|
2000-05-11 08:25:43 +04:00
|
|
|
PRBool mouseDown = PR_FALSE;
|
2000-05-11 08:50:16 +04: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 08:25:43 +04:00
|
|
|
if (!frameSelection || NS_FAILED(frameSelection->GetMouseDownState(&mouseDown)) || !mouseDown)
|
|
|
|
return NS_OK;//do not handle
|
1999-08-25 01:51:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN || aEvent->message == NS_MOUSE_MOVE ||
|
|
|
|
aEvent->message == NS_MOUSE_LEFT_DOUBLECLICK ) {
|
2000-04-14 00:21:32 +04:00
|
|
|
|
2000-09-15 11:02:05 +04:00
|
|
|
nsMouseEvent *me = (nsMouseEvent *)aEvent;
|
2000-04-14 00:21:32 +04:00
|
|
|
|
1999-09-02 01:40:16 +04:00
|
|
|
nsIFrame *resultFrame = nsnull;//this will be passed the handle event when we
|
|
|
|
//can tell who to pass it to
|
|
|
|
nsIFrame *mainframe = this;
|
2001-10-25 05:08:40 +04:00
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
2000-05-11 12:41:35 +04:00
|
|
|
if (!shell)
|
|
|
|
return NS_OK;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCOMPtr<nsIFocusTracker> tracker( do_QueryInterface(shell, &result) );
|
1999-09-02 01:40:16 +04:00
|
|
|
|
2001-10-25 05:08:40 +04:00
|
|
|
nsCOMPtr<nsILineIterator> it( do_QueryInterface(mainframe, &result) );
|
1999-09-02 01:40:16 +04:00
|
|
|
nsIView* parentWithView;
|
|
|
|
nsPoint origin;
|
2000-09-15 11:02:05 +04:00
|
|
|
nsPeekOffsetStruct pos;
|
1999-09-02 01:40:16 +04:00
|
|
|
|
2000-09-15 11:02:05 +04:00
|
|
|
while(NS_OK == result)
|
1999-09-02 01:40:16 +04:00
|
|
|
{ //we are starting aloop to allow us to "drill down to the one we want"
|
1999-11-24 09:03:41 +03:00
|
|
|
mainframe->GetOffsetFromView(aPresContext, origin, &parentWithView);
|
1999-09-02 01:40:16 +04:00
|
|
|
|
|
|
|
if (NS_FAILED(result))
|
|
|
|
return NS_OK;//do not handle
|
2001-05-11 12:04:29 +04:00
|
|
|
PRInt32 closestLine;
|
|
|
|
|
|
|
|
if (NS_FAILED(result = GetClosestLine(it,origin,aEvent->point,closestLine)))
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
1999-09-02 01:40:16 +04:00
|
|
|
//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 05:15:26 +04:00
|
|
|
pos.mTracker = tracker;
|
|
|
|
pos.mDirection = eDirNext;
|
|
|
|
pos.mDesiredX = aEvent->point.x;
|
2002-04-16 06:42:09 +04:00
|
|
|
pos.mScrollViewStop = PR_FALSE;
|
1999-11-24 09:03:41 +03:00
|
|
|
result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
|
1999-10-26 08:44:41 +04:00
|
|
|
&pos,
|
1999-09-02 01:40:16 +04:00
|
|
|
mainframe,
|
|
|
|
closestLine-1,
|
1999-10-13 05:15:26 +04:00
|
|
|
0
|
1999-09-02 01:40:16 +04:00
|
|
|
);
|
1999-10-13 05:15:26 +04:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(result) && pos.mResultFrame){
|
2000-09-15 11:02:05 +04:00
|
|
|
if (result == NS_OK)
|
2001-10-25 05:08:40 +04:00
|
|
|
it = do_QueryInterface(pos.mResultFrame, &result);//if this fails thats ok
|
1999-10-15 03:52:42 +04:00
|
|
|
resultFrame = pos.mResultFrame;
|
1999-09-02 01:40:16 +04:00
|
|
|
mainframe = resultFrame;
|
|
|
|
}
|
1999-10-15 03:52:42 +04:00
|
|
|
else
|
1999-09-02 04:04:56 +04:00
|
|
|
break;//time to go nothing was found
|
1999-08-25 01:51:47 +04:00
|
|
|
}
|
1999-09-02 01:40:16 +04: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-25 01:51:47 +04:00
|
|
|
if (resultFrame)
|
2000-05-14 07:41:25 +04:00
|
|
|
{
|
2000-09-15 11:02:05 +04: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));
|
2001-07-20 03:32:07 +04:00
|
|
|
PRBool mouseDown = aEvent->message == NS_MOUSE_MOVE;
|
2000-09-15 11:02:05 +04:00
|
|
|
if (frameselection)
|
2001-07-20 03:32:07 +04:00
|
|
|
{
|
2000-09-15 11:02:05 +04:00
|
|
|
result = frameselection->HandleClick(pos.mResultContent, pos.mContentOffset,
|
2001-07-20 03:32:07 +04:00
|
|
|
pos.mContentOffsetEnd, mouseDown || me->isShift, PR_FALSE, pos.mPreferLeft);
|
|
|
|
}
|
2000-09-15 11:02:05 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
result = resultFrame->HandleEvent(aPresContext, aEvent, aEventStatus);//else let the frame/container do what it needs
|
2000-05-14 07:41:25 +04:00
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN && !IsMouseCaptured(aPresContext))
|
|
|
|
CaptureMouse(aPresContext, PR_TRUE);
|
|
|
|
return result;
|
|
|
|
}
|
1999-08-25 01:51:47 +04:00
|
|
|
else
|
2000-05-14 07:41:25 +04: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-25 01:51:47 +04:00
|
|
|
return NS_OK; //just stop it
|
2000-05-14 07:41:25 +04:00
|
|
|
}
|
1999-08-25 01:51:47 +04:00
|
|
|
}
|
2000-04-12 07:04:11 +04:00
|
|
|
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
1999-04-14 01:29:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-10-26 08:44:41 +04:00
|
|
|
nsBlockFrame::GetFrameForPoint(nsIPresContext* aPresContext,
|
|
|
|
const nsPoint& aPoint,
|
2000-03-22 05:43:08 +03:00
|
|
|
nsFramePaintLayer aWhichLayer,
|
1999-10-26 08:44:41 +04:00
|
|
|
nsIFrame** aFrame)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2000-01-18 18:17:31 +03:00
|
|
|
nsresult rv;
|
|
|
|
|
2000-03-22 05:43:08 +03: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()) {
|
|
|
|
|
2001-11-15 10:30:09 +03:00
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint,
|
|
|
|
nsLayoutAtoms::floaterList,
|
|
|
|
NS_FRAME_PAINT_LAYER_FOREGROUND,
|
|
|
|
PR_FALSE, aFrame);
|
2000-03-22 05:43:08 +03:00
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-11-15 10:30:09 +03:00
|
|
|
rv = GetFrameForPointUsing(aPresContext, aPoint,
|
|
|
|
nsLayoutAtoms::floaterList,
|
|
|
|
NS_FRAME_PAINT_LAYER_FLOATERS,
|
|
|
|
PR_FALSE, aFrame);
|
2000-03-22 05:43:08 +03:00
|
|
|
if (NS_OK == rv) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-11-15 10:30:09 +03:00
|
|
|
return GetFrameForPointUsing(aPresContext, aPoint,
|
|
|
|
nsLayoutAtoms::floaterList,
|
|
|
|
NS_FRAME_PAINT_LAYER_BACKGROUND,
|
|
|
|
PR_FALSE, aFrame);
|
2000-03-22 05:43:08 +03:00
|
|
|
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_FRAME_PAINT_LAYER_BACKGROUND:
|
|
|
|
// we're a block, so PR_TRUE for consider self
|
2001-11-15 10:30:09 +03:00
|
|
|
return GetFrameForPointUsing(aPresContext, aPoint, nsnull,
|
|
|
|
NS_FRAME_PAINT_LAYER_BACKGROUND,
|
|
|
|
PR_TRUE, aFrame);
|
2000-03-22 05:43:08 +03:00
|
|
|
break;
|
1999-02-09 20:31:33 +03:00
|
|
|
}
|
2000-03-22 05:43:08 +03:00
|
|
|
// we shouldn't get here
|
|
|
|
NS_ASSERTION(PR_FALSE, "aWhichLayer was not understood");
|
|
|
|
return NS_ERROR_FAILURE;
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2000-01-12 11:28:24 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::ReflowDirtyChild(nsIPresShell* aPresShell, nsIFrame* aChild)
|
2001-09-06 00:27:19 +04:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
ListTag(stdout);
|
|
|
|
printf(": ReflowDirtyChild (");
|
|
|
|
if (aChild)
|
|
|
|
nsFrame::ListTag(stdout, aChild);
|
|
|
|
else
|
|
|
|
printf("null");
|
|
|
|
printf(")\n");
|
|
|
|
|
|
|
|
gNoiseIndent++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-05-09 09:06:16 +04:00
|
|
|
if (aChild) {
|
|
|
|
// See if the child is absolutely positioned
|
|
|
|
nsFrameState childState;
|
|
|
|
aChild->GetFrameState(&childState);
|
|
|
|
if (childState & NS_FRAME_OUT_OF_FLOW) {
|
2001-06-01 02:19:43 +04:00
|
|
|
const nsStyleDisplay* disp;
|
|
|
|
aChild->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&)disp);
|
2000-05-09 09:06:16 +04:00
|
|
|
|
2001-06-01 02:19:43 +04:00
|
|
|
if (disp->IsAbsolutelyPositioned()) {
|
2000-05-09 09:06:16 +04:00
|
|
|
// 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...
|
2001-12-18 01:39:59 +03:00
|
|
|
nsHTMLReflowCommand* reflowCmd;
|
2000-05-09 09:06:16 +04:00
|
|
|
nsresult rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
|
2001-12-18 01:39:59 +03:00
|
|
|
eReflowType_ReflowDirty);
|
2000-05-09 09:06:16 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
reflowCmd->SetChildListName(nsLayoutAtoms::absoluteList);
|
|
|
|
aPresShell->AppendReflowCommand(reflowCmd);
|
|
|
|
}
|
2001-09-06 00:27:19 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf("scheduled reflow command for absolutely positioned frame\n");
|
|
|
|
--gNoiseIndent;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-05-09 09:06:16 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
2001-04-30 01:58:50 +04:00
|
|
|
|
|
|
|
// Mark the line containing the child frame dirty.
|
2002-04-26 23:19:39 +04:00
|
|
|
line_iterator fline = FindLineFor(aChild);
|
|
|
|
if (fline != end_lines())
|
|
|
|
MarkLineDirty(fline);
|
2000-01-12 11:28:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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,
|
2001-12-18 01:39:59 +03:00
|
|
|
eReflowType_ReflowDirty, nsnull, nsnull, nsnull);
|
2001-09-06 00:27:19 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
IndentBy(stdout, gNoiseIndent);
|
|
|
|
printf("scheduled reflow command targeted at self\n");
|
|
|
|
}
|
|
|
|
#endif
|
2000-01-12 11:28:24 +03:00
|
|
|
}
|
2001-09-06 00:27:19 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (gNoisyReflow) {
|
|
|
|
--gNoiseIndent;
|
|
|
|
}
|
|
|
|
#endif
|
2000-01-12 11:28:24 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Debugging
|
|
|
|
|
|
|
|
#ifdef NS_DEBUG
|
|
|
|
static PRBool
|
2001-10-25 05:08:40 +04:00
|
|
|
InLineList(nsLineList& aLines, nsIFrame* aFrame)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
for (nsLineList::iterator line = aLines.begin(), line_end = aLines.end();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
|
|
|
nsIFrame* frame = line->mFirstChild;
|
|
|
|
PRInt32 n = line->GetChildCount();
|
1998-12-05 19:02:08 +03:00
|
|
|
while (--n >= 0) {
|
|
|
|
if (frame == aFrame) {
|
|
|
|
return PR_TRUE;
|
1998-11-05 22:33:01 +03:00
|
|
|
}
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-07-17 03:30:49 +04:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
return PR_FALSE;
|
1998-06-18 20:25:41 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
static PRBool
|
2001-10-25 05:08:40 +04:00
|
|
|
InSiblingList(nsLineList& aLines, nsIFrame* aFrame)
|
1998-11-12 21:19:22 +03:00
|
|
|
{
|
2001-10-25 05:08:40 +04:00
|
|
|
if (! aLines.empty()) {
|
|
|
|
nsIFrame* frame = aLines.front()->mFirstChild;
|
1998-12-05 19:02:08 +03:00
|
|
|
while (nsnull != frame) {
|
|
|
|
if (frame == aFrame) {
|
|
|
|
return PR_TRUE;
|
1998-11-12 21:19:22 +03:00
|
|
|
}
|
1999-02-10 09:13:38 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
1998-11-12 21:19:22 +03:00
|
|
|
}
|
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
return PR_FALSE;
|
1998-11-12 21:19:22 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
PRBool
|
1999-11-03 02:42:52 +03:00
|
|
|
nsBlockFrame::IsChild(nsIPresContext* aPresContext, nsIFrame* aFrame)
|
1998-11-12 21:19:22 +03:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
nsIFrame* parent;
|
1999-02-10 04:36:30 +03:00
|
|
|
aFrame->GetParent(&parent);
|
1998-12-05 19:02:08 +03:00
|
|
|
if (parent != (nsIFrame*)this) {
|
|
|
|
return PR_FALSE;
|
1998-11-12 21:19:22 +03:00
|
|
|
}
|
1998-12-05 19:02:08 +03:00
|
|
|
if (InLineList(mLines, aFrame) && InSiblingList(mLines, aFrame)) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
2002-05-29 02:50:43 +04:00
|
|
|
if (overflowLines && InLineList(*overflowLines, aFrame) && InSiblingList(*overflowLines, aFrame)) {
|
1998-12-05 19:02:08 +03:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
1998-11-12 21:19:22 +03:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-02-09 20:31:33 +03:00
|
|
|
nsBlockFrame::VerifyTree() const
|
1998-07-19 01:45:17 +04:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
// XXX rewrite this
|
1998-07-19 01:45:17 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-31 07:09:40 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsBlockFrame::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const
|
|
|
|
{
|
1999-08-31 08:32:13 +04:00
|
|
|
if (!aHandler || !aResult) {
|
1999-08-31 07:09:40 +04:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 sum = sizeof(*this);
|
|
|
|
|
|
|
|
// Add in size of each line object
|
2001-10-25 05:08:40 +04:00
|
|
|
for (const_line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-10-02 06:51:03 +04:00
|
|
|
PRUint32 lineBoxSize;
|
1999-10-15 03:10:03 +04:00
|
|
|
nsIAtom* atom = line->SizeOf(aHandler, &lineBoxSize);
|
|
|
|
aHandler->AddSize(atom, lineBoxSize);
|
1999-08-31 07:09:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
*aResult = sum;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-09-01 05:02:16 +04:00
|
|
|
#endif
|
1999-08-31 07:09:40 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
//----------------------------------------------------------------------
|
1998-07-19 01:45:17 +04:00
|
|
|
|
1999-02-25 08:31:15 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::Init(nsIPresContext* aPresContext,
|
1999-02-25 08:31:15 +03:00
|
|
|
nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIStyleContext* aContext,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
|
|
|
if (aPrevInFlow) {
|
1999-11-03 03:42:12 +03:00
|
|
|
// Copy over the block/area frame type flags
|
1999-02-25 08:31:15 +03:00
|
|
|
nsBlockFrame* blockFrame = (nsBlockFrame*)aPrevInFlow;
|
|
|
|
|
1999-11-03 03:42:12 +03:00
|
|
|
SetFlags(blockFrame->mState & NS_BLOCK_FLAGS_MASK);
|
1999-02-25 08:31:15 +03:00
|
|
|
}
|
1999-03-20 02:05:56 +03:00
|
|
|
|
1999-03-30 03:44:45 +04:00
|
|
|
nsresult rv = nsBlockFrameSuper::Init(aPresContext, aContent, aParent,
|
|
|
|
aContext, aPrevInFlow);
|
|
|
|
return rv;
|
1999-02-25 08:31:15 +03:00
|
|
|
}
|
|
|
|
|
1999-04-28 02:10:51 +04:00
|
|
|
nsIStyleContext*
|
|
|
|
nsBlockFrame::GetFirstLetterStyle(nsIPresContext* aPresContext)
|
|
|
|
{
|
2001-10-30 09:02:05 +03:00
|
|
|
// This check is here because nsComboboxControlFrame creates
|
|
|
|
// nsBlockFrame objects that have an |mContent| pointing to a text
|
|
|
|
// node. This check ensures we don't try to do selector matching on
|
|
|
|
// that text node.
|
|
|
|
//
|
|
|
|
// XXX This check should go away once we fix nsComboboxControlFrame.
|
|
|
|
//
|
|
|
|
if (!mContent->IsContentOfType(nsIContent::eELEMENT))
|
|
|
|
return nsnull;
|
|
|
|
|
1999-04-28 02:10:51 +04:00
|
|
|
nsIStyleContext* fls;
|
|
|
|
aPresContext->ProbePseudoStyleContextFor(mContent,
|
|
|
|
nsHTMLAtoms::firstLetterPseudo,
|
2002-03-31 20:59:00 +04:00
|
|
|
mStyleContext, &fls);
|
1999-04-28 02:10:51 +04:00
|
|
|
return fls;
|
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
NS_IMETHODIMP
|
1999-11-24 09:03:41 +03:00
|
|
|
nsBlockFrame::SetInitialChildList(nsIPresContext* aPresContext,
|
1999-02-09 20:31:33 +03:00
|
|
|
nsIAtom* aListName,
|
|
|
|
nsIFrame* aChildList)
|
1998-12-05 19:02:08 +03:00
|
|
|
{
|
1999-02-26 20:04:44 +03:00
|
|
|
nsresult rv = NS_OK;
|
1998-06-24 21:52:42 +04:00
|
|
|
|
2000-05-09 09:06:16 +04:00
|
|
|
if (nsLayoutAtoms::absoluteList == aListName) {
|
|
|
|
mAbsoluteContainer.SetInitialChildList(this, aPresContext, aListName, aChildList);
|
|
|
|
}
|
|
|
|
else if (nsLayoutAtoms::floaterList == aListName) {
|
1999-02-26 20:04:44 +03:00
|
|
|
mFloaters.SetFrames(aChildList);
|
|
|
|
}
|
|
|
|
else {
|
1999-04-20 04:27:43 +04:00
|
|
|
|
|
|
|
// Lookup up the two pseudo style contexts
|
|
|
|
if (nsnull == mPrevInFlow) {
|
1999-11-24 09:03:41 +03:00
|
|
|
nsIStyleContext* firstLetterStyle = GetFirstLetterStyle(aPresContext);
|
1999-04-28 02:10:51 +04:00
|
|
|
if (nsnull != firstLetterStyle) {
|
|
|
|
mState |= NS_BLOCK_HAS_FIRST_LETTER_STYLE;
|
|
|
|
#ifdef NOISY_FIRST_LETTER
|
|
|
|
ListTag(stdout);
|
2000-10-29 02:17:53 +04:00
|
|
|
printf(": first-letter style found\n");
|
1999-04-28 02:10:51 +04:00
|
|
|
#endif
|
|
|
|
NS_RELEASE(firstLetterStyle);
|
|
|
|
}
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
|
|
|
|
1999-11-24 09:03:41 +03:00
|
|
|
rv = AddFrames(aPresContext, aChildList, nsnull);
|
1999-02-26 20:04:44 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
1998-06-18 20:25:41 +04:00
|
|
|
|
1999-02-26 20:04:44 +03: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
|
2002-02-21 04:36:16 +03:00
|
|
|
const nsStyleList* styleList;
|
|
|
|
GetStyleData(eStyleStruct_List, (const nsStyleStruct*&) styleList);
|
|
|
|
nsIAtom *pseudoElement;
|
|
|
|
switch (styleList->mListStyleType) {
|
|
|
|
case NS_STYLE_LIST_STYLE_DISC:
|
|
|
|
case NS_STYLE_LIST_STYLE_CIRCLE:
|
|
|
|
case NS_STYLE_LIST_STYLE_SQUARE:
|
|
|
|
pseudoElement = nsHTMLAtoms::mozListBulletPseudo;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pseudoElement = nsHTMLAtoms::mozListNumberPseudo;
|
|
|
|
break;
|
|
|
|
}
|
1999-02-26 20:04:44 +03:00
|
|
|
nsIStyleContext* kidSC;
|
2002-02-21 04:36:16 +03:00
|
|
|
aPresContext->ResolvePseudoStyleContextFor(mContent, pseudoElement,
|
2002-03-31 20:59:00 +04:00
|
|
|
mStyleContext, &kidSC);
|
1999-02-26 20:04:44 +03:00
|
|
|
|
|
|
|
// Create bullet frame
|
1999-12-05 02:49:50 +03:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
aPresContext->GetShell(getter_AddRefs(shell));
|
|
|
|
mBullet = new (shell.get()) nsBulletFrame;
|
|
|
|
|
1999-02-26 20:04:44 +03:00
|
|
|
if (nsnull == mBullet) {
|
|
|
|
NS_RELEASE(kidSC);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
mBullet->Init(aPresContext, mContent, this, kidSC, nsnull);
|
1999-02-09 20:31:33 +03:00
|
|
|
NS_RELEASE(kidSC);
|
1998-07-02 04:04:12 +04:00
|
|
|
|
1999-02-26 20:04:44 +03:00
|
|
|
// If the list bullet frame should be positioned inside then add
|
|
|
|
// it to the flow now.
|
1999-04-20 04:27:43 +04:00
|
|
|
if (NS_STYLE_LIST_STYLE_POSITION_INSIDE ==
|
|
|
|
styleList->mListStylePosition) {
|
1999-11-24 09:03:41 +03:00
|
|
|
AddFrames(aPresContext, mBullet, nsnull);
|
1999-02-26 20:04:44 +03:00
|
|
|
mState &= ~NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mState |= NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET;
|
|
|
|
}
|
1998-07-02 04:04:12 +04:00
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
return NS_OK;
|
1998-06-24 21:52:42 +04:00
|
|
|
}
|
|
|
|
|
1999-07-14 21:26:20 +04: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 04:16:50 +03:00
|
|
|
nsBlockFrame::RenumberLists(nsIPresContext* aPresContext)
|
1999-07-14 21:26:20 +04: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;
|
2002-05-23 04:00:34 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLContent> hc(do_QueryInterface(mContent));
|
|
|
|
|
|
|
|
if (hc) {
|
1999-07-14 21:26:20 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get to first-in-flow
|
1999-09-16 23:56:36 +04:00
|
|
|
nsBlockFrame* block = (nsBlockFrame*) GetFirstInFlow();
|
2000-07-28 13:02:34 +04:00
|
|
|
RenumberListsInBlock(aPresContext, block, &ordinal, 0);
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
|
|
|
|
1999-09-18 03:16:43 +04:00
|
|
|
PRBool
|
2000-01-22 04:16:50 +03:00
|
|
|
nsBlockFrame::RenumberListsInBlock(nsIPresContext* aPresContext,
|
|
|
|
nsBlockFrame* aBlockFrame,
|
2000-07-28 13:02:34 +04:00
|
|
|
PRInt32* aOrdinal,
|
|
|
|
PRInt32 aDepth)
|
1999-09-18 03:16:43 +04:00
|
|
|
{
|
|
|
|
PRBool renumberedABullet = PR_FALSE;
|
|
|
|
|
|
|
|
while (nsnull != aBlockFrame) {
|
|
|
|
// Examine each line in the block
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = aBlockFrame->begin_lines(),
|
|
|
|
line_end = aBlockFrame->end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-09-18 03:16:43 +04:00
|
|
|
nsIFrame* kid = line->mFirstChild;
|
1999-10-15 03:10:03 +04:00
|
|
|
PRInt32 n = line->GetChildCount();
|
1999-09-18 03:16:43 +04:00
|
|
|
while (--n >= 0) {
|
2000-07-28 13:02:34 +04:00
|
|
|
PRBool kidRenumberedABullet = RenumberListsFor(aPresContext, kid, aOrdinal, aDepth);
|
1999-09-18 03:16:43 +04:00
|
|
|
if (kidRenumberedABullet) {
|
|
|
|
line->MarkDirty();
|
|
|
|
renumberedABullet = PR_TRUE;
|
|
|
|
}
|
|
|
|
kid->GetNextSibling(&kid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance to the next continuation
|
|
|
|
aBlockFrame->GetNextInFlow((nsIFrame**) &aBlockFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
return renumberedABullet;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2000-01-22 04:16:50 +03:00
|
|
|
nsBlockFrame::RenumberListsFor(nsIPresContext* aPresContext,
|
|
|
|
nsIFrame* aKid,
|
2000-07-28 13:02:34 +04:00
|
|
|
PRInt32* aOrdinal,
|
|
|
|
PRInt32 aDepth)
|
1999-09-18 03:16:43 +04:00
|
|
|
{
|
2001-07-04 06:00:05 +04:00
|
|
|
NS_PRECONDITION(aPresContext && aKid && aOrdinal, "null params are immoral!");
|
2001-02-03 00:17:01 +03:00
|
|
|
|
2000-06-15 03:15:59 +04:00
|
|
|
// add in a sanity check for absurdly deep frame trees. See bug 42138
|
2000-07-28 13:02:34 +04:00
|
|
|
if (MAX_DEPTH_FOR_LIST_RENUMBERING < aDepth)
|
2000-06-15 03:15:59 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
|
1999-09-18 03:16:43 +04:00
|
|
|
PRBool kidRenumberedABullet = PR_FALSE;
|
2001-02-03 00:17:01 +03: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 21:26:20 +04:00
|
|
|
|
1999-09-18 03:16:43 +04:00
|
|
|
// If the frame is a list-item and the frame implements our
|
2001-06-07 06:09:38 +04:00
|
|
|
// block frame API then get its bullet and set the list item
|
1999-09-18 03:16:43 +04:00
|
|
|
// ordinal.
|
|
|
|
const nsStyleDisplay* display;
|
2001-02-03 00:17:01 +03:00
|
|
|
kid->GetStyleData(eStyleStruct_Display,
|
1999-09-18 03:16:43 +04:00
|
|
|
(const nsStyleStruct*&) display);
|
|
|
|
if (NS_STYLE_DISPLAY_LIST_ITEM == display->mDisplay) {
|
2001-06-07 06:09:38 +04:00
|
|
|
// Make certain that the frame is a block frame in case
|
1999-09-18 03:16:43 +04:00
|
|
|
// something foreign has crept in.
|
|
|
|
nsBlockFrame* listItem;
|
2001-02-03 00:17:01 +03:00
|
|
|
nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**)&listItem);
|
1999-09-18 03:16:43 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (nsnull != listItem->mBullet) {
|
|
|
|
PRBool changed;
|
|
|
|
*aOrdinal = listItem->mBullet->SetListItemOrdinal(*aOrdinal,
|
|
|
|
&changed);
|
|
|
|
if (changed) {
|
|
|
|
kidRenumberedABullet = PR_TRUE;
|
2002-04-11 18:01:11 +04:00
|
|
|
|
|
|
|
nsRect damageRect;
|
|
|
|
listItem->mBullet->GetRect(damageRect);
|
|
|
|
damageRect.x = damageRect.y = 0;
|
|
|
|
if (damageRect.width > 0 || damageRect.height > 0)
|
|
|
|
listItem->mBullet->Invalidate(aPresContext, damageRect);
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
|
|
|
}
|
1999-09-18 03:16:43 +04:00
|
|
|
|
|
|
|
// XXX temporary? if the list-item has child list-items they
|
|
|
|
// should be numbered too; especially since the list-item is
|
2001-06-07 06:09:38 +04:00
|
|
|
// itself (ASSUMED!) not to be a counter-resetter.
|
2000-07-28 13:02:34 +04:00
|
|
|
PRBool meToo = RenumberListsInBlock(aPresContext, listItem, aOrdinal, aDepth + 1);
|
1999-09-18 03:16:43 +04:00
|
|
|
if (meToo) {
|
|
|
|
kidRenumberedABullet = PR_TRUE;
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-18 03:16:43 +04:00
|
|
|
else if (NS_STYLE_DISPLAY_BLOCK == display->mDisplay) {
|
2001-02-03 00:17:01 +03:00
|
|
|
if (FrameStartsCounterScope(kid)) {
|
1999-09-18 03:16:43 +04: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 {
|
2001-06-07 06:09:38 +04:00
|
|
|
// If the display=block element is a block frame then go ahead
|
|
|
|
// and recurse into it, as it might have child list-items.
|
1999-09-18 03:16:43 +04:00
|
|
|
nsBlockFrame* kidBlock;
|
2001-02-03 00:17:01 +03:00
|
|
|
nsresult rv = kid->QueryInterface(kBlockFrameCID, (void**) &kidBlock);
|
1999-09-18 03:16:43 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2000-07-28 13:02:34 +04:00
|
|
|
kidRenumberedABullet = RenumberListsInBlock(aPresContext, kidBlock, aOrdinal, aDepth + 1);
|
1999-09-18 03:16:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return kidRenumberedABullet;
|
1999-07-14 21:26:20 +04:00
|
|
|
}
|
1998-10-17 00:22:39 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
1999-02-19 01:22:55 +03:00
|
|
|
nsBlockFrame::ReflowBullet(nsBlockReflowState& aState,
|
|
|
|
nsHTMLReflowMetrics& aMetrics)
|
1998-06-18 20:25:41 +04:00
|
|
|
{
|
1998-12-05 19:02:08 +03:00
|
|
|
// Reflow the bullet now
|
|
|
|
nsSize availSize;
|
|
|
|
availSize.width = NS_UNCONSTRAINEDSIZE;
|
|
|
|
availSize.height = NS_UNCONSTRAINEDSIZE;
|
2002-05-10 22:22:41 +04:00
|
|
|
|
|
|
|
// Get the reason right.
|
|
|
|
// XXXwaterson Should this look just like the logic in
|
|
|
|
// nsBlockReflowContext::ReflowBlock and nsLineLayout::ReflowFrame?
|
|
|
|
const nsHTMLReflowState &rs = aState.mReflowState;
|
|
|
|
nsReflowReason reason = rs.reason;
|
|
|
|
if (reason == eReflowReason_Incremental) {
|
|
|
|
if (! rs.path->HasChild(mBullet)) {
|
|
|
|
// An incremental reflow not explicitly destined to (or through)
|
|
|
|
// the child should be treated as a resize...
|
|
|
|
reason = eReflowReason_Resize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ...unless its an incremental `style changed' reflow targeted at
|
|
|
|
// the block, in which case, we propagate that to its children.
|
|
|
|
nsHTMLReflowCommand *command = rs.path->mReflowCommand;
|
|
|
|
if (command) {
|
|
|
|
nsReflowType type;
|
|
|
|
command->GetType(type);
|
|
|
|
if (type == eReflowType_StyleChanged)
|
|
|
|
reason = eReflowReason_StyleChange;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLReflowState reflowState(aState.mPresContext, rs,
|
|
|
|
mBullet, availSize, reason);
|
1999-10-30 06:52:11 +04:00
|
|
|
nsReflowStatus status;
|
1999-11-24 09:03:41 +03:00
|
|
|
mBullet->WillReflow(aState.mPresContext);
|
|
|
|
mBullet->Reflow(aState.mPresContext, aMetrics, reflowState, status);
|
1998-11-19 06:52:29 +03:00
|
|
|
|
2001-03-09 06:29:00 +03:00
|
|
|
#ifdef IBMBIDI
|
2001-06-01 02:19:43 +04:00
|
|
|
const nsStyleVisibility* vis;
|
|
|
|
GetStyleData(eStyleStruct_Visibility, (const nsStyleStruct*&)vis);
|
2001-03-09 06:29:00 +03:00
|
|
|
#endif // IBMBIDI
|
1998-12-05 19:02:08 +03:00
|
|
|
// Place the bullet now; use its right margin to distance it
|
|
|
|
// from the rest of the frames in the line
|
2001-03-09 06:29:00 +03:00
|
|
|
nscoord x =
|
|
|
|
#ifdef IBMBIDI
|
|
|
|
// For direction RTL: set x to the right margin for now.
|
|
|
|
// This value will be used to indent the bullet from the right most
|
|
|
|
// egde of the previous frame in nsLineLayout::HorizontalAlignFrames.
|
2001-06-01 02:19:43 +04:00
|
|
|
(NS_STYLE_DIRECTION_RTL == vis->mDirection)
|
2001-03-09 06:29:00 +03:00
|
|
|
? reflowState.mComputedMargin.right :
|
|
|
|
#endif // IBMBIDI
|
|
|
|
- reflowState.mComputedMargin.right - aMetrics.width;
|
1999-02-19 01:22:55 +03:00
|
|
|
|
|
|
|
// Approximate the bullets position; vertical alignment will provide
|
|
|
|
// the final vertical location.
|
1999-07-14 21:26:20 +04:00
|
|
|
const nsMargin& bp = aState.BorderPadding();
|
1999-03-05 07:21:32 +03:00
|
|
|
nscoord y = bp.top;
|
1999-10-26 08:44:41 +04:00
|
|
|
mBullet->SetRect(aState.mPresContext, nsRect(x, y, aMetrics.width, aMetrics.height));
|
2001-12-07 17:51:12 +03:00
|
|
|
mBullet->DidReflow(aState.mPresContext, &aState.mReflowState, NS_FRAME_REFLOW_FINISHED);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-07-22 09:02:07 +04:00
|
|
|
|
1999-02-26 20:04:44 +03:00
|
|
|
//XXX get rid of this -- its slow
|
1998-12-05 19:02:08 +03:00
|
|
|
void
|
|
|
|
nsBlockFrame::BuildFloaterList()
|
|
|
|
{
|
|
|
|
nsIFrame* head = nsnull;
|
|
|
|
nsIFrame* current = nsnull;
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line_iterator line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-10-15 03:10:03 +04:00
|
|
|
if (line->HasFloaters()) {
|
|
|
|
nsFloaterCache* fc = line->GetFirstFloater();
|
1999-09-15 04:28:10 +04:00
|
|
|
while (fc) {
|
|
|
|
nsIFrame* floater = fc->mPlaceholder->GetOutOfFlowFrame();
|
1998-12-05 19:02:08 +03:00
|
|
|
if (nsnull == head) {
|
|
|
|
current = head = floater;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
current->SetNextSibling(floater);
|
|
|
|
current = floater;
|
|
|
|
}
|
1999-09-15 04:28:10 +04:00
|
|
|
fc = fc->Next();
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
1998-11-19 06:52:29 +03:00
|
|
|
}
|
1998-06-24 21:52:42 +04:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// Terminate end of floater list just in case a floater was removed
|
|
|
|
if (nsnull != current) {
|
|
|
|
current->SetNextSibling(nsnull);
|
1998-11-19 06:52:29 +03:00
|
|
|
}
|
1999-01-16 01:53:39 +03:00
|
|
|
mFloaters.SetFrames(head);
|
1998-12-05 19:02:08 +03:00
|
|
|
}
|
1998-10-31 01:10:10 +03:00
|
|
|
|
1998-12-05 19:02:08 +03:00
|
|
|
// XXX keep the text-run data in the first-in-flow of the block
|
1999-02-26 20:04:44 +03:00
|
|
|
|
1999-03-16 22:36:00 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
1999-04-20 04:27:43 +04:00
|
|
|
nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
|
1999-03-16 22:36:00 +03:00
|
|
|
{
|
1999-10-20 03:04:19 +04:00
|
|
|
if (!gVerifyLines) {
|
|
|
|
return;
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
if (mLines.empty()) {
|
1999-04-20 04:27:43 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add up the counts on each line. Also validate that IsFirstLine is
|
|
|
|
// set properly.
|
|
|
|
PRInt32 count = 0;
|
|
|
|
PRBool seenBlock = PR_FALSE;
|
2001-10-25 05:08:40 +04:00
|
|
|
line_iterator line, line_end;
|
|
|
|
for (line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
++line) {
|
1999-04-20 04:27:43 +04:00
|
|
|
if (aFinalCheckOK) {
|
1999-10-15 03:10:03 +04:00
|
|
|
NS_ABORT_IF_FALSE(line->GetChildCount(), "empty line");
|
1999-04-20 04:27:43 +04:00
|
|
|
if (line->IsBlock()) {
|
|
|
|
seenBlock = PR_TRUE;
|
|
|
|
}
|
1999-08-31 07:09:40 +04:00
|
|
|
if (line->IsBlock()) {
|
1999-10-15 03:10:03 +04:00
|
|
|
NS_ASSERTION(1 == line->GetChildCount(), "bad first line");
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
}
|
1999-10-15 03:10:03 +04:00
|
|
|
count += line->GetChildCount();
|
1999-04-20 04:27:43 +04:00
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
|
1999-04-20 04:27:43 +04:00
|
|
|
// Then count the frames
|
|
|
|
PRInt32 frameCount = 0;
|
2001-10-25 05:08:40 +04:00
|
|
|
nsIFrame* frame = mLines.front()->mFirstChild;
|
1999-04-20 04:27:43 +04:00
|
|
|
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
|
2001-10-25 05:08:40 +04:00
|
|
|
for (line = begin_lines(), line_end = end_lines();
|
|
|
|
line != line_end;
|
|
|
|
) {
|
1999-10-15 03:10:03 +04:00
|
|
|
count = line->GetChildCount();
|
1999-04-20 04:27:43 +04:00
|
|
|
frame = line->mFirstChild;
|
|
|
|
while (--count >= 0) {
|
1999-03-16 22:36:00 +03:00
|
|
|
frame->GetNextSibling(&frame);
|
|
|
|
}
|
2001-10-25 05:08:40 +04:00
|
|
|
++line;
|
|
|
|
if ((line != line_end) && (0 != line->GetChildCount())) {
|
1999-04-20 04:27:43 +04:00
|
|
|
NS_ASSERTION(frame == line->mFirstChild, "bad line list");
|
1999-03-16 22:36:00 +03: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-03 02:42:52 +03:00
|
|
|
nsBlockFrame::VerifyOverflowSituation(nsIPresContext* aPresContext)
|
1999-03-16 22:36:00 +03:00
|
|
|
{
|
|
|
|
nsBlockFrame* flow = (nsBlockFrame*) GetFirstInFlow();
|
|
|
|
while (nsnull != flow) {
|
2001-10-25 05:08:40 +04:00
|
|
|
nsLineList* overflowLines = GetOverflowLines(aPresContext, PR_FALSE);
|
1999-11-03 02:42:52 +03:00
|
|
|
if (nsnull != overflowLines) {
|
2001-10-25 05:08:40 +04:00
|
|
|
NS_ASSERTION(! overflowLines->empty(), "should not be empty if present");
|
|
|
|
NS_ASSERTION(overflowLines->front()->mFirstChild, "bad overflow list");
|
1999-03-16 22:36:00 +03:00
|
|
|
}
|
|
|
|
flow = (nsBlockFrame*) flow->mNextInFlow;
|
|
|
|
}
|
|
|
|
}
|
1999-03-23 01:42:30 +03:00
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsBlockFrame::GetDepth() const
|
|
|
|
{
|
|
|
|
PRInt32 depth = 0;
|
|
|
|
nsIFrame* parent = mParent;
|
|
|
|
while (nsnull != parent) {
|
|
|
|
parent->GetParent(&parent);
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
return depth;
|
|
|
|
}
|
1999-03-16 22:36:00 +03:00
|
|
|
#endif
|