--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1841,18 +1841,19 @@ nsBlockFrame::PropagateFloatDamage(nsBlo
// with aLine's floats
nscoord lineYA = aLine->BStart() + aDeltaY;
nscoord lineYB = lineYA + aLine->BSize();
// Scrollable overflow should be sufficient for things that affect
// layout.
nsRect overflow = aLine->GetOverflowArea(eScrollableOverflow);
nscoord lineYCombinedA = overflow.y + aDeltaY;
nscoord lineYCombinedB = lineYCombinedA + overflow.height;
- if (floatManager->IntersectsDamage(lineYA, lineYB) ||
- floatManager->IntersectsDamage(lineYCombinedA, lineYCombinedB)) {
+ WritingMode wm = aState.mReflowState.GetWritingMode();
+ if (floatManager->IntersectsDamage(wm, lineYA, lineYB) ||
+ floatManager->IntersectsDamage(wm, lineYCombinedA, lineYCombinedB)) {
aLine->MarkDirty();
return;
}
}
// Check if the line is moving relative to the float manager
if (aDeltaY + aState.mReflowState.mBlockDelta != 0) {
if (aLine->IsBlock()) {
@@ -3179,17 +3180,18 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
// Reflow the block into the available space
// construct the html reflow state for the block. ReflowBlock
// will initialize it
nsHTMLReflowState
blockHtmlRS(aState.mPresContext, aState.mReflowState, frame,
LogicalSize(frame->GetWritingMode(), availSpace.Size()));
blockHtmlRS.mFlags.mHasClearance = aLine->HasClearance();
- nsFloatManager::SavedState floatManagerState;
+ nsFloatManager::SavedState
+ floatManagerState(aState.mReflowState.GetWritingMode());
if (mayNeedRetry) {
blockHtmlRS.mDiscoveredClearance = &clearanceFrame;
aState.mFloatManager->PushState(&floatManagerState);
} else if (!applyBStartMargin) {
blockHtmlRS.mDiscoveredClearance = aState.mReflowState.mDiscoveredClearance;
}
nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
@@ -3444,17 +3446,18 @@ nsBlockFrame::ReflowInlineFrames(nsBlock
do {
nscoord availableSpaceHeight = 0;
do {
bool allowPullUp = true;
nsIContent* forceBreakInContent = nullptr;
int32_t forceBreakOffset = -1;
gfxBreakPriority forceBreakPriority = gfxBreakPriority::eNoBreak;
do {
- nsFloatManager::SavedState floatManagerState;
+ nsFloatManager::SavedState
+ floatManagerState(aState.mReflowState.GetWritingMode());
aState.mReflowState.mFloatManager->PushState(&floatManagerState);
// Once upon a time we allocated the first 30 nsLineLayout objects
// on the stack, and then we switched to the heap. At that time
// these objects were large (1100 bytes on a 32 bit system).
// Then the nsLineLayout object was shrunk to 156 bytes by
// removing some internal buffers. Given that it is so much
// smaller, the complexity of 2 different ways of allocating
@@ -5979,60 +5982,63 @@ nsBlockFrame::ReflowPushedFloats(nsBlock
// If there are continued floats, then we may need to continue BR clearance
if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_BOTH)) {
aState.mFloatBreakType = static_cast<nsBlockFrame*>(GetPrevInFlow())
->FindTrailingClear();
}
}
void
-nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager)
+nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager, WritingMode aWM,
+ nscoord aContainerWidth)
{
// Recover our own floats
nsIFrame* stop = nullptr; // Stop before we reach pushed floats that
// belong to our next-in-flow
for (nsIFrame* f = mFloats.FirstChild(); f && f != stop; f = f->GetNextSibling()) {
- nsRect region = nsFloatManager::GetRegionFor(f);
- aFloatManager.AddFloat(f, region);
+ LogicalRect region = nsFloatManager::GetRegionFor(aWM, f, aContainerWidth);
+ aFloatManager.AddFloat(f, region, aWM, aContainerWidth);
if (!stop && f->GetNextInFlow())
stop = f->GetNextInFlow();
}
// Recurse into our overflow container children
for (nsIFrame* oc = GetFirstChild(kOverflowContainersList);
oc; oc = oc->GetNextSibling()) {
- RecoverFloatsFor(oc, aFloatManager);
+ RecoverFloatsFor(oc, aFloatManager, aWM, aContainerWidth);
}
// Recurse into our normal children
for (nsBlockFrame::line_iterator line = begin_lines(); line != end_lines(); ++line) {
if (line->IsBlock()) {
- RecoverFloatsFor(line->mFirstChild, aFloatManager);
+ RecoverFloatsFor(line->mFirstChild, aFloatManager, aWM, aContainerWidth);
}
}
}
void
nsBlockFrame::RecoverFloatsFor(nsIFrame* aFrame,
- nsFloatManager& aFloatManager)
+ nsFloatManager& aFloatManager,
+ WritingMode aWM,
+ nscoord aContainerWidth)
{
NS_PRECONDITION(aFrame, "null frame");
// Only blocks have floats
nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
// Don't recover any state inside a block that has its own space manager
// (we don't currently have any blocks like this, though, thanks to our
// use of extra frames for 'overflow')
if (block && !nsBlockFrame::BlockNeedsFloatManager(block)) {
// If the element is relatively positioned, then adjust x and y
// accordingly so that we consider relatively positioned frames
// at their original position.
- nsPoint pos = block->GetNormalPosition();
- aFloatManager.Translate(pos.x, pos.y);
- block->RecoverFloats(aFloatManager);
- aFloatManager.Translate(-pos.x, -pos.y);
+ LogicalPoint pos = block->GetLogicalNormalPosition(aWM, aContainerWidth);
+ WritingMode oldWM = aFloatManager.Translate(aWM, pos, aContainerWidth);
+ block->RecoverFloats(aFloatManager, aWM, aContainerWidth);
+ aFloatManager.Untranslate(oldWM, pos, aContainerWidth);
}
}
//////////////////////////////////////////////////////////////////////
// Painting, event handling
#ifdef DEBUG
static void ComputeVisualOverflowArea(nsLineList& aLines,
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -471,18 +471,20 @@ public:
virtual bool UpdateOverflow() MOZ_OVERRIDE;
/** Load all of aFrame's floats into the float manager iff aFrame is not a
* block formatting context. Handles all necessary float manager translations;
* assumes float manager is in aFrame's parent's coord system.
* Safe to call on non-blocks (does nothing).
*/
- static void RecoverFloatsFor(nsIFrame* aFrame,
- nsFloatManager& aFloatManager);
+ static void RecoverFloatsFor(nsIFrame* aFrame,
+ nsFloatManager& aFloatManager,
+ mozilla::WritingMode aWM,
+ nscoord aContainerWidth);
/**
* Determine if we have any pushed floats from a previous continuation.
*
* @returns true, if any of the floats at the beginning of our mFloats list
* have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise.
*/
bool HasPushedFloatsFromPrevContinuation() const {
@@ -536,17 +538,19 @@ protected:
/** grab pushed floats from this block's prevInFlow, and splice
* them into this block's mFloats list.
*/
void DrainPushedFloats(nsBlockReflowState& aState);
/** Load all our floats into the float manager (without reflowing them).
* Assumes float manager is in our own coordinate system.
*/
- void RecoverFloats(nsFloatManager& aFloatManager);
+ void RecoverFloats(nsFloatManager& aFloatManager,
+ mozilla::WritingMode aWM,
+ nscoord aContainerWidth);
/** Reflow pushed floats
*/
void ReflowPushedFloats(nsBlockReflowState& aState,
nsOverflowAreas& aOverflowAreas,
nsReflowStatus& aStatus);
/** Find any trailing BR clear from the last line of the block (or its PIFs)
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -245,55 +245,53 @@ nsBlockReflowContext::ReflowBlock(const
// Adjust the available block size if it's constrained so that the
// child frame doesn't think it can reflow into its margin area.
if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableBSize()) {
aFrameRS.AvailableBSize() -= mBStartMargin.get() + aClearance;
}
}
- nscoord tI = 0, tB = 0;
+ LogicalPoint tPt(mWritingMode);
// The values of x and y do not matter for floats, so don't bother
// calculating them. Floats are guaranteed to have their own float
// manager, so tI and tB don't matter. mICoord and mBCoord don't
// matter becacuse they are only used in PlaceBlock, which is not used
// for floats.
if (aLine) {
// Compute inline/block coordinate where reflow will begin. Use the
// rules from 10.3.3 to determine what to apply. At this point in the
// reflow auto inline-start/end margins will have a zero value.
WritingMode frameWM = aFrameRS.GetWritingMode();
- mICoord = tI =
+ mICoord = tPt.I(mWritingMode) =
mSpace.IStart(mWritingMode) +
aFrameRS.ComputedLogicalMargin().ConvertTo(mWritingMode,
frameWM).IStart(mWritingMode);
- mBCoord = tB = mSpace.BStart(mWritingMode) +
- mBStartMargin.get() + aClearance;
-
- //XXX temporary until nsFloatManager is logicalized
- tI = aSpace.x + aFrameRS.ComputedPhysicalMargin().left;
- tB = aSpace.y + mBStartMargin.get() + aClearance;
+ mBCoord = tPt.B(mWritingMode) = mSpace.BStart(mWritingMode) +
+ mBStartMargin.get() + aClearance;
if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0)
aFrameRS.mBlockDelta =
mOuterReflowState.mBlockDelta + mBCoord - aLine->BStart();
}
// Let frame know that we are reflowing it
mFrame->WillReflow(mPresContext);
#ifdef DEBUG
mMetrics.ISize(mWritingMode) = nscoord(0xdeadbeef);
mMetrics.BSize(mWritingMode) = nscoord(0xdeadbeef);
#endif
- mOuterReflowState.mFloatManager->Translate(tI, tB);
+ WritingMode oldWM =
+ mOuterReflowState.mFloatManager->Translate(mWritingMode, tPt,
+ mContainerWidth);
mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus);
- mOuterReflowState.mFloatManager->Translate(-tI, -tB);
+ mOuterReflowState.mFloatManager->Untranslate(oldWM, tPt, mContainerWidth);
#ifdef DEBUG
if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
if (CRAZY_SIZE(mMetrics.ISize(mWritingMode)) ||
CRAZY_SIZE(mMetrics.BSize(mWritingMode))) {
printf("nsBlockReflowContext: ");
nsFrame::ListTag(stdout, mFrame);
printf(" metrics=%d,%d!\n",
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -29,16 +29,18 @@ nsBlockReflowState::nsBlockReflowState(c
nsBlockFrame* aFrame,
bool aBStartMarginRoot,
bool aBEndMarginRoot,
bool aBlockNeedsFloatManager,
nscoord aConsumedBSize)
: mBlock(aFrame),
mPresContext(aPresContext),
mReflowState(aReflowState),
+ mFloatManagerOrigin(aReflowState.GetWritingMode()),
+ mFloatManagerStateBefore(aReflowState.GetWritingMode()),
mContentArea(aReflowState.GetWritingMode()),
mPushedFloats(nullptr),
mOverflowTracker(nullptr),
mBorderPadding(mReflowState.ComputedLogicalBorderPadding()),
mPrevBEndMargin(),
mLineNumber(0),
mFlags(0),
mFloatBreakType(NS_STYLE_CLEAR_NONE),
@@ -69,17 +71,17 @@ nsBlockReflowState::nsBlockReflowState(c
}
mFloatManager = aReflowState.mFloatManager;
NS_ASSERTION(mFloatManager,
"FloatManager should be set in nsBlockReflowState" );
if (mFloatManager) {
// Save the coordinate system origin for later.
- mFloatManager->GetTranslation(mFloatManagerX, mFloatManagerY);
+ mFloatManager->GetTranslation(mFloatManagerWM, mFloatManagerOrigin);
mFloatManager->PushState(&mFloatManagerStateBefore); // never popped
}
mReflowStatus = NS_FRAME_COMPLETE;
mNextInFlow = static_cast<nsBlockFrame*>(mBlock->GetNextInFlow());
NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aReflowState.ComputedISize(),
@@ -274,31 +276,37 @@ nsBlockReflowState::ComputeBlockAvailSpa
#endif
}
nsFlowAreaRect
nsBlockReflowState::GetFloatAvailableSpaceWithState(
nscoord aBCoord,
nsFloatManager::SavedState *aState) const
{
+ WritingMode wm = mReflowState.GetWritingMode();
#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");
+ WritingMode wWM;
+ LogicalPoint wPt(wWM);
+ mFloatManager->GetTranslation(wWM, wPt);
+
+ if (wWM == mFloatManagerWM) {
+ NS_ASSERTION(wPt == mFloatManagerOrigin, "bad coord system");
+ } else {
+ //XXX if the writing modes are different we can't easily assert that
+ // the origin is the same.
+ }
#endif
- nsRect contentArea =
- mContentArea.GetPhysicalRect(mReflowState.GetWritingMode(), mContainerWidth);
- nscoord height = (contentArea.height == nscoord_MAX)
- ? nscoord_MAX : std::max(contentArea.YMost() - aBCoord, 0);
+ nscoord blockSize = (mContentArea.BSize(wm) == nscoord_MAX)
+ ? nscoord_MAX : std::max(mContentArea.BEnd(wm) - aBCoord, 0);
nsFlowAreaRect result =
- mFloatManager->GetFlowArea(aBCoord, nsFloatManager::BAND_FROM_POINT,
- height, contentArea, aState);
+ mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::BAND_FROM_POINT,
+ blockSize, mContentArea, aState,
+ mContainerWidth);
// 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("GetAvailableSpace: band=%d,%d,%d,%d hasfloats=%d\n",
@@ -309,28 +317,32 @@ nsBlockReflowState::GetFloatAvailableSpa
return result;
}
nsFlowAreaRect
nsBlockReflowState::GetFloatAvailableSpaceForBSize(
nscoord aBCoord, nscoord aBSize,
nsFloatManager::SavedState *aState) const
{
+ WritingMode wm = mReflowState.GetWritingMode();
#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");
+ WritingMode wWM;
+ LogicalPoint wPt(wWM);
+ mFloatManager->GetTranslation(wWM, wPt);
+ if (wWM == mFloatManagerWM) {
+ NS_ASSERTION(wPt == mFloatManagerOrigin, "bad coord system");
+ } else {
+ //XXX if the writing modes are different we can't easily assert that
+ // the origin is the same.
+ }
#endif
- nsRect contentArea =
- mContentArea.GetPhysicalRect(mReflowState.GetWritingMode(), mContainerWidth);
nsFlowAreaRect result =
- mFloatManager->GetFlowArea(aBCoord, nsFloatManager::WIDTH_WITHIN_HEIGHT,
- aBSize, contentArea, aState);
+ mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::WIDTH_WITHIN_HEIGHT,
+ aBSize, mContentArea, aState, mContainerWidth);
// 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",
@@ -414,46 +426,55 @@ nsBlockReflowState::AppendPushedFloat(ns
* 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 aDeltaBCoord)
{
+ WritingMode wm = mReflowState.GetWritingMode();
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) {
nsIFrame* floatFrame = fc->mFloat;
if (aDeltaBCoord != 0) {
floatFrame->MovePositionBy(nsPoint(0, aDeltaBCoord));
nsContainerFrame::PositionFrameView(floatFrame);
nsContainerFrame::PositionChildViews(floatFrame);
}
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) {
- nscoord tx, ty;
- mFloatManager->GetTranslation(tx, ty);
+ WritingMode tWM;
+ LogicalPoint tPt(tWM);
+ mFloatManager->GetTranslation(tWM, tPt);
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("RecoverFloats: txy=%d,%d (%d,%d) ",
- tx, ty, mFloatManagerX, mFloatManagerY);
+ tPt.I(tWM), tPt.B(tWM),
+ mFloatManagerOrigin.I(mFloatManagerWM),
+ mFloatManagerOrigin.B(mFloatManagerWM));
nsFrame::ListTag(stdout, floatFrame);
- nsRect region = nsFloatManager::GetRegionFor(floatFrame);
+ LogicalRect region = nsFloatManager::GetRegionFor(wm, floatFrame,
+ mContainerWidth);
printf(" aDeltaBCoord=%d region={%d,%d,%d,%d}\n",
- aDeltaBCoord, region.x, region.y, region.width, region.height);
+ aDeltaBCoord, region.IStart(wm), region.BStart(wm),
+ region.ISize(wm), region.BSize(wm));
}
#endif
mFloatManager->AddFloat(floatFrame,
- nsFloatManager::GetRegionFor(floatFrame));
+ nsFloatManager::GetRegionFor(wm, floatFrame,
+ mContainerWidth),
+ wm, mContainerWidth);
fc = fc->Next();
}
} else if (aLine->IsBlock()) {
- nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager);
+ nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager, wm,
+ mContainerWidth);
}
}
/**
* 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.
*
@@ -530,21 +551,20 @@ nsBlockReflowState::AddFloat(nsLineLayou
mBlock->mFloats.AppendFrame(mBlock, aFloat);
}
// 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);
+ WritingMode oldWM;
+ LogicalPoint oPt(oldWM);
+ mFloatManager->GetTranslation(oldWM, oPt);
+ mFloatManager->SetTranslation(mFloatManagerWM, mFloatManagerOrigin);
bool placed;
// Now place the float immediately if possible. Otherwise stash it
// away in mPendingFloats and place it later.
// 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.
@@ -572,17 +592,17 @@ nsBlockReflowState::AddFloat(nsLineLayou
// deal with this in PlaceBelowCurrentLineFloats
placed = true;
// This float will be placed after the line is done (it is a
// below-current-line float).
mBelowCurrentLineFloats.Append(mFloatCacheFreeList.Alloc(aFloat));
}
// Restore coordinate system
- mFloatManager->Translate(dx, dy);
+ mFloatManager->SetTranslation(oldWM, oPt);
return placed;
}
bool
nsBlockReflowState::CanPlaceFloat(nscoord aFloatWidth,
const nsFlowAreaRect& aFloatAvailableSpace)
{
@@ -614,34 +634,41 @@ FloatMarginWidth(const nsHTMLReflowState
true).Width(fosWM) +
aFloatOffsetState.ComputedPhysicalMargin().LeftRight() +
aFloatOffsetState.ComputedPhysicalBorderPadding().LeftRight();
}
bool
nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
{
+ WritingMode wm = mReflowState.GetWritingMode();
// Save away the Y coordinate before placing the float. We will
// restore mBCoord at the end after placing the float. This is
// necessary because any adjustments to mBCoord during the float
// placement are for the float only, not for any non-floating
// content.
AutoRestore<nscoord> restoreBCoord(mBCoord);
// FIXME: Should give AutoRestore a getter for the value to avoid this.
const nscoord saveBCoord = mBCoord;
// Grab the float's display information
const nsStyleDisplay* floatDisplay = aFloat->StyleDisplay();
// The float's old region, so we can propagate damage.
- nsRect oldRegion = nsFloatManager::GetRegionFor(aFloat);
+ LogicalRect oldRegion = nsFloatManager::GetRegionFor(wm, aFloat,
+ mContainerWidth);
// 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.
- mBCoord = std::max(mFloatManager->GetLowestFloatTop(), mBCoord);
+ // "Translate" the float manager with an offset of (0, 0) in order to
+ // set the origin to our writing mode
+ LogicalPoint oPt(wm);
+ WritingMode oldWM = mFloatManager->Translate(wm, oPt, mContainerWidth);
+ mBCoord = std::max(mFloatManager->GetLowestFloatTop(wm, mContainerWidth),
+ mBCoord);
// See if the float should clear any preceding floats...
// XXX We need to mark this float somehow so that it gets reflowed
// when floats are inserted before it.
if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
// XXXldb Does this handle vertical margins correctly?
mBCoord = ClearFloats(mBCoord, floatDisplay->mBreakType);
}
@@ -859,63 +886,72 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
}
// Update the float combined area state
// XXX Floats should really just get invalidated here if necessary
mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() + origin);
// Place the float in the float manager
// calculate region
- nsRect region = nsFloatManager::CalculateRegionFor(aFloat, floatMargin);
+ LogicalRect region =
+ nsFloatManager::CalculateRegionFor(wm, aFloat,
+ LogicalMargin(wm, floatMargin),
+ mContainerWidth);
// if the float split, then take up all of the vertical height
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
(NS_UNCONSTRAINEDSIZE != ContentBSize())) {
- region.height = std::max(region.height, ContentBSize() - floatY);
+ region.BSize(wm) = std::max(region.BSize(wm), ContentBSize() - floatY);
}
- DebugOnly<nsresult> rv =
- mFloatManager->AddFloat(aFloat, region);
+ DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
+ mContainerWidth);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "bad float placement");
// store region
- nsFloatManager::StoreRegionFor(aFloat, region);
+ nsFloatManager::StoreRegionFor(wm, aFloat, region, mContainerWidth);
// If the float's dimensions have changed, note the damage in the
// float manager.
if (!region.IsEqualEdges(oldRegion)) {
// 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.
- nscoord top = std::min(region.y, oldRegion.y);
- nscoord bottom = std::max(region.YMost(), oldRegion.YMost());
- mFloatManager->IncludeInDamage(top, bottom);
+ nscoord blockStart = std::min(region.BStart(wm), oldRegion.BStart(wm));
+ nscoord blockEnd = std::max(region.BEnd(wm), oldRegion.BEnd(wm));
+ mFloatManager->IncludeInDamage(wm, blockStart, blockEnd);
}
if (!NS_FRAME_IS_FULLY_COMPLETE(reflowStatus)) {
mBlock->SplitFloat(*this, aFloat, reflowStatus);
}
#ifdef NOISY_FLOATMANAGER
- nscoord tx, ty;
- mFloatManager->GetTranslation(tx, ty);
+ WritingMode tWM;
+ LogicalPoint tPt(wm);
+ mFloatManager->GetTranslation(tWM, tPt);
nsFrame::ListTag(stdout, mBlock);
printf(": FlowAndPlaceFloat: AddFloat: txy=%d,%d (%d,%d) {%d,%d,%d,%d}\n",
- tx, ty, mFloatManagerX, mFloatManagerY,
- region.x, region.y, region.width, region.height);
+ tPt.I(tWM), tPt.B(tWM),
+ mFloatManagerOrigin.I(mFloatManagerWM),
+ mFloatManagerOrigin.B(mFloatManagerWM),
+ region.IStart(wm), region.BStart(wm),
+ region.ISize(wm), region.BSize(wm));
#endif
#ifdef DEBUG
if (nsBlockFrame::gNoisyReflow) {
nsRect r = aFloat->GetRect();
nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
printf("placed float: ");
nsFrame::ListTag(stdout, aFloat);
printf(" %d,%d,%d,%d\n", r.x, r.y, r.width, r.height);
}
#endif
+ mFloatManager->Untranslate(oldWM, oPt, mContainerWidth);
+
return true;
}
void
nsBlockReflowState::PushFloatPastBreak(nsIFrame *aFloat)
{
// This ensures that we:
// * don't try to place later but smaller floats (which CSS says
@@ -990,17 +1026,18 @@ nsBlockReflowState::ClearFloats(nscoord
if (!mFloatManager->HasAnyFloats()) {
return aBCoord;
}
nscoord newBCoord = aBCoord;
WritingMode wm = mReflowState.GetWritingMode();
if (aBreakType != NS_STYLE_CLEAR_NONE) {
- newBCoord = mFloatManager->ClearFloats(newBCoord, aBreakType, aFlags);
+ newBCoord = mFloatManager->ClearFloats(wm, newBCoord, aBreakType,
+ mContainerWidth, aFlags);
}
if (aReplacedBlock) {
for (;;) {
nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
if (!floatAvailableSpace.mHasFloats) {
// If there aren't any floats here, then we always fit.
// We check this before calling WidthToClearPastFloats, which is
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -152,17 +152,18 @@ public:
nsFloatManager* mFloatManager;
// The coordinates within the float manager where the block is being
// placed <b>after</b> taking into account the blocks border and
// padding. This, therefore, represents the inner "content area" (in
// spacemanager coordinates) where child frames will be placed,
// including child blocks and floats.
- nscoord mFloatManagerX, mFloatManagerY;
+ mozilla::WritingMode mFloatManagerWM;
+ mozilla::LogicalPoint mFloatManagerOrigin;
// XXX get rid of this
nsReflowStatus mReflowStatus;
// The float manager state as it was before the contents of this
// block. This is needed for positioning bullets, since we only want
// to move the bullet to flow around floats that were before this
// block, not floats inside of it.
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1168,18 +1168,21 @@ nsContainerFrame::ReflowOverflowContaine
}
NS_MergeReflowStatusInto(&aStatus, frameStatus);
// At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
// but we have some unsplittable frames that, when taller than
// availableHeight will push zero-height content into a next-in-flow.
}
else {
tracker.Skip(frame, aStatus);
- if (aReflowState.mFloatManager)
- nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
+ if (aReflowState.mFloatManager) {
+ nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager,
+ aReflowState.GetWritingMode(),
+ aReflowState.ComputedWidth());
+ }
}
ConsiderChildOverflow(aOverflowRects, frame);
}
}
void
nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -32,18 +32,20 @@ static void
PSArenaFreeCB(size_t aSize, void* aPtr, void* aClosure)
{
static_cast<nsIPresShell*>(aClosure)->FreeMisc(aSize, aPtr);
}
/////////////////////////////////////////////////////////////////////////////
// nsFloatManager
-nsFloatManager::nsFloatManager(nsIPresShell* aPresShell)
- : mX(0), mY(0),
+nsFloatManager::nsFloatManager(nsIPresShell* aPresShell,
+ mozilla::WritingMode aWM)
+ : mWritingMode(aWM),
+ mOrigin(aWM),
mFloatDamage(PSArenaAllocCB, PSArenaFreeCB, aPresShell),
mPushedLeftFloatPastBreak(false),
mPushedRightFloatPastBreak(false),
mSplitLeftFloatAcrossBreak(false),
mSplitRightFloatAcrossBreak(false)
{
MOZ_COUNT_CTOR(nsFloatManager);
}
@@ -105,224 +107,251 @@ void nsFloatManager::Shutdown()
nsMemory::Free(floatManager);
}
// Disable further caching.
sCachedFloatManagerCount = -1;
}
nsFlowAreaRect
-nsFloatManager::GetFlowArea(nscoord aYOffset, BandInfoType aInfoType,
- nscoord aHeight, nsRect aContentArea,
- SavedState* aState) const
+nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBOffset,
+ BandInfoType aInfoType, nscoord aBSize,
+ LogicalRect aContentArea, SavedState* aState,
+ nscoord aContainerWidth) const
{
- NS_ASSERTION(aHeight >= 0, "unexpected max height");
- NS_ASSERTION(aContentArea.width >= 0, "unexpected content area width");
+ NS_ASSERTION(aBSize >= 0, "unexpected max block size");
+ NS_ASSERTION(aContentArea.ISize(aWM) >= 0,
+ "unexpected content area inline size");
- nscoord top = aYOffset + mY;
- if (top < nscoord_MIN) {
+ LogicalPoint origin = mOrigin.ConvertTo(aWM, mWritingMode, aContainerWidth);
+ nscoord blockStart = aBOffset + origin.B(aWM);
+ if (blockStart < nscoord_MIN) {
NS_WARNING("bad value");
- top = nscoord_MIN;
+ blockStart = nscoord_MIN;
}
// Determine the last float that we should consider.
uint32_t floatCount;
if (aState) {
// Use the provided state.
floatCount = aState->mFloatInfoCount;
NS_ABORT_IF_FALSE(floatCount <= mFloats.Length(), "bad state");
} else {
// Use our current state.
floatCount = mFloats.Length();
}
// If there are no floats at all, or we're below the last one, return
// quickly.
if (floatCount == 0 ||
- (mFloats[floatCount-1].mLeftYMost <= top &&
- mFloats[floatCount-1].mRightYMost <= top)) {
- return nsFlowAreaRect(aContentArea.x, aYOffset, aContentArea.width,
- aHeight, false);
+ (mFloats[floatCount-1].mLeftBEnd <= blockStart &&
+ mFloats[floatCount-1].mRightBEnd <= blockStart)) {
+ //XXX temporary!
+ LogicalRect rect(aWM, aContentArea.IStart(aWM), aBOffset,
+ aContentArea.ISize(aWM), aBSize);
+ nsRect phys = rect.GetPhysicalRect(aWM, aContainerWidth);
+ return nsFlowAreaRect(phys.x, phys.y, phys.width, phys.height, false);
}
- nscoord bottom;
- if (aHeight == nscoord_MAX) {
+ nscoord blockEnd;
+ if (aBSize == nscoord_MAX) {
// This warning (and the two below) are possible to hit on pages
// with really large objects.
NS_WARN_IF_FALSE(aInfoType == BAND_FROM_POINT,
"bad height");
- bottom = nscoord_MAX;
+ blockEnd = nscoord_MAX;
} else {
- bottom = top + aHeight;
- if (bottom < top || bottom > nscoord_MAX) {
+ blockEnd = blockStart + aBSize;
+ if (blockEnd < blockStart || blockEnd > nscoord_MAX) {
NS_WARNING("bad value");
- bottom = nscoord_MAX;
+ blockEnd = nscoord_MAX;
}
}
- nscoord left = mX + aContentArea.x;
- nscoord right = mX + aContentArea.XMost();
- if (right < left) {
+ nscoord inlineStart = origin.I(aWM) + aContentArea.IStart(aWM);
+ nscoord inlineEnd = origin.I(aWM) + aContentArea.IEnd(aWM);
+ if (inlineEnd < inlineStart) {
NS_WARNING("bad value");
- right = left;
+ inlineEnd = inlineStart;
}
// Walk backwards through the floats until we either hit the front of
- // the list or we're above |top|.
+ // the list or we're above |blockStart|.
bool haveFloats = false;
for (uint32_t i = floatCount; i > 0; --i) {
const FloatInfo &fi = mFloats[i-1];
- if (fi.mLeftYMost <= top && fi.mRightYMost <= top) {
+ if (fi.mLeftBEnd <= blockStart && fi.mRightBEnd <= blockStart) {
// There aren't any more floats that could intersect this band.
break;
}
if (fi.mRect.IsEmpty()) {
// For compatibility, ignore floats with empty rects, even though it
// disagrees with the spec. (We might want to fix this in the
// future, though.)
continue;
}
- nscoord floatTop = fi.mRect.y, floatBottom = fi.mRect.YMost();
- if (top < floatTop && aInfoType == BAND_FROM_POINT) {
+
+ LogicalRect rect = fi.mRect.ConvertTo(aWM, fi.mWritingMode,
+ aContainerWidth);
+ nscoord floatBStart = rect.BStart(aWM);
+ nscoord floatBEnd = rect.BEnd(aWM);
+ if (blockStart < floatBStart && aInfoType == BAND_FROM_POINT) {
// This float is below our band. Shrink our band's height if needed.
- if (floatTop < bottom) {
- bottom = floatTop;
+ if (floatBStart < blockEnd) {
+ blockEnd = floatBStart;
}
}
- // If top == bottom (which happens only with WIDTH_WITHIN_HEIGHT),
+ // If blockStart == blockEnd (which happens only with WIDTH_WITHIN_HEIGHT),
// we include floats that begin at our 0-height vertical area. We
// need to to this to satisfy the invariant that a
// WIDTH_WITHIN_HEIGHT call is at least as narrow on both sides as a
- // BAND_WITHIN_POINT call beginning at its top.
- else if (top < floatBottom &&
- (floatTop < bottom || (floatTop == bottom && top == bottom))) {
+ // BAND_WITHIN_POINT call beginning at its blockStart.
+ else if (blockStart < floatBEnd &&
+ (floatBStart < blockEnd ||
+ (floatBStart == blockEnd && blockStart == blockEnd))) {
// This float is in our band.
// Shrink our band's height if needed.
- if (floatBottom < bottom && aInfoType == BAND_FROM_POINT) {
- bottom = floatBottom;
+ if (floatBEnd < blockEnd && aInfoType == BAND_FROM_POINT) {
+ blockEnd = floatBEnd;
}
// Shrink our band's width if needed.
- if (fi.mFrame->StyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) {
- // A left float.
- nscoord rightEdge = fi.mRect.XMost();
- if (rightEdge > left) {
- left = rightEdge;
+ if ((fi.mFrame->StyleDisplay()->mFloats == NS_STYLE_FLOAT_LEFT) ==
+ aWM.IsBidiLTR()) {
+ // A left float in an ltr block or a right float in an rtl block
+ nscoord inlineEndEdge = rect.IEnd(aWM);
+ if (inlineEndEdge > inlineStart) {
+ inlineStart = inlineEndEdge;
// Only set haveFloats to true if the float is inside our
// containing block. This matches the spec for what some
// callers want and disagrees for other callers, so we should
// probably provide better information at some point.
haveFloats = true;
}
} else {
- // A right float.
- nscoord leftEdge = fi.mRect.x;
- if (leftEdge < right) {
- right = leftEdge;
+ // A left float in an rtl block or a right float in an ltr block
+ nscoord inlineStartEdge = rect.IStart(aWM);
+ if (inlineStartEdge < inlineEnd) {
+ inlineEnd = inlineStartEdge;
// See above.
haveFloats = true;
}
}
}
}
- nscoord height = (bottom == nscoord_MAX) ? nscoord_MAX : (bottom - top);
- return nsFlowAreaRect(left - mX, top - mY, right - left, height, haveFloats);
+ nscoord height = (blockEnd == nscoord_MAX) ?
+ nscoord_MAX : (blockEnd - blockStart);
+ //XXX temporary!
+ LogicalRect rect(aWM,
+ inlineStart - origin.I(aWM), blockStart - origin.B(aWM),
+ inlineEnd - inlineStart, height);
+ nsRect phys = rect.GetPhysicalRect(aWM, aContainerWidth);
+ return nsFlowAreaRect(phys.x, phys.y, phys.width, phys.height, haveFloats);
}
nsresult
-nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect)
+nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const LogicalRect& aMarginRect,
+ WritingMode aWM, nscoord aContainerWidth)
{
- NS_ASSERTION(aMarginRect.width >= 0, "negative width!");
- NS_ASSERTION(aMarginRect.height >= 0, "negative height!");
+ NS_ASSERTION(aMarginRect.ISize(aWM) >= 0, "negative inline size!");
+ NS_ASSERTION(aMarginRect.BSize(aWM) >= 0, "negative block size!");
- FloatInfo info(aFloatFrame, aMarginRect + nsPoint(mX, mY));
+ FloatInfo info(aFloatFrame, aWM, aMarginRect + mOrigin);
- // Set mLeftYMost and mRightYMost.
+ // Set mLeftBEnd and mRightBEnd.
if (HasAnyFloats()) {
FloatInfo &tail = mFloats[mFloats.Length() - 1];
- info.mLeftYMost = tail.mLeftYMost;
- info.mRightYMost = tail.mRightYMost;
+ info.mLeftBEnd = tail.mLeftBEnd;
+ info.mRightBEnd = tail.mRightBEnd;
} else {
- info.mLeftYMost = nscoord_MIN;
- info.mRightYMost = nscoord_MIN;
+ info.mLeftBEnd = nscoord_MIN;
+ info.mRightBEnd = nscoord_MIN;
}
uint8_t floatStyle = aFloatFrame->StyleDisplay()->mFloats;
NS_ASSERTION(floatStyle == NS_STYLE_FLOAT_LEFT ||
floatStyle == NS_STYLE_FLOAT_RIGHT, "unexpected float");
- nscoord& sideYMost = (floatStyle == NS_STYLE_FLOAT_LEFT) ? info.mLeftYMost
- : info.mRightYMost;
- nscoord thisYMost = info.mRect.YMost();
- if (thisYMost > sideYMost)
- sideYMost = thisYMost;
+ nscoord& sideBEnd =
+ ((floatStyle == NS_STYLE_FLOAT_LEFT) == aWM.IsBidiLTR()) ? info.mLeftBEnd
+ : info.mRightBEnd;
+ nscoord thisBEnd = info.mRect.BEnd(aWM);
+ if (thisBEnd > sideBEnd)
+ sideBEnd = thisBEnd;
if (!mFloats.AppendElement(info))
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
-nsRect
-nsFloatManager::CalculateRegionFor(nsIFrame* aFloat,
- const nsMargin& aMargin)
+LogicalRect
+nsFloatManager::CalculateRegionFor(WritingMode aWM,
+ nsIFrame* aFloat,
+ const LogicalMargin& aMargin,
+ nscoord aContainerWidth)
{
// We consider relatively positioned frames at their original position.
- nsRect region(aFloat->GetNormalPosition(), aFloat->GetSize());
+ LogicalRect region(aWM, nsRect(aFloat->GetNormalPosition(),
+ aFloat->GetSize()),
+ aContainerWidth);
// Float region includes its margin
- region.Inflate(aMargin);
+ region.Inflate(aWM, aMargin);
// Don't store rectangles with negative margin-box width or height in
// the float manager; it can't deal with them.
- if (region.width < 0) {
+ if (region.ISize(aWM) < 0) {
// Preserve the right margin-edge for left floats and the left
// margin-edge for right floats
const nsStyleDisplay* display = aFloat->StyleDisplay();
- if (NS_STYLE_FLOAT_LEFT == display->mFloats) {
- region.x = region.XMost();
+ if ((NS_STYLE_FLOAT_LEFT == display->mFloats) == aWM.IsBidiLTR()) {
+ region.IStart(aWM) = region.IEnd(aWM);
}
- region.width = 0;
+ region.ISize(aWM) = 0;
}
- if (region.height < 0) {
- region.height = 0;
+ if (region.BSize(aWM) < 0) {
+ region.BSize(aWM) = 0;
}
return region;
}
NS_DECLARE_FRAME_PROPERTY(FloatRegionProperty, nsIFrame::DestroyMargin)
-nsRect
-nsFloatManager::GetRegionFor(nsIFrame* aFloat)
+LogicalRect
+nsFloatManager::GetRegionFor(WritingMode aWM, nsIFrame* aFloat,
+ nscoord aContainerWidth)
{
- nsRect region = aFloat->GetRect();
+ LogicalRect region = aFloat->GetLogicalRect(aWM, aContainerWidth);
void* storedRegion = aFloat->Properties().Get(FloatRegionProperty());
if (storedRegion) {
nsMargin margin = *static_cast<nsMargin*>(storedRegion);
- region.Inflate(margin);
+ region.Inflate(aWM, LogicalMargin(aWM, margin));
}
return region;
}
void
-nsFloatManager::StoreRegionFor(nsIFrame* aFloat,
- nsRect& aRegion)
+nsFloatManager::StoreRegionFor(WritingMode aWM, nsIFrame* aFloat,
+ const LogicalRect& aRegion,
+ nscoord aContainerWidth)
{
+ nsRect region = aRegion.GetPhysicalRect(aWM, aContainerWidth);
nsRect rect = aFloat->GetRect();
FrameProperties props = aFloat->Properties();
- if (aRegion.IsEqualEdges(rect)) {
+ if (region.IsEqualEdges(rect)) {
props.Delete(FloatRegionProperty());
}
else {
nsMargin* storedMargin = static_cast<nsMargin*>
(props.Get(FloatRegionProperty()));
if (!storedMargin) {
storedMargin = new nsMargin();
props.Set(FloatRegionProperty(), storedMargin);
}
- *storedMargin = aRegion - rect;
+ *storedMargin = region - rect;
}
}
nsresult
nsFloatManager::RemoveTrailingRegions(nsIFrame* aFrameList)
{
if (!aFrameList) {
return NS_OK;
@@ -373,52 +402,57 @@ nsFloatManager::PushState(SavedState* aS
// It should also be noted that the state for mFloatDamage is
// intentionally not saved or restored in PushState() and PopState(),
// since that could lead to bugs where damage is missed/dropped when
// we move from position A to B (during the intermediate incremental
// reflow mentioned above) and then from B to C during the subsequent
// reflow. In the typical case A and C will be the same, but not always.
// Allowing mFloatDamage to accumulate the damage incurred during both
// reflows ensures that nothing gets missed.
- aState->mX = mX;
- aState->mY = mY;
+ aState->mWritingMode = mWritingMode;
+ aState->mOrigin = mOrigin;
aState->mPushedLeftFloatPastBreak = mPushedLeftFloatPastBreak;
aState->mPushedRightFloatPastBreak = mPushedRightFloatPastBreak;
aState->mSplitLeftFloatAcrossBreak = mSplitLeftFloatAcrossBreak;
aState->mSplitRightFloatAcrossBreak = mSplitRightFloatAcrossBreak;
aState->mFloatInfoCount = mFloats.Length();
}
void
nsFloatManager::PopState(SavedState* aState)
{
NS_PRECONDITION(aState, "No state to restore?");
- mX = aState->mX;
- mY = aState->mY;
+ mWritingMode = aState->mWritingMode;
+ mOrigin = aState->mOrigin;
mPushedLeftFloatPastBreak = aState->mPushedLeftFloatPastBreak;
mPushedRightFloatPastBreak = aState->mPushedRightFloatPastBreak;
mSplitLeftFloatAcrossBreak = aState->mSplitLeftFloatAcrossBreak;
mSplitRightFloatAcrossBreak = aState->mSplitRightFloatAcrossBreak;
NS_ASSERTION(aState->mFloatInfoCount <= mFloats.Length(),
"somebody misused PushState/PopState");
mFloats.TruncateLength(aState->mFloatInfoCount);
}
nscoord
-nsFloatManager::GetLowestFloatTop() const
+nsFloatManager::GetLowestFloatTop(WritingMode aWM,
+ nscoord aContainerWidth) const
{
if (mPushedLeftFloatPastBreak || mPushedRightFloatPastBreak) {
return nscoord_MAX;
}
if (!HasAnyFloats()) {
return nscoord_MIN;
}
- return mFloats[mFloats.Length() - 1].mRect.y - mY;
+ FloatInfo fi = mFloats[mFloats.Length() - 1];
+ LogicalRect rect = fi.mRect.ConvertTo(aWM, fi.mWritingMode, aContainerWidth);
+ LogicalPoint origin = mOrigin.ConvertTo(aWM, mWritingMode, aContainerWidth);
+
+ return rect.BStart(aWM) - origin.B(aWM);
}
#ifdef DEBUG_FRAME_DUMP
void
DebugListFloatManager(const nsFloatManager *aFloatManager)
{
aFloatManager->List(stdout);
}
@@ -428,84 +462,93 @@ nsFloatManager::List(FILE* out) const
{
if (!HasAnyFloats())
return NS_OK;
for (uint32_t i = 0; i < mFloats.Length(); ++i) {
const FloatInfo &fi = mFloats[i];
fprintf_stderr(out, "Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
i, static_cast<void*>(fi.mFrame),
- fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
- fi.mLeftYMost, fi.mRightYMost);
+ fi.mRect.IStart(fi.mWritingMode),
+ fi.mRect.BStart(fi.mWritingMode),
+ fi.mRect.ISize(fi.mWritingMode),
+ fi.mRect.BSize(fi.mWritingMode),
+ fi.mLeftBEnd, fi.mRightBEnd);
}
return NS_OK;
}
#endif
nscoord
-nsFloatManager::ClearFloats(nscoord aY, uint8_t aBreakType,
+nsFloatManager::ClearFloats(WritingMode aWM, nscoord aBCoord,
+ uint8_t aBreakType, nscoord aContainerWidth,
uint32_t aFlags) const
{
if (!(aFlags & DONT_CLEAR_PUSHED_FLOATS) && ClearContinues(aBreakType)) {
return nscoord_MAX;
}
if (!HasAnyFloats()) {
- return aY;
+ return aBCoord;
}
- nscoord bottom = aY + mY;
+ LogicalPoint origin = mOrigin.ConvertTo(aWM, mWritingMode, aContainerWidth);
+ nscoord blockEnd = aBCoord + origin.B(aWM);
const FloatInfo &tail = mFloats[mFloats.Length() - 1];
switch (aBreakType) {
case NS_STYLE_CLEAR_BOTH:
- bottom = std::max(bottom, tail.mLeftYMost);
- bottom = std::max(bottom, tail.mRightYMost);
+ blockEnd = std::max(blockEnd, tail.mLeftBEnd);
+ blockEnd = std::max(blockEnd, tail.mRightBEnd);
break;
case NS_STYLE_CLEAR_LEFT:
- bottom = std::max(bottom, tail.mLeftYMost);
+ blockEnd = std::max(blockEnd, aWM.IsBidiLTR() ? tail.mLeftBEnd
+ : tail.mRightBEnd);
break;
case NS_STYLE_CLEAR_RIGHT:
- bottom = std::max(bottom, tail.mRightYMost);
+ blockEnd = std::max(blockEnd, aWM.IsBidiLTR() ? tail.mRightBEnd
+ : tail.mLeftBEnd);
break;
default:
// Do nothing
break;
}
- bottom -= mY;
+ blockEnd -= origin.B(aWM);
- return bottom;
+ return blockEnd;
}
bool
nsFloatManager::ClearContinues(uint8_t aBreakType) const
{
return ((mPushedLeftFloatPastBreak || mSplitLeftFloatAcrossBreak) &&
(aBreakType == NS_STYLE_CLEAR_BOTH ||
aBreakType == NS_STYLE_CLEAR_LEFT)) ||
((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
(aBreakType == NS_STYLE_CLEAR_BOTH ||
aBreakType == NS_STYLE_CLEAR_RIGHT));
}
/////////////////////////////////////////////////////////////////////////////
// FloatInfo
-nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, const nsRect& aRect)
- : mFrame(aFrame), mRect(aRect)
+nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame, WritingMode aWM,
+ const LogicalRect& aRect)
+ : mFrame(aFrame), mRect(aRect), mWritingMode(aWM)
{
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsFloatManager::FloatInfo::FloatInfo(const FloatInfo& aOther)
: mFrame(aOther.mFrame),
mRect(aOther.mRect),
- mLeftYMost(aOther.mLeftYMost),
- mRightYMost(aOther.mRightYMost)
+ mWritingMode(aOther.mWritingMode),
+ mLeftBEnd(aOther.mLeftBEnd),
+ mRightBEnd(aOther.mRightBEnd)
{
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
}
nsFloatManager::FloatInfo::~FloatInfo()
{
MOZ_COUNT_DTOR(nsFloatManager::FloatInfo);
}
@@ -536,17 +579,18 @@ nsAutoFloatManager::~nsAutoFloatManager(
}
nsresult
nsAutoFloatManager::CreateFloatManager(nsPresContext *aPresContext)
{
// Create a new float manager and install it in the reflow
// state. `Remember' the old float manager so we can restore it
// later.
- mNew = new nsFloatManager(aPresContext->PresShell());
+ mNew = new nsFloatManager(aPresContext->PresShell(),
+ mReflowState.GetWritingMode());
if (! mNew)
return NS_ERROR_OUT_OF_MEMORY;
#ifdef NOISY_FLOATMANAGER
printf("constructed new float manager %p (replacing %p)\n",
mNew, mReflowState.mFloatManager);
#endif
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -8,155 +8,207 @@
#ifndef nsFloatManager_h_
#define nsFloatManager_h_
#include "mozilla/Attributes.h"
#include "nsIntervalSet.h"
#include "nsCoord.h"
-#include "nsRect.h"
+#include "WritingModes.h"
#include "nsTArray.h"
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
class nsIPresShell;
class nsIFrame;
struct nsHTMLReflowState;
class nsPresContext;
/**
* The available space for content not occupied by floats is divided
- * into a (vertical) sequence of rectangles. However, we need to know
- * not only the rectangle, but also whether it was reduced (from the
- * content rectangle) by floats that actually intruded into the content
- * rectangle.
+ * into a sequence of rectangles in the block direction. However, we
+ * need to know not only the rectangle, but also whether it was reduced
+ * (from the content rectangle) by floats that actually intruded into
+ * the content rectangle.
*/
struct nsFlowAreaRect {
nsRect mRect;
bool mHasFloats;
- nsFlowAreaRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
+ nsFlowAreaRect(nscoord aICoord, nscoord aBCoord,
+ nscoord aISize, nscoord aBSize,
bool aHasFloats)
- : mRect(aX, aY, aWidth, aHeight), mHasFloats(aHasFloats) {}
+ : mRect(aICoord, aBCoord, aISize, aBSize), mHasFloats(aHasFloats) {}
};
#define NS_FLOAT_MANAGER_CACHE_SIZE 4
class nsFloatManager {
public:
- explicit nsFloatManager(nsIPresShell* aPresShell);
+ explicit nsFloatManager(nsIPresShell* aPresShell, mozilla::WritingMode aWM);
~nsFloatManager();
void* operator new(size_t aSize) CPP_THROW_NEW;
void operator delete(void* aPtr, size_t aSize);
static void Shutdown();
/**
* Get float region stored on the frame. (Defaults to mRect if it's
* not there.) The float region is the area impacted by this float;
* the coordinates are relative to the containing block frame.
*/
- static nsRect GetRegionFor(nsIFrame* aFloatFrame);
+ static mozilla::LogicalRect GetRegionFor(mozilla::WritingMode aWM,
+ nsIFrame* aFloatFrame,
+ nscoord aContainerWidth);
/**
* Calculate the float region for this frame using aMargin and the
* frame's mRect. The region includes the margins around the float,
* but doesn't include the relative offsets.
* Note that if the frame is or has a continuation, aMargin's top
* and/or bottom must be zeroed by the caller.
*/
- static nsRect CalculateRegionFor(nsIFrame* aFloatFrame,
- const nsMargin& aMargin);
+ static mozilla::LogicalRect CalculateRegionFor(
+ mozilla::WritingMode aWM,
+ nsIFrame* aFloatFrame,
+ const mozilla::LogicalMargin& aMargin,
+ nscoord aContainerWidth);
/**
* Store the float region on the frame. The region is stored
* as a delta against the mRect, so repositioning the frame will
* also reposition the float region.
*/
- static void StoreRegionFor(nsIFrame* aFloat, nsRect& aRegion);
+ static void StoreRegionFor(mozilla::WritingMode aWM,
+ nsIFrame* aFloat,
+ const mozilla::LogicalRect& aRegion,
+ nscoord aContainerWidth);
// Structure that stores the current state of a frame manager for
// Save/Restore purposes.
- struct SavedState;
- friend struct SavedState;
struct SavedState {
+ SavedState(mozilla::WritingMode aWM)
+ : mWritingMode(aWM)
+ , mOrigin(aWM)
+ {}
private:
uint32_t mFloatInfoCount;
- nscoord mX, mY;
+ mozilla::WritingMode mWritingMode;
+ mozilla::LogicalPoint mOrigin;
bool mPushedLeftFloatPastBreak;
bool mPushedRightFloatPastBreak;
bool mSplitLeftFloatAcrossBreak;
bool mSplitRightFloatAcrossBreak;
friend class nsFloatManager;
};
/**
- * Translate the current origin by the specified (dx, dy). This
+ * Translate the current origin by the specified (dICoord, dBCoord). This
* creates a new local coordinate space relative to the current
* coordinate space.
+ * @returns previous writing mode
*/
- void Translate(nscoord aDx, nscoord aDy) { mX += aDx; mY += aDy; }
+ mozilla::WritingMode Translate(mozilla::WritingMode aWM,
+ mozilla::LogicalPoint aDOrigin,
+ nscoord aContainerWidth)
+ {
+ mozilla::WritingMode oldWM = mWritingMode;
+ mOrigin = mOrigin.ConvertTo(aWM, oldWM, aContainerWidth);
+ mWritingMode = aWM;
+ mOrigin += aDOrigin;
+ return oldWM;
+ }
+
+ /*
+ * Set the translation origin to a specified value instead of
+ * translating by a delta.
+ */
+ void SetTranslation(mozilla::WritingMode aWM,
+ mozilla::LogicalPoint aOrigin)
+ {
+ mWritingMode = aWM;
+ mOrigin = aOrigin;
+ }
+
+ void Untranslate(mozilla::WritingMode aWM,
+ mozilla::LogicalPoint aDOrigin,
+ nscoord aContainerWidth)
+ {
+ mOrigin -= aDOrigin;
+ mOrigin = mOrigin.ConvertTo(aWM, mWritingMode, aContainerWidth);
+ mWritingMode = aWM;
+ }
/**
* Returns the current translation from local coordinate space to
* world coordinate space. This represents the accumulated calls to
* Translate().
*/
- void GetTranslation(nscoord& aX, nscoord& aY) const { aX = mX; aY = mY; }
+ void GetTranslation(mozilla::WritingMode& aWM,
+ mozilla::LogicalPoint& aOrigin) const
+ {
+ aWM = mWritingMode;
+ aOrigin = mOrigin;
+ }
/**
* Get information about the area available to content that flows
* around floats. Two different types of space can be requested:
- * BAND_FROM_POINT: returns the band containing vertical coordinate
- * |aY| (though actually with the top truncated to begin at aY),
- * but up to at most |aHeight| (which may be nscoord_MAX).
- * This will return the tallest rectangle whose top is |aY| and in
- * which there are no changes in what floats are on the sides of
- * that rectangle, but will limit the height of the rectangle to
- * |aHeight|. The left and right edges of the rectangle give the
- * area available for line boxes in that space. The width of this
- * resulting rectangle will not be negative.
- * WIDTH_WITHIN_HEIGHT: This returns a rectangle whose top is aY and
- * whose height is exactly aHeight. Its left and right edges give
- * the left and right edges of the space that can be used for line
- * boxes *throughout* that space. (It is possible that more
- * horizontal space could be used in part of the space if a float
- * begins or ends in it.) The width of the resulting rectangle
- * can be negative.
+ * BAND_FROM_POINT: returns the band containing block-dir coordinate
+ * |aBCoord| (though actually with the top truncated to begin at
+ * aBCoord), but up to at most |aBSize| (which may be nscoord_MAX).
+ * This will return the tallest rectangle whose block start is
+ * |aBCoord| and in which there are no changes in what floats are
+ * on the sides of that rectangle, but will limit the block size
+ * of the rectangle to |aBSize|. The inline start and end edges
+ * of the rectangle give the area available for line boxes in that
+ * space. The inline size of this resulting rectangle will not be
+ * negative.
+ * WIDTH_WITHIN_HEIGHT: This returns a rectangle whose block start
+ * is aBCoord and whose block size is exactly aBSize. Its inline
+ * start and end edges give the corresponding edges of the space
+ * that can be used for line boxes *throughout* that space. (It
+ * is possible that more inline space could be used in part of the
+ * space if a float begins or ends in it.) The inline size of the
+ * resulting rectangle can be negative.
*
- * @param aY [in] vertical coordinate for top of available space
- * desired
- * @param aHeight [in] see above
+ * @param aBCoord [in] block-dir coordinate for block start of
+ * available space desired
+ * @param aBSize [in] see above
* @param aContentArea [in] an nsRect representing the content area
* @param aState [in] If null, use the current state, otherwise, do
* computation based only on floats present in the given
* saved state.
* @return An nsFlowAreaRect whose:
* mRect is the resulting rectangle for line boxes. It will not
- * extend beyond aContentArea's horizontal bounds, but may be
+ * extend beyond aContentArea's inline bounds, but may be
* narrower when floats are present.
* mBandHasFloats is whether there are floats at the sides of the
* return value including those that do not reduce the line box
- * width at all (because they are entirely in the margins)
+ * inline size at all (because they are entirely in the margins)
*
- * aY and aAvailSpace are positioned relative to the current translation
+ * aBCoord and aAvailSpace are positioned relative to the current translation
*/
enum BandInfoType { BAND_FROM_POINT, WIDTH_WITHIN_HEIGHT };
- nsFlowAreaRect GetFlowArea(nscoord aY, BandInfoType aInfoType,
- nscoord aHeight, nsRect aContentArea,
- SavedState* aState) const;
+ nsFlowAreaRect GetFlowArea(mozilla::WritingMode aWM,
+ nscoord aBCoord, BandInfoType aInfoType,
+ nscoord aBSize, mozilla::LogicalRect aContentArea,
+ SavedState* aState, nscoord mContainerWidth) const;
/**
- * Add a float that comes after all floats previously added. Its top
- * must be even with or below the top of all previous floats.
+ * Add a float that comes after all floats previously added. Its
+ * block start must be even with or below the top of all previous
+ * floats.
*
* aMarginRect is relative to the current translation. The caller
* must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
*/
- nsresult AddFloat(nsIFrame* aFloatFrame, const nsRect& aMarginRect);
+ nsresult AddFloat(nsIFrame* aFloatFrame,
+ const mozilla::LogicalRect& aMarginRect,
+ mozilla::WritingMode aWM, nscoord aContainerWidth);
/**
* Notify that we tried to place a float that could not fit at all and
* had to be pushed to the next page/column? (If so, we can't place
* any more floats in this page/column because of the rule that the
* top of a float cannot be above the top of an earlier float. It
* also means that any clear needs to continue to the next column.)
*/
@@ -195,24 +247,28 @@ public:
* Methods for dealing with the propagation of float damage during
* reflow.
*/
bool HasFloatDamage() const
{
return !mFloatDamage.IsEmpty();
}
- void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
+ void IncludeInDamage(mozilla::WritingMode aWM,
+ nscoord aIntervalBegin, nscoord aIntervalEnd)
{
- mFloatDamage.IncludeInterval(aIntervalBegin + mY, aIntervalEnd + mY);
+ mFloatDamage.IncludeInterval(aIntervalBegin + mOrigin.B(aWM),
+ aIntervalEnd + mOrigin.B(aWM));
}
- bool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd) const
+ bool IntersectsDamage(mozilla::WritingMode aWM,
+ nscoord aIntervalBegin, nscoord aIntervalEnd) const
{
- return mFloatDamage.Intersects(aIntervalBegin + mY, aIntervalEnd + mY);
+ return mFloatDamage.Intersects(aIntervalBegin + mOrigin.B(aWM),
+ aIntervalEnd + mOrigin.B(aWM));
}
/**
* Saves the current state of the float manager into aState.
*/
void PushState(SavedState* aState);
/**
@@ -223,46 +279,51 @@ public:
* be used once --- although it can be omitted; saved states can be ignored.
* States must be popped in the reverse order they were pushed. A
* call to PopState invalidates any saved states Pushed after the
* state passed to PopState was pushed.
*/
void PopState(SavedState* aState);
/**
- * Get the top of the last float placed into the float manager, to
- * enforce the rule that a float can't be above an earlier float.
- * Returns the minimum nscoord value if there are no floats.
+ * Get the block start of the last float placed into the float
+ * manager, to enforce the rule that a float can't be above an earlier
+ * float. Returns the minimum nscoord value if there are no floats.
*
* The result is relative to the current translation.
*/
- nscoord GetLowestFloatTop() const;
+ nscoord GetLowestFloatTop(mozilla::WritingMode aWM,
+ nscoord aContainerWidth) const;
/**
- * Return the coordinate of the lowest float matching aBreakType in this
- * float manager. Returns aY if there are no matching floats.
+ * Return the coordinate of the lowest float matching aBreakType in
+ * this float manager. Returns aBCoord if there are no matching
+ * floats.
*
- * Both aY and the result are relative to the current translation.
+ * Both aBCoord and the result are relative to the current translation.
*/
enum {
// Tell ClearFloats not to push to nscoord_MAX when floats have been
// pushed to the next page/column.
DONT_CLEAR_PUSHED_FLOATS = (1<<0)
};
- nscoord ClearFloats(nscoord aY, uint8_t aBreakType, uint32_t aFlags = 0) const;
+ nscoord ClearFloats(mozilla::WritingMode aWM, nscoord aBCoord,
+ uint8_t aBreakType, nscoord aContainerWidth,
+ uint32_t aFlags = 0) const;
/**
* Checks if clear would pass into the floats' BFC's next-in-flow,
* i.e. whether floats affecting this clear have continuations.
*/
bool ClearContinues(uint8_t aBreakType) const;
void AssertStateMatches(SavedState *aState) const
{
- NS_ASSERTION(aState->mX == mX && aState->mY == mY &&
+ NS_ASSERTION(aState->mWritingMode == mWritingMode &&
+ aState->mOrigin == mOrigin &&
aState->mPushedLeftFloatPastBreak ==
mPushedLeftFloatPastBreak &&
aState->mPushedRightFloatPastBreak ==
mPushedRightFloatPastBreak &&
aState->mSplitLeftFloatAcrossBreak ==
mSplitLeftFloatAcrossBreak &&
aState->mSplitRightFloatAcrossBreak ==
mSplitRightFloatAcrossBreak &&
@@ -276,28 +337,34 @@ public:
*/
nsresult List(FILE* out) const;
#endif
private:
struct FloatInfo {
nsIFrame *const mFrame;
- nsRect mRect;
- // The lowest bottoms of left/right floats up to and including this one.
- nscoord mLeftYMost, mRightYMost;
+ mozilla::LogicalRect mRect;
+ mozilla::WritingMode mWritingMode;
+ // The lowest block-ends of left/right floats up to and including
+ // this one.
+ nscoord mLeftBEnd, mRightBEnd;
- FloatInfo(nsIFrame* aFrame, const nsRect& aRect);
+ FloatInfo(nsIFrame* aFrame, mozilla::WritingMode aWM,
+ const mozilla::LogicalRect& aRect);
#ifdef NS_BUILD_REFCNT_LOGGING
FloatInfo(const FloatInfo& aOther);
~FloatInfo();
#endif
};
- nscoord mX, mY; // translation from local to global coordinate space
+ mozilla::WritingMode mWritingMode;
+ mozilla::LogicalPoint mOrigin; // translation from local to global
+ // coordinate space
+
nsTArray<FloatInfo> mFloats;
nsIntervalSet mFloatDamage;
// Did we try to place a float that could not fit at all and had to be
// pushed to the next page/column? If so, we can't place any more
// floats in this page/column because of the rule that the top of a
// float cannot be above the top of an earlier float. And we also
// need to apply this information to 'clear', and thus need to
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -836,20 +836,18 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
aFrame->WillReflow(mPresContext);
// Adjust spacemanager coordinate system for the frame.
nsHTMLReflowMetrics metrics(lineWM);
#ifdef DEBUG
metrics.ISize(lineWM) = nscoord(0xdeadbeef);
metrics.BSize(lineWM) = nscoord(0xdeadbeef);
#endif
- nsRect physicalBounds = pfd->mBounds.GetPhysicalRect(lineWM, mContainerWidth);
- nscoord tx = physicalBounds.x;
- nscoord ty = physicalBounds.y;
- mFloatManager->Translate(tx, ty);
+ LogicalPoint tPt = pfd->mBounds.Origin(lineWM);
+ WritingMode oldWM = mFloatManager->Translate(lineWM, tPt, mContainerWidth);
int32_t savedOptionalBreakOffset;
gfxBreakPriority savedOptionalBreakPriority;
nsIContent* savedOptionalBreakContent =
GetLastOptionalBreakPosition(&savedOptionalBreakOffset,
&savedOptionalBreakPriority);
if (!isText) {
@@ -924,17 +922,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
if (pfd->mSpan) {
isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
} else {
isEmpty = pfd->mFrame->IsEmpty();
}
}
}
- mFloatManager->Translate(-tx, -ty);
+ mFloatManager->Untranslate(oldWM, tPt, mContainerWidth);
NS_ASSERTION(metrics.ISize(lineWM) >= 0, "bad inline size");
NS_ASSERTION(metrics.BSize(lineWM) >= 0,"bad block size");
if (metrics.ISize(lineWM) < 0) {
metrics.ISize(lineWM) = 0;
}
if (metrics.BSize(lineWM) < 0) {
metrics.BSize(lineWM) = 0;