2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
// vim:cindent:ts=2:et:sw=2:
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla 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/MPL/
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Steve Clark <buster@netscape.com>
|
|
|
|
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
|
|
|
* L. David Baron <dbaron@dbaron.org>
|
|
|
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of 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 MPL, 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 MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
/* state used in reflow of block frames */
|
|
|
|
|
|
|
|
#include "nsBlockReflowContext.h"
|
|
|
|
#include "nsBlockReflowState.h"
|
|
|
|
#include "nsBlockFrame.h"
|
|
|
|
#include "nsLineLayout.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsFrameManager.h"
|
2010-08-05 21:59:19 -07:00
|
|
|
#include "mozilla/AutoRestore.h"
|
2010-12-19 17:37:43 -08:00
|
|
|
#include "FrameLayerBuilder.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
|
2011-06-21 08:37:47 -07:00
|
|
|
#include "mozilla/Util.h" // for DebugOnly
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#include "nsBlockDebugFlags.h"
|
|
|
|
#endif
|
|
|
|
|
2010-08-05 21:59:19 -07:00
|
|
|
using namespace mozilla;
|
2012-01-24 17:21:29 -08:00
|
|
|
using namespace mozilla::layout;
|
2010-08-05 21:59:19 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
nsBlockFrame* aFrame,
|
|
|
|
const nsHTMLReflowMetrics& aMetrics,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aTopMarginRoot,
|
|
|
|
bool aBottomMarginRoot,
|
|
|
|
bool aBlockNeedsFloatManager)
|
2007-03-22 10:30:00 -07:00
|
|
|
: mBlock(aFrame),
|
|
|
|
mPresContext(aPresContext),
|
|
|
|
mReflowState(aReflowState),
|
2010-08-05 21:59:20 -07:00
|
|
|
mPushedFloats(nsnull),
|
2009-09-13 17:26:01 -07:00
|
|
|
mOverflowTracker(nsnull),
|
2007-03-22 10:30:00 -07:00
|
|
|
mPrevBottomMargin(),
|
|
|
|
mLineNumber(0),
|
|
|
|
mFlags(0),
|
2008-02-18 23:36:50 -08:00
|
|
|
mFloatBreakType(NS_STYLE_CLEAR_NONE)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nsnull);
|
2007-07-25 21:03:29 -07:00
|
|
|
SetFlag(BRS_ISOVERFLOWCONTAINER,
|
2007-10-01 22:57:45 -07:00
|
|
|
IS_TRUE_OVERFLOW_CONTAINER(aFrame));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
const nsMargin& borderPadding = BorderPadding();
|
|
|
|
|
|
|
|
if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_ISTOPMARGINROOT, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
if (aBottomMarginRoot || 0 != aReflowState.mComputedBorderPadding.bottom) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_ISBOTTOMMARGINROOT, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_APPLYTOPMARGIN, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-01-04 16:39:54 -08:00
|
|
|
if (aBlockNeedsFloatManager) {
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_FLOAT_MGR, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager = aReflowState.mFloatManager;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-01-04 16:39:54 -08:00
|
|
|
NS_ASSERTION(mFloatManager,
|
|
|
|
"FloatManager should be set in nsBlockReflowState" );
|
|
|
|
if (mFloatManager) {
|
2010-08-11 12:32:53 -07:00
|
|
|
// Save the coordinate system origin for later.
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY);
|
2009-04-08 13:52:36 -07:00
|
|
|
mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mReflowStatus = NS_FRAME_COMPLETE;
|
|
|
|
|
|
|
|
mPresContext = aPresContext;
|
2007-07-08 00:08:04 -07:00
|
|
|
mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-10-28 20:22:28 -07:00
|
|
|
NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedWidth(),
|
|
|
|
"have unconstrained width; this should only result from "
|
|
|
|
"very large sizes, not attempts at intrinsic width "
|
|
|
|
"calculation");
|
2007-03-22 10:30:00 -07:00
|
|
|
mContentArea.width = aReflowState.ComputedWidth();
|
|
|
|
|
|
|
|
// Compute content area height. Unlike the width, if we have a
|
|
|
|
// specified style height we ignore it since extra content is
|
|
|
|
// managed by the "overflow" property. When we don't have a
|
|
|
|
// specified style height then we may end up limiting our height if
|
|
|
|
// the availableHeight is constrained (this situation occurs when we
|
|
|
|
// are paginated).
|
|
|
|
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
|
|
|
// We are in a paginated situation. The bottom edge is just inside
|
|
|
|
// the bottom border and padding. The content area height doesn't
|
|
|
|
// include either border or padding edge.
|
|
|
|
mBottomEdge = aReflowState.availableHeight - borderPadding.bottom;
|
2009-09-16 08:01:36 -07:00
|
|
|
mContentArea.height = NS_MAX(0, mBottomEdge - borderPadding.top);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// When we are not in a paginated situation then we always use
|
|
|
|
// an constrained height.
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_UNCONSTRAINEDHEIGHT, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
|
|
|
}
|
2010-08-11 12:32:53 -07:00
|
|
|
mContentArea.x = borderPadding.left;
|
|
|
|
mY = mContentArea.y = borderPadding.top;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
mPrevChild = nsnull;
|
|
|
|
mCurrentLine = aFrame->end_lines();
|
|
|
|
|
2009-05-18 15:13:12 -07:00
|
|
|
mMinLineHeight = aReflowState.CalcLineHeight();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-04-14 18:05:17 -07:00
|
|
|
void
|
|
|
|
nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
|
2009-04-08 13:52:37 -07:00
|
|
|
const nsRect& aFloatAvailableSpace,
|
2008-04-14 18:05:17 -07:00
|
|
|
nscoord& aLeftResult,
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
nscoord& aRightResult)
|
2008-04-14 18:05:17 -07:00
|
|
|
{
|
2009-01-04 16:39:54 -08:00
|
|
|
// The frame is clueless about the float manager and therefore we
|
2008-04-14 18:05:17 -07:00
|
|
|
// only give it free space. An example is a table frame - the
|
|
|
|
// tables do not flow around floats.
|
|
|
|
// However, we can let its margins intersect floats.
|
2010-08-11 12:32:53 -07:00
|
|
|
NS_ASSERTION(aFloatAvailableSpace.x >= mContentArea.x, "bad avail space rect x");
|
2009-04-08 13:52:37 -07:00
|
|
|
NS_ASSERTION(aFloatAvailableSpace.width == 0 ||
|
2010-08-11 12:32:53 -07:00
|
|
|
aFloatAvailableSpace.XMost() <= mContentArea.XMost(),
|
2008-04-14 18:05:17 -07:00
|
|
|
"bad avail space rect width");
|
|
|
|
|
|
|
|
nscoord leftOffset, rightOffset;
|
2009-04-08 13:52:37 -07:00
|
|
|
if (aFloatAvailableSpace.width == mContentArea.width) {
|
2008-04-14 18:05:17 -07:00
|
|
|
// We don't need to compute margins when there are no floats around.
|
|
|
|
leftOffset = 0;
|
|
|
|
rightOffset = 0;
|
|
|
|
} else {
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
nsMargin frameMargin;
|
2008-04-14 18:05:17 -07:00
|
|
|
nsCSSOffsetState os(aFrame, mReflowState.rendContext, mContentArea.width);
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
frameMargin = os.mComputedMargin;
|
2008-04-14 18:05:17 -07:00
|
|
|
|
2010-08-11 12:32:53 -07:00
|
|
|
nscoord leftFloatXOffset = aFloatAvailableSpace.x - mContentArea.x;
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
leftOffset = NS_MAX(leftFloatXOffset, frameMargin.left) -
|
|
|
|
frameMargin.left;
|
2009-09-16 08:01:36 -07:00
|
|
|
leftOffset = NS_MAX(leftOffset, 0); // in case of negative margin
|
2009-04-08 13:52:37 -07:00
|
|
|
nscoord rightFloatXOffset =
|
2010-08-11 12:32:53 -07:00
|
|
|
mContentArea.XMost() - aFloatAvailableSpace.XMost();
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
rightOffset = NS_MAX(rightFloatXOffset, frameMargin.right) -
|
|
|
|
frameMargin.right;
|
2009-09-16 08:01:36 -07:00
|
|
|
rightOffset = NS_MAX(rightOffset, 0); // in case of negative margin
|
2008-04-14 18:05:17 -07:00
|
|
|
}
|
|
|
|
aLeftResult = leftOffset;
|
|
|
|
aRightResult = rightOffset;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Compute the amount of available space for reflowing a block frame
|
|
|
|
// at the current Y coordinate. This method assumes that
|
|
|
|
// GetAvailableSpace has already been called.
|
|
|
|
void
|
|
|
|
nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
|
|
|
const nsStyleDisplay* aDisplay,
|
2009-04-08 13:52:37 -07:00
|
|
|
const nsFlowAreaRect& aFloatAvailableSpace,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aBlockAvoidsFloats,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsRect& aResult)
|
|
|
|
{
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
2009-04-08 13:52:37 -07:00
|
|
|
printf("CBAS frame=%p has floats %d\n",
|
|
|
|
aFrame, aFloatAvailableSpace.mHasFloats);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
aResult.y = mY;
|
|
|
|
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
|
|
|
? NS_UNCONSTRAINEDSIZE
|
2010-08-05 21:59:20 -07:00
|
|
|
: mReflowState.availableHeight - mY;
|
2007-12-11 17:21:34 -08:00
|
|
|
// mY might be greater than mBottomEdge if the block's top margin pushes
|
|
|
|
// it off the page/column. Negative available height can confuse other code
|
|
|
|
// and is nonsense in principle.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-01-28 23:40:05 -08:00
|
|
|
// XXX Do we really want this condition to be this restrictive (i.e.,
|
|
|
|
// more restrictive than it used to be)? The |else| here is allowed
|
|
|
|
// by the CSS spec, but only out of desperation given implementations,
|
|
|
|
// and the behavior it leads to is quite undesirable (it can cause
|
|
|
|
// things to become extremely narrow when they'd fit quite well a
|
|
|
|
// little bit lower). Should the else be a quirk or something that
|
|
|
|
// applies to a specific set of frame classes and no new ones?
|
|
|
|
// If we did that, then for those frames where the condition below is
|
|
|
|
// true but nsBlockFrame::BlockCanIntersectFloats is false,
|
|
|
|
// nsBlockFrame::WidthToClearPastFloats would need to use the
|
|
|
|
// shrink-wrap formula, max(MIN_WIDTH, min(avail width, PREF_WIDTH))
|
|
|
|
// rather than just using MIN_WIDTH.
|
2008-05-03 16:33:36 -07:00
|
|
|
NS_ASSERTION(nsBlockFrame::BlockCanIntersectFloats(aFrame) ==
|
|
|
|
!aBlockAvoidsFloats,
|
2008-04-14 18:05:17 -07:00
|
|
|
"unexpected replaced width");
|
2008-05-03 16:33:36 -07:00
|
|
|
if (!aBlockAvoidsFloats) {
|
2009-04-08 13:52:37 -07:00
|
|
|
if (aFloatAvailableSpace.mHasFloats) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Use the float-edge property to determine how the child block
|
|
|
|
// will interact with the float.
|
|
|
|
const nsStyleBorder* borderStyle = aFrame->GetStyleBorder();
|
|
|
|
switch (borderStyle->mFloatEdge) {
|
|
|
|
default:
|
|
|
|
case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floats
|
|
|
|
// The child block will flow around the float. Therefore
|
|
|
|
// give it all of the available space.
|
2010-08-11 12:32:53 -07:00
|
|
|
aResult.x = mContentArea.x;
|
2007-03-22 10:30:00 -07:00
|
|
|
aResult.width = mContentArea.width;
|
|
|
|
break;
|
|
|
|
case NS_STYLE_FLOAT_EDGE_MARGIN:
|
|
|
|
{
|
|
|
|
// The child block's margins should be placed adjacent to,
|
|
|
|
// but not overlap the float.
|
2010-08-11 12:32:53 -07:00
|
|
|
aResult.x = aFloatAvailableSpace.mRect.x;
|
2009-04-08 13:52:37 -07:00
|
|
|
aResult.width = aFloatAvailableSpace.mRect.width;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Since there are no floats present the float-edge property
|
|
|
|
// doesn't matter therefore give the block element all of the
|
|
|
|
// available space since it will flow around the float itself.
|
2010-08-11 12:32:53 -07:00
|
|
|
aResult.x = mContentArea.x;
|
2007-03-22 10:30:00 -07:00
|
|
|
aResult.width = mContentArea.width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2008-04-14 18:05:17 -07:00
|
|
|
nscoord leftOffset, rightOffset;
|
2009-04-08 13:52:37 -07:00
|
|
|
ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace.mRect,
|
Bug 659828 - Part 1: Apply table margins to the outer table frame instead of the inner table frame (also fixes bug 87277); r=dbaron
Outer table frames act as CSS2.1 table wrapper boxes. We used to lay them out
without taking their margins into the account, which meant that their width was
always equal to the available width. This breaks horizontal positioning of
absolutely positioned kids of a table frame.
The main purpose of this patch is to apply the margins of tables to their outer
frame, instead of the inner frame. This means that the inner table frame will
always have a zero margin, which means that a lot of the stuff which used to
rely on the fact that table margins are applied to the inner frame need to
change.
In particular, in order to get the computed margins of a table, we used to query
the inner table frame, and this patch corrects that. Also, when shrink wrapping
tables, we used to not take the margins of the inner table frame into account,
which is fixed by this patch too. nsBlockReflowState::
ComputeReplacedBlockOffsetsForFloats also needed to be changed to read the
margin values from the outer frame too.
Also, as part of this patch, we start to respect the CSS2.1 margin model for
captions on all sides. This means that in particular, the top/bottom margins on
the top-outside and bottom-outside captions will not be collapsed with the
top/bottom margins of the table, and that the margins of the caption element
contribute to the width and height of the outer table frame. The
427129-table-caption reftest has been modified to match this new behavior.
Another side effect of this bug is fixing bug 87277, and the reftests for that
bug are marked as passing in this patch.
2011-05-31 16:02:56 -07:00
|
|
|
leftOffset, rightOffset);
|
2010-08-11 12:32:53 -07:00
|
|
|
aResult.x = mContentArea.x + leftOffset;
|
2008-04-14 18:05:17 -07:00
|
|
|
aResult.width = mContentArea.width - leftOffset - rightOffset;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef REALLY_NOISY_REFLOW
|
|
|
|
printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-04-08 13:52:37 -07:00
|
|
|
nsFlowAreaRect
|
2009-04-08 13:52:36 -07:00
|
|
|
nsBlockReflowState::GetFloatAvailableSpaceWithState(
|
2010-08-05 21:59:18 -07:00
|
|
|
nscoord aY,
|
2009-04-08 13:52:37 -07:00
|
|
|
nsFloatManager::SavedState *aState) const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Verify that the caller setup the coordinate system properly
|
|
|
|
nscoord wx, wy;
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->GetTranslation(wx, wy);
|
|
|
|
NS_ASSERTION((wx == mFloatManagerX) && (wy == mFloatManagerY),
|
2007-03-22 10:30:00 -07:00
|
|
|
"bad coord system");
|
|
|
|
#endif
|
|
|
|
|
2010-08-05 21:59:20 -07:00
|
|
|
nscoord height = (mContentArea.height == nscoord_MAX)
|
2010-08-11 12:32:53 -07:00
|
|
|
? nscoord_MAX : NS_MAX(mContentArea.YMost() - aY, 0);
|
2009-04-08 13:52:37 -07:00
|
|
|
nsFlowAreaRect result =
|
2010-08-11 12:32:53 -07:00
|
|
|
mFloatManager->GetFlowArea(aY, nsFloatManager::BAND_FROM_POINT,
|
|
|
|
height, mContentArea, aState);
|
2009-02-04 13:24:17 -08:00
|
|
|
// Keep the width >= 0 for compatibility with nsSpaceManager.
|
2009-04-08 13:52:37 -07:00
|
|
|
if (result.mRect.width < 0)
|
|
|
|
result.mRect.width = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
2009-01-04 16:39:54 -08:00
|
|
|
printf("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
|
2009-04-08 13:52:37 -07:00
|
|
|
result.mRect.x, result.mRect.y, result.mRect.width,
|
|
|
|
result.mRect.height, result.mHasFloats);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
2009-04-08 13:52:37 -07:00
|
|
|
return result;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-05-20 04:21:34 -07:00
|
|
|
nsFlowAreaRect
|
|
|
|
nsBlockReflowState::GetFloatAvailableSpaceForHeight(
|
|
|
|
nscoord aY, nscoord aHeight,
|
|
|
|
nsFloatManager::SavedState *aState) const
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Verify that the caller setup the coordinate system properly
|
|
|
|
nscoord wx, wy;
|
|
|
|
mFloatManager->GetTranslation(wx, wy);
|
|
|
|
NS_ASSERTION((wx == mFloatManagerX) && (wy == mFloatManagerY),
|
|
|
|
"bad coord system");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsFlowAreaRect result =
|
2010-08-11 12:32:53 -07:00
|
|
|
mFloatManager->GetFlowArea(aY, nsFloatManager::WIDTH_WITHIN_HEIGHT,
|
|
|
|
aHeight, mContentArea, aState);
|
2009-05-20 04:21:34 -07:00
|
|
|
// Keep the width >= 0 for compatibility with nsSpaceManager.
|
|
|
|
if (result.mRect.width < 0)
|
|
|
|
result.mRect.width = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
printf("GetAvailableSpaceForHeight: space=%d,%d,%d,%d hasfloats=%d\n",
|
|
|
|
result.mRect.x, result.mRect.y, result.mRect.width,
|
|
|
|
result.mRect.height, result.mHasFloats);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/*
|
|
|
|
* Reconstruct the vertical margin before the line |aLine| in order to
|
|
|
|
* do an incremental reflow that begins with |aLine| without reflowing
|
|
|
|
* the line before it. |aLine| may point to the fencepost at the end of
|
|
|
|
* the line list, and it is used this way since we (for now, anyway)
|
|
|
|
* always need to recover margins at the end of a block.
|
|
|
|
*
|
|
|
|
* The reconstruction involves walking backward through the line list to
|
|
|
|
* find any collapsed margins preceding the line that would have been in
|
|
|
|
* the reflow state's |mPrevBottomMargin| when we reflowed that line in
|
|
|
|
* a full reflow (under the rule in CSS2 that all adjacent vertical
|
|
|
|
* margins of blocks collapse).
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsBlockReflowState::ReconstructMarginAbove(nsLineList::iterator aLine)
|
|
|
|
{
|
|
|
|
mPrevBottomMargin.Zero();
|
|
|
|
nsBlockFrame *block = mBlock;
|
|
|
|
|
|
|
|
nsLineList::iterator firstLine = block->begin_lines();
|
|
|
|
for (;;) {
|
|
|
|
--aLine;
|
|
|
|
if (aLine->IsBlock()) {
|
|
|
|
mPrevBottomMargin = aLine->GetCarriedOutBottomMargin();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!aLine->IsEmpty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (aLine == firstLine) {
|
|
|
|
// If the top margin was carried out (and thus already applied),
|
|
|
|
// set it to zero. Either way, we're done.
|
|
|
|
if (!GetFlag(BRS_ISTOPMARGINROOT)) {
|
|
|
|
mPrevBottomMargin.Zero();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-31 11:25:36 -07:00
|
|
|
void
|
2010-08-05 21:59:20 -07:00
|
|
|
nsBlockReflowState::SetupPushedFloatList()
|
2009-08-31 11:25:36 -07:00
|
|
|
{
|
2010-08-05 21:59:20 -07:00
|
|
|
NS_ABORT_IF_FALSE(!GetFlag(BRS_PROPTABLE_FLOATCLIST) == !mPushedFloats,
|
2010-08-05 21:59:19 -07:00
|
|
|
"flag mismatch");
|
2009-08-31 11:25:36 -07:00
|
|
|
if (!GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
|
2010-08-05 21:59:19 -07:00
|
|
|
// If we're being re-Reflow'd without our next-in-flow having been
|
2010-08-05 21:59:20 -07:00
|
|
|
// reflowed, some pushed floats from our previous reflow might
|
|
|
|
// still be on our pushed floats list. However, that's
|
2010-08-05 21:59:19 -07:00
|
|
|
// actually fine, since they'll all end up being stolen and
|
|
|
|
// reordered into the correct order again.
|
2010-08-05 21:59:20 -07:00
|
|
|
// (nsBlockFrame::ReflowDirtyLines ensures that any lines with
|
|
|
|
// pushed floats are reflowed.)
|
2010-08-05 21:59:20 -07:00
|
|
|
mPushedFloats = mBlock->EnsurePushedFloats();
|
2011-10-17 07:59:28 -07:00
|
|
|
SetFlag(BRS_PROPTABLE_FLOATCLIST, true);
|
2009-08-31 11:25:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/**
|
2009-01-04 16:39:54 -08:00
|
|
|
* Restore information about floats into the float manager for an
|
2007-03-22 10:30:00 -07:00
|
|
|
* incremental reflow, and simultaneously push the floats by
|
|
|
|
* |aDeltaY|, which is the amount |aLine| was pushed relative to its
|
|
|
|
* parent. The recovery of state is one of the things that makes
|
|
|
|
* incremental reflow O(N^2) and this state should really be kept
|
|
|
|
* around, attached to the frame tree.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
|
|
|
|
nscoord aDeltaY)
|
|
|
|
{
|
|
|
|
if (aLine->HasFloats()) {
|
|
|
|
// Place the floats into the space-manager again. Also slide
|
|
|
|
// them, just like the regular frames on the line.
|
|
|
|
nsFloatCache* fc = aLine->GetFirstFloat();
|
|
|
|
while (fc) {
|
2009-08-31 11:25:35 -07:00
|
|
|
nsIFrame* floatFrame = fc->mFloat;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aDeltaY != 0) {
|
|
|
|
nsPoint p = floatFrame->GetPosition();
|
|
|
|
floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY));
|
2007-07-01 22:19:57 -07:00
|
|
|
nsContainerFrame::PositionFrameView(floatFrame);
|
|
|
|
nsContainerFrame::PositionChildViews(floatFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
2009-01-04 16:39:54 -08:00
|
|
|
if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nscoord tx, ty;
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->GetTranslation(tx, ty);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
printf("RecoverFloats: txy=%d,%d (%d,%d) ",
|
2009-01-04 16:39:54 -08:00
|
|
|
tx, ty, mFloatManagerX, mFloatManagerY);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFrame::ListTag(stdout, floatFrame);
|
2009-07-14 22:19:31 -07:00
|
|
|
nsRect region = nsFloatManager::GetRegionFor(floatFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
printf(" aDeltaY=%d region={%d,%d,%d,%d}\n",
|
2009-07-14 22:19:31 -07:00
|
|
|
aDeltaY, region.x, region.y, region.width, region.height);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
2009-07-14 22:19:31 -07:00
|
|
|
mFloatManager->AddFloat(floatFrame,
|
|
|
|
nsFloatManager::GetRegionFor(floatFrame));
|
2007-03-22 10:30:00 -07:00
|
|
|
fc = fc->Next();
|
|
|
|
}
|
|
|
|
} else if (aLine->IsBlock()) {
|
2009-08-31 11:25:36 -07:00
|
|
|
nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Everything done in this function is done O(N) times for each pass of
|
|
|
|
* reflow so it is O(N*M) where M is the number of incremental reflow
|
|
|
|
* passes. That's bad. Don't do stuff here.
|
|
|
|
*
|
|
|
|
* When this function is called, |aLine| has just been slid by |aDeltaY|
|
|
|
|
* and the purpose of RecoverStateFrom is to ensure that the
|
|
|
|
* nsBlockReflowState is in the same state that it would have been in
|
|
|
|
* had the line just been reflowed.
|
|
|
|
*
|
|
|
|
* Most of the state recovery that we have to do involves floats.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsBlockReflowState::RecoverStateFrom(nsLineList::iterator aLine,
|
|
|
|
nscoord aDeltaY)
|
|
|
|
{
|
|
|
|
// Make the line being recovered the current line
|
|
|
|
mCurrentLine = aLine;
|
|
|
|
|
2009-01-04 16:39:54 -08:00
|
|
|
// Place floats for this line into the float manager
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aLine->HasFloats() || aLine->IsBlock()) {
|
|
|
|
RecoverFloats(aLine, aDeltaY);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2009-01-04 16:39:54 -08:00
|
|
|
if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
|
|
|
|
mFloatManager->List(stdout);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is called by the line layout's AddFloat method when a
|
|
|
|
// place-holder frame is reflowed in a line. If the float is a
|
|
|
|
// left-most child (it's x coordinate is at the line's left margin)
|
|
|
|
// then the float is place immediately, otherwise the float
|
|
|
|
// placement is deferred until the line has been reflowed.
|
|
|
|
|
|
|
|
// XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
|
|
|
|
// technically we're supposed let the current line flow around the
|
|
|
|
// float as well unless it won't fit next to what we already have.
|
|
|
|
// But nobody else implements it that way...
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2009-08-31 11:25:36 -07:00
|
|
|
nsBlockReflowState::AddFloat(nsLineLayout* aLineLayout,
|
2009-08-31 11:25:35 -07:00
|
|
|
nsIFrame* aFloat,
|
2010-08-05 21:59:20 -07:00
|
|
|
nscoord aAvailableWidth)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-08-05 21:59:19 -07:00
|
|
|
NS_PRECONDITION(aLineLayout, "must have line layout");
|
|
|
|
NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
|
2009-08-31 11:25:35 -07:00
|
|
|
NS_PRECONDITION(aFloat->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
|
|
|
|
"aFloat must be an out-of-flow frame");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-05 21:59:19 -07:00
|
|
|
NS_ABORT_IF_FALSE(aFloat->GetParent(), "float must have parent");
|
|
|
|
NS_ABORT_IF_FALSE(aFloat->GetParent()->IsFrameOfType(nsIFrame::eBlockFrame),
|
|
|
|
"float's parent must be block");
|
|
|
|
NS_ABORT_IF_FALSE(aFloat->GetParent() == mBlock ||
|
2010-08-05 21:59:20 -07:00
|
|
|
(aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
|
2010-08-05 21:59:19 -07:00
|
|
|
"float should be in this block unless it was marked as "
|
2010-08-05 21:59:20 -07:00
|
|
|
"pushed float");
|
|
|
|
if (aFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT) {
|
2010-08-05 21:59:19 -07:00
|
|
|
// If, in a previous reflow, the float was pushed entirely to
|
|
|
|
// another column/page, we need to steal it back. (We might just
|
|
|
|
// push it again, though.) Likewise, if that previous reflow
|
|
|
|
// reflowed this block but not its next continuation, we might need
|
|
|
|
// to steal it from our own float-continuations list.
|
|
|
|
nsBlockFrame *floatParent =
|
|
|
|
static_cast<nsBlockFrame*>(aFloat->GetParent());
|
|
|
|
floatParent->StealFrame(mPresContext, aFloat);
|
|
|
|
|
2010-08-05 21:59:20 -07:00
|
|
|
aFloat->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
|
2010-08-05 21:59:19 -07:00
|
|
|
|
|
|
|
// Appending is fine, since if a float was pushed to the next
|
|
|
|
// page/column, all later floats were also pushed.
|
|
|
|
mBlock->mFloats.AppendFrame(mBlock, aFloat);
|
|
|
|
}
|
2009-05-20 04:21:34 -07:00
|
|
|
|
2009-04-08 13:52:36 -07:00
|
|
|
// Because we are in the middle of reflowing a placeholder frame
|
|
|
|
// within a line (and possibly nested in an inline frame or two
|
|
|
|
// that's a child of our block) we need to restore the space
|
|
|
|
// manager's translation to the space that the block resides in
|
|
|
|
// before placing the float.
|
|
|
|
nscoord ox, oy;
|
|
|
|
mFloatManager->GetTranslation(ox, oy);
|
|
|
|
nscoord dx = ox - mFloatManagerX;
|
|
|
|
nscoord dy = oy - mFloatManagerY;
|
|
|
|
mFloatManager->Translate(-dx, -dy);
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool placed;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Now place the float immediately if possible. Otherwise stash it
|
|
|
|
// away in mPendingFloats and place it later.
|
2008-06-10 16:53:22 -07:00
|
|
|
// If one or more floats has already been pushed to the next line,
|
|
|
|
// don't let this one go on the current line, since that would violate
|
|
|
|
// float ordering.
|
2009-04-08 13:52:37 -07:00
|
|
|
nsRect floatAvailableSpace = GetFloatAvailableSpace().mRect;
|
2010-08-05 21:59:19 -07:00
|
|
|
if (mBelowCurrentLineFloats.IsEmpty() &&
|
|
|
|
(aLineLayout->LineIsEmpty() ||
|
|
|
|
mBlock->ComputeFloatWidth(*this, floatAvailableSpace, aFloat)
|
|
|
|
<= aAvailableWidth)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// And then place it
|
2010-08-05 21:59:20 -07:00
|
|
|
placed = FlowAndPlaceFloat(aFloat);
|
2010-08-05 21:59:19 -07:00
|
|
|
if (placed) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Pass on updated available space to the current inline reflow engine
|
2010-08-05 21:59:18 -07:00
|
|
|
nsFlowAreaRect floatAvailSpace = GetFloatAvailableSpace(mY);
|
2010-08-11 12:32:53 -07:00
|
|
|
nsRect availSpace(nsPoint(floatAvailSpace.mRect.x, mY),
|
2009-04-08 13:52:37 -07:00
|
|
|
floatAvailSpace.mRect.Size());
|
2010-08-05 21:59:19 -07:00
|
|
|
aLineLayout->UpdateBand(availSpace, aFloat);
|
|
|
|
// Record this float in the current-line list
|
|
|
|
mCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
|
2010-08-05 21:59:20 -07:00
|
|
|
} else {
|
|
|
|
(*aLineLayout->GetLine())->SetHadFloatPushed();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2007-06-27 09:35:31 -07:00
|
|
|
// Always claim to be placed; we don't know whether we fit yet, so we
|
|
|
|
// deal with this in PlaceBelowCurrentLineFloats
|
2011-10-17 07:59:28 -07:00
|
|
|
placed = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
// This float will be placed after the line is done (it is a
|
|
|
|
// below-current-line float).
|
2009-08-31 11:25:36 -07:00
|
|
|
mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-04-08 13:52:36 -07:00
|
|
|
|
|
|
|
// Restore coordinate system
|
|
|
|
mFloatManager->Translate(dx, dy);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return placed;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-08-05 21:59:18 -07:00
|
|
|
nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth,
|
2010-08-05 21:59:18 -07:00
|
|
|
const nsFlowAreaRect& aFloatAvailableSpace)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-08-05 21:59:18 -07:00
|
|
|
// A float fits at a given vertical position if there are no floats at
|
|
|
|
// its horizontal position (no matter what its width) or if its width
|
|
|
|
// fits in the space remaining after prior floats have been placed.
|
|
|
|
// FIXME: We should allow overflow by up to half a pixel here (bug 21193).
|
|
|
|
return !aFloatAvailableSpace.mHasFloats ||
|
|
|
|
aFloatAvailableSpace.mRect.width >= aFloatWidth;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
static nscoord
|
|
|
|
FloatMarginWidth(const nsHTMLReflowState& aCBReflowState,
|
|
|
|
nscoord aFloatAvailableWidth,
|
|
|
|
nsIFrame *aFloat,
|
|
|
|
const nsCSSOffsetState& aFloatOffsetState)
|
|
|
|
{
|
2012-01-24 17:21:29 -08:00
|
|
|
AutoMaybeNullInflationContainer an(aFloat);
|
2010-08-05 21:59:18 -07:00
|
|
|
return aFloat->ComputeSize(
|
|
|
|
aCBReflowState.rendContext,
|
|
|
|
nsSize(aCBReflowState.ComputedWidth(),
|
|
|
|
aCBReflowState.ComputedHeight()),
|
|
|
|
aFloatAvailableWidth,
|
|
|
|
nsSize(aFloatOffsetState.mComputedMargin.LeftRight(),
|
|
|
|
aFloatOffsetState.mComputedMargin.TopBottom()),
|
|
|
|
nsSize(aFloatOffsetState.mComputedBorderPadding.LeftRight() -
|
|
|
|
aFloatOffsetState.mComputedPadding.LeftRight(),
|
|
|
|
aFloatOffsetState.mComputedBorderPadding.TopBottom() -
|
|
|
|
aFloatOffsetState.mComputedPadding.TopBottom()),
|
|
|
|
nsSize(aFloatOffsetState.mComputedPadding.LeftRight(),
|
|
|
|
aFloatOffsetState.mComputedPadding.TopBottom()),
|
2011-10-17 07:59:28 -07:00
|
|
|
true).width +
|
2010-08-05 21:59:18 -07:00
|
|
|
aFloatOffsetState.mComputedMargin.LeftRight() +
|
|
|
|
aFloatOffsetState.mComputedBorderPadding.LeftRight();
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-08-05 21:59:20 -07:00
|
|
|
nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Save away the Y coordinate before placing the float. We will
|
|
|
|
// restore mY at the end after placing the float. This is
|
|
|
|
// necessary because any adjustments to mY during the float
|
|
|
|
// placement are for the float only, not for any non-floating
|
|
|
|
// content.
|
2010-08-05 21:59:19 -07:00
|
|
|
AutoRestore<nscoord> restoreY(mY);
|
|
|
|
// FIXME: Should give AutoRestore a getter for the value to avoid this.
|
|
|
|
const nscoord saveY = mY;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Grab the float's display information
|
2009-08-31 11:25:35 -07:00
|
|
|
const nsStyleDisplay* floatDisplay = aFloat->GetStyleDisplay();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// The float's old region, so we can propagate damage.
|
2009-08-31 11:25:35 -07:00
|
|
|
nsRect oldRegion = nsFloatManager::GetRegionFor(aFloat);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
|
|
|
|
// ``above'' another float that preceded it in the flow.
|
2010-08-11 12:32:53 -07:00
|
|
|
mY = NS_MAX(mFloatManager->GetLowestFloatTop(), mY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// See if the float should clear any preceding floats...
|
2007-06-16 13:27:46 -07:00
|
|
|
// XXX We need to mark this float somehow so that it gets reflowed
|
|
|
|
// when floats are inserted before it.
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
|
|
|
|
// XXXldb Does this handle vertical margins correctly?
|
|
|
|
mY = ClearFloats(mY, floatDisplay->mBreakType);
|
|
|
|
}
|
|
|
|
// Get the band of available space
|
2010-08-05 21:59:18 -07:00
|
|
|
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mY);
|
2010-08-05 21:59:18 -07:00
|
|
|
nsRect adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
|
|
|
|
floatAvailableSpace.mRect, aFloat);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-31 11:25:35 -07:00
|
|
|
NS_ASSERTION(aFloat->GetParent() == mBlock,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Float frame has wrong parent");
|
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
nsCSSOffsetState offsets(aFloat, mReflowState.rendContext,
|
|
|
|
mReflowState.ComputedWidth());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
nscoord floatMarginWidth = FloatMarginWidth(mReflowState,
|
|
|
|
adjustedAvailableSpace.width,
|
|
|
|
aFloat, offsets);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-06 21:25:47 -07:00
|
|
|
nsMargin floatMargin; // computed margin
|
|
|
|
nsReflowStatus reflowStatus;
|
|
|
|
|
|
|
|
// If it's a floating first-letter, we need to reflow it before we
|
|
|
|
// know how wide it is (since we don't compute which letters are part
|
|
|
|
// of the first letter until reflow!).
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isLetter = aFloat->GetType() == nsGkAtoms::letterFrame;
|
2010-10-06 21:25:47 -07:00
|
|
|
if (isLetter) {
|
|
|
|
mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat,
|
2011-10-17 07:59:28 -07:00
|
|
|
floatMargin, false, reflowStatus);
|
2010-10-06 21:25:47 -07:00
|
|
|
floatMarginWidth = aFloat->GetSize().width + floatMargin.LeftRight();
|
|
|
|
NS_ASSERTION(NS_FRAME_IS_COMPLETE(reflowStatus),
|
|
|
|
"letter frames shouldn't break, and if they do now, "
|
|
|
|
"then they're breaking at the wrong point");
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Find a place to place the float. The CSS2 spec doesn't want
|
|
|
|
// floats overlapping each other or sticking out of the containing
|
|
|
|
// block if possible (CSS2 spec section 9.5.1, see the rule list).
|
|
|
|
NS_ASSERTION((NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) ||
|
|
|
|
(NS_STYLE_FLOAT_RIGHT == floatDisplay->mFloats),
|
|
|
|
"invalid float type");
|
|
|
|
|
|
|
|
// Can the float fit here?
|
2011-09-28 23:19:26 -07:00
|
|
|
bool keepFloatOnSameLine = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-19 06:38:00 -07:00
|
|
|
// Are we required to place at least part of the float because we're
|
|
|
|
// at the top of the page (to avoid an infinite loop of pushing and
|
|
|
|
// breaking).
|
2011-09-28 23:19:26 -07:00
|
|
|
bool mustPlaceFloat =
|
2010-08-19 06:38:00 -07:00
|
|
|
mReflowState.mFlags.mIsTopOfPage && IsAdjacentWithTop();
|
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
for (;;) {
|
2010-08-05 21:59:20 -07:00
|
|
|
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE &&
|
2010-08-19 06:38:00 -07:00
|
|
|
floatAvailableSpace.mRect.height <= 0 &&
|
|
|
|
!mustPlaceFloat) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// No space, nowhere to put anything.
|
2010-08-05 21:59:19 -07:00
|
|
|
PushFloatPastBreak(aFloat);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
if (CanPlaceFloat(floatMarginWidth, floatAvailableSpace)) {
|
2010-08-05 21:59:18 -07:00
|
|
|
// We found an appropriate place.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Nope. try to advance to the next band.
|
|
|
|
if (NS_STYLE_DISPLAY_TABLE != floatDisplay->mDisplay ||
|
|
|
|
eCompatibility_NavQuirks != mPresContext->CompatibilityMode() ) {
|
|
|
|
|
2009-04-08 13:52:37 -07:00
|
|
|
mY += floatAvailableSpace.mRect.height;
|
2010-08-05 21:59:18 -07:00
|
|
|
if (adjustedAvailableSpace.height != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
adjustedAvailableSpace.height -= floatAvailableSpace.mRect.height;
|
|
|
|
}
|
2010-08-05 21:59:18 -07:00
|
|
|
floatAvailableSpace = GetFloatAvailableSpace(mY);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2010-08-05 21:59:18 -07:00
|
|
|
// This quirk matches the one in nsBlockFrame::AdjustFloatAvailableSpace
|
2007-03-22 10:30:00 -07:00
|
|
|
// IE handles float tables in a very special way
|
|
|
|
|
|
|
|
// see if the previous float is also a table and has "align"
|
|
|
|
nsFloatCache* fc = mCurrentLineFloats.Head();
|
|
|
|
nsIFrame* prevFrame = nsnull;
|
|
|
|
while (fc) {
|
2009-08-31 11:25:35 -07:00
|
|
|
if (fc->mFloat == aFloat) {
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
2009-08-31 11:25:35 -07:00
|
|
|
prevFrame = fc->mFloat;
|
2007-03-22 10:30:00 -07:00
|
|
|
fc = fc->Next();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(prevFrame) {
|
|
|
|
//get the frame type
|
|
|
|
if (nsGkAtoms::tableOuterFrame == prevFrame->GetType()) {
|
|
|
|
//see if it has "align="
|
|
|
|
// IE makes a difference between align and he float property
|
|
|
|
nsIContent* content = prevFrame->GetContent();
|
|
|
|
if (content) {
|
|
|
|
// we're interested only if previous frame is align=left
|
|
|
|
// IE messes things up when "right" (overlapping frames)
|
|
|
|
if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::align,
|
|
|
|
NS_LITERAL_STRING("left"), eIgnoreCase)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
keepFloatOnSameLine = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
// don't advance to next line (IE quirkie behaviour)
|
|
|
|
// it breaks rule CSS2/9.5.1/1, but what the hell
|
|
|
|
// since we cannot evangelize the world
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// the table does not fit anymore in this line so advance to next band
|
2009-04-08 13:52:37 -07:00
|
|
|
mY += floatAvailableSpace.mRect.height;
|
2010-08-05 21:59:18 -07:00
|
|
|
// To match nsBlockFrame::AdjustFloatAvailableSpace, we have to
|
|
|
|
// get a new width for the new band.
|
2010-08-05 21:59:18 -07:00
|
|
|
floatAvailableSpace = GetFloatAvailableSpace(mY);
|
2010-08-05 21:59:18 -07:00
|
|
|
adjustedAvailableSpace = mBlock->AdjustFloatAvailableSpace(*this,
|
|
|
|
floatAvailableSpace.mRect, aFloat);
|
|
|
|
floatMarginWidth = FloatMarginWidth(mReflowState,
|
|
|
|
adjustedAvailableSpace.width,
|
|
|
|
aFloat, offsets);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-08-19 06:38:00 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
mustPlaceFloat = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-08-05 21:59:18 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If the float is continued, it will get the same absolute x value as its prev-in-flow
|
|
|
|
|
|
|
|
// We don't worry about the geometry of the prev in flow, let the continuation
|
|
|
|
// place and size itself as required.
|
|
|
|
|
2010-08-11 12:32:53 -07:00
|
|
|
// Assign an x and y coordinate to the float.
|
2007-03-22 10:30:00 -07:00
|
|
|
nscoord floatX, floatY;
|
|
|
|
if (NS_STYLE_FLOAT_LEFT == floatDisplay->mFloats) {
|
2009-04-08 13:52:37 -07:00
|
|
|
floatX = floatAvailableSpace.mRect.x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!keepFloatOnSameLine) {
|
2010-08-05 21:59:18 -07:00
|
|
|
floatX = floatAvailableSpace.mRect.XMost() - floatMarginWidth;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// this is the IE quirk (see few lines above)
|
|
|
|
// the table is kept in the same line: don't let it overlap the
|
|
|
|
// previous float
|
2009-04-08 13:52:37 -07:00
|
|
|
floatX = floatAvailableSpace.mRect.x;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2010-08-11 12:32:53 -07:00
|
|
|
// CSS2 spec, 9.5.1 rule [4]: "A floating box's outer top may not
|
|
|
|
// be higher than the top of its containing block." (Since the
|
|
|
|
// containing block is the content edge of the block box, this
|
|
|
|
// means the margin edge of the float can't be higher than the
|
|
|
|
// content edge of the block that contains it.)
|
|
|
|
floatY = NS_MAX(mY, mContentArea.y);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-08-05 21:59:18 -07:00
|
|
|
// Reflow the float after computing its vertical position so it knows
|
|
|
|
// where to break.
|
2010-10-06 21:25:47 -07:00
|
|
|
if (!isLetter) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool pushedDown = mY != saveY;
|
2010-10-06 21:25:47 -07:00
|
|
|
mBlock->ReflowFloat(*this, adjustedAvailableSpace, aFloat,
|
|
|
|
floatMargin, pushedDown, reflowStatus);
|
|
|
|
}
|
2010-08-05 21:59:18 -07:00
|
|
|
if (aFloat->GetPrevInFlow())
|
|
|
|
floatMargin.top = 0;
|
2010-08-05 21:59:19 -07:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus))
|
2010-08-05 21:59:18 -07:00
|
|
|
floatMargin.bottom = 0;
|
|
|
|
|
2010-08-05 21:59:19 -07:00
|
|
|
// In the case that we're in columns and not splitting floats, we need
|
|
|
|
// to check here that the float's height fit, and if it didn't, bail.
|
|
|
|
// (This code is only for DISABLE_FLOAT_BREAKING_IN_COLUMNS .)
|
2010-08-05 21:59:19 -07:00
|
|
|
//
|
|
|
|
// Likewise, if none of the float fit, and it needs to be pushed in
|
|
|
|
// its entirety to the next page (NS_FRAME_IS_TRUNCATED), we need to
|
|
|
|
// do the same.
|
|
|
|
if ((mContentArea.height != NS_UNCONSTRAINEDSIZE &&
|
|
|
|
adjustedAvailableSpace.height == NS_UNCONSTRAINEDSIZE &&
|
2010-08-19 06:38:00 -07:00
|
|
|
!mustPlaceFloat &&
|
2010-08-05 21:59:19 -07:00
|
|
|
aFloat->GetSize().height + floatMargin.TopBottom() >
|
2010-08-11 12:32:53 -07:00
|
|
|
mContentArea.YMost() - floatY) ||
|
2010-08-05 21:59:19 -07:00
|
|
|
NS_FRAME_IS_TRUNCATED(reflowStatus)) {
|
|
|
|
|
|
|
|
PushFloatPastBreak(aFloat);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-08-05 21:59:19 -07:00
|
|
|
}
|
|
|
|
|
2009-07-14 22:19:31 -07:00
|
|
|
// Calculate the actual origin of the float frame's border rect
|
2010-08-11 12:32:53 -07:00
|
|
|
// relative to the parent block; the margin must be added in
|
2009-07-14 22:19:31 -07:00
|
|
|
// to get the border rect
|
2010-08-11 12:32:53 -07:00
|
|
|
nsPoint origin(floatMargin.left + floatX,
|
|
|
|
floatMargin.top + floatY);
|
2009-07-14 22:19:31 -07:00
|
|
|
|
|
|
|
// If float is relatively positioned, factor that in as well
|
2009-08-31 11:25:35 -07:00
|
|
|
origin += aFloat->GetRelativeOffset(floatDisplay);
|
2009-07-14 22:19:31 -07:00
|
|
|
|
|
|
|
// Position the float and make sure and views are properly
|
|
|
|
// positioned. We need to explicitly position its child views as
|
|
|
|
// well, since we're moving the float after flowing it.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool moved = aFloat->GetPosition() != origin;
|
2010-12-19 17:37:43 -08:00
|
|
|
if (moved) {
|
|
|
|
aFloat->SetPosition(origin);
|
|
|
|
nsContainerFrame::PositionFrameView(aFloat);
|
|
|
|
nsContainerFrame::PositionChildViews(aFloat);
|
|
|
|
FrameLayerBuilder::InvalidateThebesLayersInSubtree(aFloat);
|
|
|
|
}
|
2009-07-14 22:19:31 -07:00
|
|
|
|
|
|
|
// Update the float combined area state
|
|
|
|
// XXX Floats should really just get invalidated here if necessary
|
2010-10-06 21:25:45 -07:00
|
|
|
mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() + origin);
|
2009-07-14 22:19:31 -07:00
|
|
|
|
2009-01-04 16:39:54 -08:00
|
|
|
// Place the float in the float manager
|
2009-07-14 22:19:31 -07:00
|
|
|
// calculate region
|
2009-08-31 11:25:35 -07:00
|
|
|
nsRect region = nsFloatManager::CalculateRegionFor(aFloat, floatMargin);
|
2009-07-14 22:19:31 -07:00
|
|
|
// if the float split, then take up all of the vertical height
|
2010-08-05 21:59:19 -07:00
|
|
|
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
|
2007-03-22 10:30:00 -07:00
|
|
|
(NS_UNCONSTRAINEDSIZE != mContentArea.height)) {
|
2009-09-16 08:01:36 -07:00
|
|
|
region.height = NS_MAX(region.height, mContentArea.height - floatY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
nsresult rv =
|
2010-08-11 12:32:53 -07:00
|
|
|
mFloatManager->AddFloat(aFloat, region);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
|
2009-07-14 22:19:31 -07:00
|
|
|
// store region
|
2011-05-08 01:00:29 -07:00
|
|
|
nsFloatManager::StoreRegionFor(aFloat, region);
|
2007-06-16 13:27:46 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If the float's dimensions have changed, note the damage in the
|
2009-01-04 16:39:54 -08:00
|
|
|
// float manager.
|
2011-04-18 20:07:23 -07:00
|
|
|
if (!region.IsEqualEdges(oldRegion)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXXwaterson conservative: we could probably get away with noting
|
|
|
|
// less damage; e.g., if only height has changed, then only note the
|
|
|
|
// area into which the float has grown or from which the float has
|
|
|
|
// shrunk.
|
2010-08-11 12:32:53 -07:00
|
|
|
nscoord top = NS_MIN(region.y, oldRegion.y);
|
|
|
|
nscoord bottom = NS_MAX(region.YMost(), oldRegion.YMost());
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->IncludeInDamage(top, bottom);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-19 06:38:00 -07:00
|
|
|
if (!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus)) {
|
2010-08-05 21:59:19 -07:00
|
|
|
mBlock->SplitFloat(*this, aFloat, reflowStatus);
|
|
|
|
}
|
|
|
|
|
2009-01-04 16:39:54 -08:00
|
|
|
#ifdef NOISY_FLOATMANAGER
|
2007-03-22 10:30:00 -07:00
|
|
|
nscoord tx, ty;
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->GetTranslation(tx, ty);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFrame::ListTag(stdout, mBlock);
|
2009-01-04 16:39:54 -08:00
|
|
|
printf(": FlowAndPlaceFloat: AddFloat: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
|
2009-01-04 16:39:54 -08:00
|
|
|
tx, ty, mFloatManagerX, mFloatManagerY,
|
2009-07-14 22:19:31 -07:00
|
|
|
region.x, region.y, region.width, region.height);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
2009-08-31 11:25:35 -07:00
|
|
|
nsRect r = aFloat->GetRect();
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
printf("placed float: ");
|
2009-08-31 11:25:35 -07:00
|
|
|
nsFrame::ListTag(stdout, aFloat);
|
2007-03-22 10:30:00 -07:00
|
|
|
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-05 21:59:19 -07:00
|
|
|
void
|
|
|
|
nsBlockReflowState::PushFloatPastBreak(nsIFrame *aFloat)
|
|
|
|
{
|
|
|
|
// This ensures that we:
|
|
|
|
// * don't try to place later but smaller floats (which CSS says
|
|
|
|
// must have their tops below the top of this float)
|
|
|
|
// * don't waste much time trying to reflow this float again until
|
|
|
|
// after the break
|
|
|
|
if (aFloat->GetStyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
|
|
|
|
mFloatManager->SetPushedLeftFloatPastBreak();
|
|
|
|
} else {
|
|
|
|
NS_ABORT_IF_FALSE(aFloat->GetStyleDisplay()->mFloats ==
|
|
|
|
NS_STYLE_FLOAT_RIGHT,
|
|
|
|
"unexpected float value");
|
|
|
|
mFloatManager->SetPushedRightFloatPastBreak();
|
|
|
|
}
|
|
|
|
|
2010-08-05 21:59:20 -07:00
|
|
|
// Put the float on the pushed floats list, even though it
|
2010-08-05 21:59:19 -07:00
|
|
|
// isn't actually a continuation.
|
2011-06-21 08:37:47 -07:00
|
|
|
DebugOnly<nsresult> rv = mBlock->StealFrame(mPresContext, aFloat);
|
2010-08-05 21:59:19 -07:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame should succeed");
|
2010-08-05 21:59:20 -07:00
|
|
|
AppendPushedFloat(aFloat);
|
2010-08-05 21:59:19 -07:00
|
|
|
|
|
|
|
NS_FRAME_SET_OVERFLOW_INCOMPLETE(mReflowStatus);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/**
|
|
|
|
* Place below-current-line floats.
|
|
|
|
*/
|
2010-08-05 21:59:20 -07:00
|
|
|
void
|
2010-08-05 21:59:20 -07:00
|
|
|
nsBlockReflowState::PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aList,
|
|
|
|
nsLineBox* aLine)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsFloatCache* fc = aList.Head();
|
|
|
|
while (fc) {
|
|
|
|
#ifdef DEBUG
|
2010-08-05 21:59:20 -07:00
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
|
|
|
printf("placing bcl float: ");
|
|
|
|
nsFrame::ListTag(stdout, fc->mFloat);
|
|
|
|
printf("\n");
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2010-08-05 21:59:20 -07:00
|
|
|
// Place the float
|
2011-09-28 23:19:26 -07:00
|
|
|
bool placed = FlowAndPlaceFloat(fc->mFloat);
|
2010-08-05 21:59:20 -07:00
|
|
|
nsFloatCache *next = fc->Next();
|
|
|
|
if (!placed) {
|
|
|
|
aList.Remove(fc);
|
|
|
|
delete fc;
|
2010-08-05 21:59:20 -07:00
|
|
|
aLine->SetHadFloatPushed();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-08-05 21:59:20 -07:00
|
|
|
fc = next;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nscoord
|
2008-01-28 23:40:05 -08:00
|
|
|
nsBlockReflowState::ClearFloats(nscoord aY, PRUint8 aBreakType,
|
2010-08-05 21:59:19 -07:00
|
|
|
nsIFrame *aReplacedBlock,
|
|
|
|
PRUint32 aFlags)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
2010-08-11 12:32:53 -07:00
|
|
|
printf("clear floats: in: aY=%d\n", aY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NOISY_FLOAT_CLEARING
|
|
|
|
printf("nsBlockReflowState::ClearFloats: aY=%d breakType=%d\n",
|
|
|
|
aY, aBreakType);
|
2009-01-04 16:39:54 -08:00
|
|
|
mFloatManager->List(stdout);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
2008-01-28 23:40:05 -08:00
|
|
|
nscoord newY = aY;
|
|
|
|
|
|
|
|
if (aBreakType != NS_STYLE_CLEAR_NONE) {
|
2010-08-11 12:32:53 -07:00
|
|
|
newY = mFloatManager->ClearFloats(newY, aBreakType, aFlags);
|
2008-01-28 23:40:05 -08:00
|
|
|
}
|
|
|
|
|
2008-05-03 16:33:36 -07:00
|
|
|
if (aReplacedBlock) {
|
2008-01-28 23:40:05 -08:00
|
|
|
for (;;) {
|
2010-08-05 21:59:18 -07:00
|
|
|
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newY);
|
2008-05-03 16:33:36 -07:00
|
|
|
nsBlockFrame::ReplacedElementWidthToClear replacedWidth =
|
2009-04-08 13:52:37 -07:00
|
|
|
nsBlockFrame::WidthToClearPastFloats(*this, floatAvailableSpace.mRect,
|
2009-04-08 13:52:37 -07:00
|
|
|
aReplacedBlock);
|
2009-04-08 13:52:37 -07:00
|
|
|
if (!floatAvailableSpace.mHasFloats ||
|
2010-08-11 12:32:53 -07:00
|
|
|
NS_MAX(floatAvailableSpace.mRect.x - mContentArea.x,
|
|
|
|
replacedWidth.marginLeft) +
|
2008-05-03 16:33:36 -07:00
|
|
|
replacedWidth.borderBoxWidth +
|
2010-08-11 12:32:53 -07:00
|
|
|
NS_MAX(mContentArea.XMost() - floatAvailableSpace.mRect.XMost(),
|
2008-05-03 16:33:36 -07:00
|
|
|
replacedWidth.marginRight) <=
|
2008-04-14 18:05:17 -07:00
|
|
|
mContentArea.width) {
|
2008-01-28 23:40:05 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
|
2009-04-08 13:52:37 -07:00
|
|
|
if (floatAvailableSpace.mRect.height > 0) {
|
2008-01-28 23:40:05 -08:00
|
|
|
// See if there's room in the next band.
|
2009-04-08 13:52:37 -07:00
|
|
|
newY += floatAvailableSpace.mRect.height;
|
2008-01-28 23:40:05 -08:00
|
|
|
} else {
|
|
|
|
if (mReflowState.availableHeight != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
// Stop trying to clear here; we'll just get pushed to the
|
|
|
|
// next column or page and try again there.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NS_NOTREACHED("avail space rect with zero height!");
|
|
|
|
newY += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (nsBlockFrame::gNoisyReflow) {
|
|
|
|
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
|
2010-08-11 12:32:53 -07:00
|
|
|
printf("clear floats: out: y=%d\n", newY);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return newY;
|
|
|
|
}
|
|
|
|
|