nsIFrame* nsInlineFrame::PullOneFrame(nsPresContext* aPresContext, InlineReflowState& irs, PRBool* aIsComplete) { PRBool isComplete = PR_TRUE; nsIFrame* frame = nsnull; nsInlineFrame* nextInFlow = irs.mNextInFlow; while (nsnull != nextInFlow) { frame = nextInFlow->mFrames.FirstChild(); if (!frame) { // If the principal childlist has no frames, then try moving the overflow // frames to it. nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames()); if (overflowFrames) { nextInFlow->mFrames.SetFrames(*overflowFrames); frame = nextInFlow->mFrames.FirstChild(); } } if (nsnull != frame) { // If our block has no next continuation, then any floats belonging to // the pulled frame must belong to our block already. This check ensures // we do no extra work in the common non-vertical-breaking case. if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) { // The blockChildren.ContainsFrame check performed by // ReparentFloatsForInlineChild will be fast because frame's ancestor // will be the first child of its containing block. ReparentFloatsForInlineChild(irs.mLineContainer, frame, PR_FALSE); } nextInFlow->mFrames.RemoveFirstChild(); // If we removed the last frame from the principal child list then move // any overflow frames to it. if (!nextInFlow->mFrames.FirstChild()) { nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames()); if (overflowFrames) { nextInFlow->mFrames.SetFrames(*overflowFrames); } } mFrames.InsertFrame(this, irs.mPrevFrame, frame); isComplete = PR_FALSE; if (irs.mLineLayout) { irs.mLineLayout->SetDirtyNextLine(); } nsHTMLContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this); break; } nextInFlow = (nsInlineFrame*) nextInFlow->GetNextInFlow(); irs.mNextInFlow = nextInFlow; } *aIsComplete = isComplete; return frame; }
NS_IMETHODIMP nsFirstLineFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { if (nsnull == aReflowState.mLineLayout) { return NS_ERROR_INVALID_ARG; } nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame(); // Check for an overflow list with our prev-in-flow nsFirstLineFrame* prevInFlow = (nsFirstLineFrame*)GetPrevInFlow(); if (nsnull != prevInFlow) { nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames()); if (prevOverflowFrames) { // Assign all floats to our block if necessary if (lineContainer && lineContainer->GetPrevContinuation()) { ReparentFloatsForInlineChild(lineContainer, prevOverflowFrames->FirstChild(), PR_TRUE); } const nsFrameList::Slice& newFrames = mFrames.InsertFrames(this, nsnull, *prevOverflowFrames); ReParentChildListStyle(aPresContext, newFrames, this); } } // It's also possible that we have an overflow list for ourselves nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames()); if (overflowFrames) { NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); const nsFrameList::Slice& newFrames = mFrames.AppendFrames(nsnull, *overflowFrames); ReParentChildListStyle(aPresContext, newFrames, this); } // Set our own reflow state (additional state above and beyond // aReflowState) InlineReflowState irs; irs.mPrevFrame = nsnull; irs.mLineContainer = lineContainer; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); nsresult rv; PRBool wasEmpty = mFrames.IsEmpty(); if (wasEmpty) { // Try to pull over one frame before starting so that we know // whether we have an anonymous block or not. PRBool complete; PullOneFrame(aPresContext, irs, &complete); } if (nsnull == GetPrevInFlow()) { // XXX This is pretty sick, but what we do here is to pull-up, in // advance, all of the next-in-flows children. We re-resolve their // style while we are at at it so that when we reflow they have // the right style. // // All of this is so that text-runs reflow properly. irs.mPrevFrame = mFrames.LastChild(); for (;;) { PRBool complete; nsIFrame* frame = PullOneFrame(aPresContext, irs, &complete); if (!frame) { break; } irs.mPrevFrame = frame; } irs.mPrevFrame = nsnull; } else { // XXX do this in the Init method instead // For continuations, we need to check and see if our style // context is right. If its the same as the first-in-flow, then // we need to fix it up (that way :first-line style doesn't leak // into this continuation since we aren't the first line). nsFirstLineFrame* first = (nsFirstLineFrame*) GetFirstInFlow(); if (mStyleContext == first->mStyleContext) { // Fixup our style context and our children. First get the // proper parent context. nsStyleContext* parentContext = first->GetParent()->GetStyleContext(); if (parentContext) { // Create a new style context that is a child of the parent // style context thus removing the :first-line style. This way // we behave as if an anonymous (unstyled) span was the child // of the parent frame. nsRefPtr<nsStyleContext> newSC; newSC = aPresContext->StyleSet()-> ResolvePseudoStyleFor(nsnull, nsCSSAnonBoxes::mozLineFrame, parentContext); if (newSC) { // Switch to the new style context. SetStyleContext(newSC); // Re-resolve all children ReParentChildListStyle(aPresContext, mFrames, this); } } } } NS_ASSERTION(!aReflowState.mLineLayout->GetInFirstLine(), "Nested first-line frames? BOGUS"); aReflowState.mLineLayout->SetInFirstLine(PR_TRUE); rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); aReflowState.mLineLayout->SetInFirstLine(PR_FALSE); // Note: the line layout code will properly compute our overflow state for us return rv; }
NS_IMETHODIMP nsInlineFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsInlineFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); if (nsnull == aReflowState.mLineLayout) { return NS_ERROR_INVALID_ARG; } PRBool lazilySetParentPointer = PR_FALSE; nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame(); // Check for an overflow list with our prev-in-flow nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow(); if (nsnull != prevInFlow) { nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames()); if (prevOverflowFrames) { // When pushing and pulling frames we need to check for whether any // views need to be reparented. nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, *prevOverflowFrames, prevInFlow, this); // Check if we should do the lazilySetParentPointer optimization. // Only do it in simple cases where we're being reflowed for the // first time, nothing (e.g. bidi resolution) has already given // us children, and there's no next-in-flow, so all our frames // will be taken from prevOverflowFrames. if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) && mFrames.IsEmpty() && !GetNextInFlow()) { // If our child list is empty, just put the new frames into it. // Note that we don't set the parent pointer for the new frames. Instead wait // to do this until we actually reflow the frame. If the overflow list contains // thousands of frames this is a big performance issue (see bug #5588) mFrames.SetFrames(*prevOverflowFrames); lazilySetParentPointer = PR_TRUE; } else { // Assign all floats to our block if necessary if (lineContainer && lineContainer->GetPrevContinuation()) { ReparentFloatsForInlineChild(lineContainer, prevOverflowFrames->FirstChild(), PR_TRUE); } // Insert the new frames at the beginning of the child list // and set their parent pointer mFrames.InsertFrames(this, nsnull, *prevOverflowFrames); } } } // It's also possible that we have an overflow list for ourselves #ifdef DEBUG if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { // If it's our initial reflow, then we should not have an overflow list. // However, add an assertion in case we get reflowed more than once with // the initial reflow reason nsFrameList* overflowFrames = GetOverflowFrames(); NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(), "overflow list is not empty for initial reflow"); } #endif if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames()); if (overflowFrames) { NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); // Because we lazily set the parent pointer of child frames we get from // our prev-in-flow's overflow list, it's possible that we have not set // the parent pointer for these frames. mFrames.AppendFrames(this, *overflowFrames); } } if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) { return NS_OK; } // Set our own reflow state (additional state above and beyond // aReflowState) InlineReflowState irs; irs.mPrevFrame = nsnull; irs.mLineContainer = lineContainer; irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow(); irs.mSetParentPointer = lazilySetParentPointer; nsresult rv; if (mFrames.IsEmpty()) { // Try to pull over one frame before starting so that we know // whether we have an anonymous block or not. PRBool complete; (void) PullOneFrame(aPresContext, irs, &complete); } rv = ReflowFrames(aPresContext, aReflowState, irs, aMetrics, aStatus); // Note: the line layout code will properly compute our // overflow-rect state for us. NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return rv; }