/* * 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 |mPrevBEndMargin| when we reflowed that line in * a full reflow (under the rule in CSS2 that all adjacent vertical * margins of blocks collapse). */ void nsBlockReflowState::ReconstructMarginBefore(nsLineList::iterator aLine) { mPrevBEndMargin.Zero(); nsBlockFrame *block = mBlock; nsLineList::iterator firstLine = block->begin_lines(); for (;;) { --aLine; if (aLine->IsBlock()) { mPrevBEndMargin = aLine->GetCarriedOutBEndMargin(); 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_ISBSTARTMARGINROOT)) { mPrevBEndMargin.Zero(); } break; } } }
bool nsLineBox::RFindLineContaining(nsIFrame* aFrame, const nsLineList::iterator& aBegin, nsLineList::iterator& aEnd, nsIFrame* aLastFrameBeforeEnd, PRInt32* aFrameIndexInLine) { NS_PRECONDITION(aFrame, "null ptr"); nsIFrame* curFrame = aLastFrameBeforeEnd; while (aBegin != aEnd) { --aEnd; NS_ASSERTION(aEnd->LastChild() == curFrame, "Unexpected curFrame"); if (NS_UNLIKELY(aEnd->mFlags.mHasHashedFrames) && !aEnd->Contains(aFrame)) { if (aEnd->mFirstChild) { curFrame = aEnd->mFirstChild->GetPrevSibling(); } continue; } // i is the index of curFrame in aEnd PRInt32 i = aEnd->GetChildCount() - 1; while (i >= 0) { if (curFrame == aFrame) { *aFrameIndexInLine = i; return true; } --i; curFrame = curFrame->GetPrevSibling(); } MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames, "Contains lied to us!"); } *aFrameIndexInLine = -1; return false; }
/** * 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; // Place floats for this line into the space manager if (aLine->HasFloats() || aLine->IsBlock()) { // Undo border/padding translation since the nsFloatCache's // coordinates are relative to the frame not relative to the // border/padding. const nsMargin& bp = BorderPadding(); mSpaceManager->Translate(-bp.left, -bp.top); RecoverFloats(aLine, aDeltaY); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) { mSpaceManager->List(stdout); } #endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } }
PRBool nsLineBox::RFindLineContaining(nsIFrame* aFrame, const nsLineList::iterator& aBegin, nsLineList::iterator& aEnd, nsIFrame* aLastFrameBeforeEnd, PRInt32* aFrameIndexInLine) { NS_PRECONDITION(aFrame, "null ptr"); nsIFrame* curFrame = aLastFrameBeforeEnd; while (aBegin != aEnd) { --aEnd; NS_ASSERTION(aEnd->IsLastChild(curFrame), "Unexpected curFrame"); // i is the index of curFrame in aEnd PRInt32 i = aEnd->GetChildCount() - 1; while (i >= 0) { if (curFrame == aFrame) { *aFrameIndexInLine = i; return PR_TRUE; } --i; curFrame = curFrame->GetPrevSibling(); } } *aFrameIndexInLine = -1; return PR_FALSE; }
/* * 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 |mPrevBEndMargin| when we reflowed that line in * a full reflow (under the rule in CSS2 that all adjacent vertical * margins of blocks collapse). */ void BlockReflowInput::ReconstructMarginBefore(nsLineList::iterator aLine) { mPrevBEndMargin.Zero(); nsBlockFrame *block = mBlock; nsLineList::iterator firstLine = block->LinesBegin(); for (;;) { --aLine; if (aLine->IsBlock()) { mPrevBEndMargin = aLine->GetCarriedOutBEndMargin(); 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 (!mFlags.mIsBStartMarginRoot) { mPrevBEndMargin.Zero(); } break; } } }
/** * 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 |aDeltaBCoord| * 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 aDeltaBCoord) { // Make the line being recovered the current line mCurrentLine = aLine; // Place floats for this line into the float manager if (aLine->HasFloats() || aLine->IsBlock()) { RecoverFloats(aLine, aDeltaBCoord); #ifdef DEBUG if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) { mFloatManager->List(stdout); } #endif } }
/** * Restore information about floats into the float manager for an * incremental reflow, and simultaneously push the floats by * |aDeltaBCoord|, 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 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 tI, tB; mFloatManager->GetTranslation(tI, tB); nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); printf("RecoverFloats: tIB=%d,%d (%d,%d) ", tI, tB, mFloatManagerI, mFloatManagerB); nsFrame::ListTag(stdout, floatFrame); LogicalRect region = nsFloatManager::GetRegionFor(wm, floatFrame, ContainerSize()); printf(" aDeltaBCoord=%d region={%d,%d,%d,%d}\n", aDeltaBCoord, region.IStart(wm), region.BStart(wm), region.ISize(wm), region.BSize(wm)); } #endif mFloatManager->AddFloat(floatFrame, nsFloatManager::GetRegionFor(wm, floatFrame, ContainerSize()), wm, ContainerSize()); fc = fc->Next(); } } else if (aLine->IsBlock()) { nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager, wm, ContainerSize()); } }
/** * Restore information about floats into the float manager for an * 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) { nsIFrame* floatFrame = fc->mFloat; if (aDeltaY != 0) { nsPoint p = floatFrame->GetPosition(); floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY)); nsContainerFrame::PositionFrameView(floatFrame); nsContainerFrame::PositionChildViews(floatFrame); } #ifdef DEBUG if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisyFloatManager) { nscoord tx, ty; mFloatManager->GetTranslation(tx, ty); nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); printf("RecoverFloats: txy=%d,%d (%d,%d) ", tx, ty, mFloatManagerX, mFloatManagerY); nsFrame::ListTag(stdout, floatFrame); nsRect region = nsFloatManager::GetRegionFor(floatFrame); printf(" aDeltaY=%d region={%d,%d,%d,%d}\n", aDeltaY, region.x, region.y, region.width, region.height); } #endif mFloatManager->AddFloat(floatFrame, nsFloatManager::GetRegionFor(floatFrame)); fc = fc->Next(); } } else if (aLine->IsBlock()) { nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager); } }
/** * Restore information about floats into the space manager for an * 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) { nsIFrame* floatFrame = fc->mPlaceholder->GetOutOfFlowFrame(); if (aDeltaY != 0) { fc->mRegion.y += aDeltaY; nsPoint p = floatFrame->GetPosition(); floatFrame->SetPosition(nsPoint(p.x, p.y + aDeltaY)); nsContainerFrame::PositionFrameView(floatFrame); nsContainerFrame::PositionChildViews(floatFrame); } #ifdef DEBUG if (nsBlockFrame::gNoisyReflow || nsBlockFrame::gNoisySpaceManager) { nscoord tx, ty; mSpaceManager->GetTranslation(tx, ty); nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent); printf("RecoverFloats: txy=%d,%d (%d,%d) ", tx, ty, mSpaceManagerX, mSpaceManagerY); nsFrame::ListTag(stdout, floatFrame); printf(" aDeltaY=%d region={%d,%d,%d,%d}\n", aDeltaY, fc->mRegion.x, fc->mRegion.y, fc->mRegion.width, fc->mRegion.height); } #endif mSpaceManager->AddRectRegion(floatFrame, fc->mRegion); fc = fc->Next(); } } else if (aLine->IsBlock()) { nsBlockFrame *kid = nsnull; aLine->mFirstChild->QueryInterface(kBlockFrameCID, (void**)&kid); // 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 (kid && !nsBlockFrame::BlockNeedsSpaceManager(kid)) { nscoord tx = kid->mRect.x, ty = kid->mRect.y; // If the element is relatively positioned, then adjust x and y // accordingly so that we consider relatively positioned frames // at their original position. if (NS_STYLE_POSITION_RELATIVE == kid->GetStyleDisplay()->mPosition) { nsPoint *offsets = static_cast<nsPoint*> (mPresContext->PropertyTable()->GetProperty(kid, nsGkAtoms::computedOffsetProperty)); if (offsets) { tx -= offsets->x; ty -= offsets->y; } } mSpaceManager->Translate(tx, ty); for (nsBlockFrame::line_iterator line = kid->begin_lines(), line_end = kid->end_lines(); line != line_end; ++line) // Pass 0, not the real DeltaY, since these floats aren't // moving relative to their parent block, only relative to // the space manager. RecoverFloats(line, 0); mSpaceManager->Translate(-tx, -ty); } } }