diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index ace7029c4bca..8ad1e61ab2aa 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -3816,6 +3816,16 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, // Split line, but after the frame just reflowed rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling(), aLineReflowStatus); NS_ENSURE_SUCCESS(rv, rv); + + if (NS_INLINE_IS_BREAK_AFTER(frameReflowStatus) && + !aLineLayout.GetLineEndsInBR()) { + // Mark next line dirty in case SplitLine didn't end up + // pushing any frames. + nsLineList_iterator next = aLine.next(); + if (next != end_lines() && !next->IsBlock()) { + next->MarkDirty(); + } + } } } } @@ -3850,6 +3860,13 @@ nsBlockFrame::ReflowInlineFrame(nsBlockReflowState& aState, *aLineReflowStatus = LINE_REFLOW_STOP; rv = SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling(), aLineReflowStatus); NS_ENSURE_SUCCESS(rv, rv); + + // Mark next line dirty in case SplitLine didn't end up + // pushing any frames. + nsLineList_iterator next = aLine.next(); + if (next != end_lines() && !next->IsBlock()) { + next->MarkDirty(); + } } } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 88287041ec6d..2221349ee219 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -177,7 +177,7 @@ public: NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval); // Update offsets to account for new length. This may clear mTextRun. - void SetLength(PRInt32 aLength, nsLineLayout* aLineLayout); + void SetLength(PRInt32 aLength); NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const; diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 92346c3a5b3d..12f9636b0c44 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -221,8 +221,8 @@ struct TextRunMappedFlow { /** * This is our user data for the textrun, when textRun->GetFlags() does not - * have TEXT_IS_SIMPLE_FLOW set. When TEXT_IS_SIMPLE_FLOW is set, there is - * just one flow, the textrun's user data pointer is a pointer to mStartFrame + * have TEXT_SIMPLE_FLOW set. When TEXT_SIMPLE_FLOW is set, there is just one + * flow, the textrun's user data pointer is a pointer to mStartFrame * for that flow, mDOMOffsetToBeforeTransformOffset is zero, and mContentLength * is the length of the text node. */ @@ -3779,73 +3779,53 @@ nsTextFrame::ClearTextRun() } } +static void +ClearTextRunsInFlowChain(nsTextFrame* aFrame) +{ + nsTextFrame* f; + for (f = aFrame; f; f = static_cast(f->GetNextInFlow())) { + f->ClearTextRun(); + } +} + NS_IMETHODIMP nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) { - // Find the first frame whose text has changed. Frames that are entirely - // before the text change are completely unaffected. - nsTextFrame* next; - nsTextFrame* textFrame = this; - while (PR_TRUE) { - next = static_cast(textFrame->GetNextContinuation()); - if (!next || next->GetContentOffset() > PRInt32(aInfo->mChangeStart)) - break; - textFrame = next; - } + ClearTextRunsInFlowChain(this); - PRInt32 endOfChangedText = aInfo->mChangeStart + aInfo->mReplaceLength; - nsTextFrame* lastDirtiedFrame = nsnull; + nsTextFrame* targetTextFrame; + PRInt32 nodeLength = mContent->GetText()->GetLength(); - nsIPresShell* shell = PresContext()->GetPresShell(); - do { - // textFrame contained deleted text (or the insertion point, - // if this was a pure insertion). - textFrame->mState &= ~TEXT_WHITESPACE_FLAGS; - textFrame->ClearTextRun(); - if (!lastDirtiedFrame || - lastDirtiedFrame->GetParent() != textFrame->GetParent()) { - // Ask the parent frame to reflow me. - shell->FrameNeedsReflow(textFrame, nsIPresShell::eStyleChange, - NS_FRAME_IS_DIRTY); - lastDirtiedFrame = textFrame; - } else { - // if the parent is a block, we're cheating here because we should - // be marking our line dirty, but we're not. nsTextFrame::SetLength - // will do that when it gets called during reflow. - textFrame->AddStateBits(NS_FRAME_IS_DIRTY); - } - - // Below, frames that start after the deleted text will be adjusted so that - // their offsets move with the trailing unchanged text. If this change - // deletes more text than it inserts, those frame offsets will decrease. - // We need to maintain the invariant that mContentOffset is non-decreasing - // along the continuation chain. So we need to ensure that frames that - // started in the deleted text are all still starting before the - // unchanged text. - if (textFrame->mContentOffset > endOfChangedText) { - textFrame->mContentOffset = endOfChangedText; - } - - textFrame = static_cast(textFrame->GetNextContinuation()); - } while (textFrame && textFrame->GetContentOffset() < PRInt32(aInfo->mChangeEnd)); - - // This is how much the length of the string changed by --- i.e., - // how much the trailing unchanged text moved. - PRInt32 sizeChange = - aInfo->mChangeStart + aInfo->mReplaceLength - aInfo->mChangeEnd; - - if (sizeChange) { - // Fix the offsets of the text frames that start in the trailing - // unchanged text. - while (textFrame) { - textFrame->mContentOffset += sizeChange; - // XXX we could rescue some text runs by adjusting their user data - // to reflect the change in DOM offsets - textFrame->ClearTextRun(); + if (aInfo->mAppend) { + targetTextFrame = static_cast(GetLastContinuation()); + targetTextFrame->mState &= ~TEXT_WHITESPACE_FLAGS; + } else { + // Mark all the continuation frames as dirty, and fix up content offsets to + // be valid. + // Don't set NS_FRAME_IS_DIRTY on |this|, since we call FrameNeedsReflow + // below. + nsTextFrame* textFrame = this; + PRInt32 newLength = nodeLength; + do { + textFrame->mState &= ~TEXT_WHITESPACE_FLAGS; + // If the text node has shrunk, clip the frame contentlength as necessary + if (textFrame->mContentOffset > newLength) { + textFrame->mContentOffset = newLength; + } textFrame = static_cast(textFrame->GetNextContinuation()); - } + if (!textFrame) { + break; + } + textFrame->mState |= NS_FRAME_IS_DIRTY; + } while (1); + targetTextFrame = this; } + // Ask the parent frame to reflow me. + PresContext()->GetPresShell()->FrameNeedsReflow(targetTextFrame, + nsIPresShell::eStyleChange, + NS_FRAME_IS_DIRTY); + return NS_OK; } @@ -5918,33 +5898,13 @@ HasSoftHyphenBefore(const nsTextFragment* aFrag, gfxTextRun* aTextRun, } void -nsTextFrame::SetLength(PRInt32 aLength, nsLineLayout* aLineLayout) +nsTextFrame::SetLength(PRInt32 aLength) { mContentLengthHint = aLength; PRInt32 end = GetContentOffset() + aLength; nsTextFrame* f = static_cast(GetNextInFlow()); if (!f) return; - - // If our end offset is moving, then even if frames are not being pushed or - // pulled, content is moving to or from the next line and the next line - // must be reflowed. - // If the next-continuation is dirty, then we should dirty the next line now - // because we may have skipped doing it if we dirtied it in - // CharacterDataChanged. This is ugly but teaching FrameNeedsReflow - // and ChildIsDirty to handle a range of frames would be worse. - if (aLineLayout && - (end != f->mContentOffset || (f->GetStateBits() & NS_FRAME_IS_DIRTY))) { - const nsLineList::iterator* line = aLineLayout->GetLine(); - nsBlockFrame* block = do_QueryFrame(aLineLayout->GetLineContainerFrame()); - if (line && block) { - nsLineList::iterator next = line->next(); - if (next != block->end_lines() && !next->IsBlock()) { - next->MarkDirty(); - } - } - } - if (end < f->mContentOffset) { // Our frame is shrinking. Give the text to our next in flow. f->mContentOffset = end; @@ -5954,12 +5914,8 @@ nsTextFrame::SetLength(PRInt32 aLength, nsLineLayout* aLineLayout) } return; } - // Our frame is growing. Take text from our in-flow(s). - // We can take text from frames in lines beyond just the next line. - // We don't dirty those lines. That's OK, because when we reflow - // our empty next-in-flow, it will take text from its next-in-flow and - // dirty that line. while (f && f->mContentOffset < end) { + // Our frame is growing. Take text from our in-flow. f->mContentOffset = end; if (f->GetTextRun() != mTextRun) { ClearTextRun(); @@ -5967,7 +5923,6 @@ nsTextFrame::SetLength(PRInt32 aLength, nsLineLayout* aLineLayout) } f = static_cast(f->GetNextInFlow()); } - #ifdef DEBUG f = this; PRInt32 iterations = 0; @@ -6091,7 +6046,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // Layout dependent styles are a problem because we need to reconstruct // the gfxTextRun based on our layout. if (lineLayout.GetInFirstLetter() || lineLayout.GetInFirstLine()) { - SetLength(maxContentLength, &lineLayout); + SetLength(maxContentLength); if (lineLayout.GetInFirstLetter()) { // floating first-letter boundaries are significant in textrun @@ -6133,7 +6088,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // Change this frame's length to the first-letter length right now // so that when we rebuild the textrun it will be built with the // right first-letter boundary - SetLength(offset + length - GetContentOffset(), &lineLayout); + SetLength(offset + length - GetContentOffset()); // Ensure that the textrun will be rebuilt ClearTextRun(); } @@ -6430,9 +6385,10 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, charsFit - numJustifiableCharacters); } - SetLength(contentLength, &lineLayout); + SetLength(contentLength); if (mContent->HasFlag(NS_TEXT_IN_SELECTION)) { + // XXXroc Watch out, this could be slow!!! Speed up GetSelectionDetails? SelectionDetails* details = GetSelectionDetails(); if (details) { AddStateBits(NS_FRAME_SELECTED_CONTENT); @@ -6863,7 +6819,7 @@ nsTextFrame::AdjustOffsetsForBidi(PRInt32 aStart, PRInt32 aEnd) } mContentOffset = aStart; - SetLength(aEnd - aStart, nsnull); + SetLength(aEnd - aStart); } /** diff --git a/layout/reftests/text/line-editing-1-ref.html b/layout/reftests/text/line-editing-1-ref.html deleted file mode 100644 index a8b064edbe4a..000000000000 --- a/layout/reftests/text/line-editing-1-ref.html +++ /dev/null @@ -1,14 +0,0 @@ - - - -Line 1 -Line 2 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7 -Line 8 -Line 9 - - diff --git a/layout/reftests/text/line-editing-1a.html b/layout/reftests/text/line-editing-1a.html deleted file mode 100644 index 88e809700d64..000000000000 --- a/layout/reftests/text/line-editing-1a.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - -Line 1 -Line 2 -Line 2 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7 -Line X -Line 9 - - diff --git a/layout/reftests/text/line-editing-1b.html b/layout/reftests/text/line-editing-1b.html deleted file mode 100644 index 7ff1dd1452c6..000000000000 --- a/layout/reftests/text/line-editing-1b.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - -Line 1 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7 -Line X -Line 9 - - diff --git a/layout/reftests/text/line-editing-1c.html b/layout/reftests/text/line-editing-1c.html deleted file mode 100644 index 81ebe8142b41..000000000000 --- a/layout/reftests/text/line-editing-1c.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - -Line 1 -Line 2 -Line 3 -Line 4 -Line 5 -Line 6 -Line 7 -Line X -Line 9 - - diff --git a/layout/reftests/text/line-editing-1d.html b/layout/reftests/text/line-editing-1d.html deleted file mode 100644 index c2b4583db93d..000000000000 --- a/layout/reftests/text/line-editing-1d.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -Line 1 -Line 2 -Line 3 -Line 4 -Line X -Line X -Line X -Line 7 -Line 8 -Line 9 - - diff --git a/layout/reftests/text/line-editing-1e.html b/layout/reftests/text/line-editing-1e.html deleted file mode 100644 index 86fd4e1f2777..000000000000 --- a/layout/reftests/text/line-editing-1e.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - -Line 1 -Line 2 -Line 3 -Line 4 -Line X -Line 7 -Line 8 -Line 9 - - diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index 85bca7c16a70..8185e1d35014 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -12,11 +12,6 @@ random-if(MOZ_WIDGET_TOOLKIT!="cocoa") == font-size-adjust-02.html font-size-adj == justification-1.html justification-1-ref.html == justification-2a.html justification-2-ref.html == justification-2b.html justification-2-ref.html -== line-editing-1a.html line-editing-1-ref.html -== line-editing-1b.html line-editing-1-ref.html -== line-editing-1c.html line-editing-1-ref.html -== line-editing-1d.html line-editing-1-ref.html -== line-editing-1e.html line-editing-1-ref.html == long-1.html long-ref.html == pre-line-1.html pre-line-1-ref.html == pre-line-2.html pre-line-2-ref.html