diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index bf25ff565fe..ffe043488df 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -883,16 +883,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top; mSpaceManager->Translate(tx, ty); -#ifdef IBMBIDI - PRInt32 start, end; - - if (mPresContext->BidiEnabled()) { - if (aFrame->GetStateBits() & NS_FRAME_IS_BIDI) { - aFrame->GetOffsets(start, end); - } - } -#endif // IBMBIDI - nsIAtom* frameType = aFrame->GetType(); PRInt32 savedOptionalBreakOffset; nsIContent* savedOptionalBreakContent = @@ -1086,24 +1076,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, printf(" status=%x\n", aReflowStatus); #endif - if (aFrame->GetStateBits() & NS_FRAME_IS_BIDI) { - // Since aReflowStatus may change, check it at the end - if (NS_INLINE_IS_BREAK_BEFORE(aReflowStatus) ) { - aFrame->AdjustOffsetsForBidi(start, end); - } - else if (!NS_FRAME_IS_COMPLETE(aReflowStatus) ) { - PRInt32 newEnd; - aFrame->GetOffsets(start, newEnd); - if (newEnd != end) { - nsIFrame* nextInFlow = aFrame->GetNextInFlow(); - if (nextInFlow) { - nextInFlow->GetOffsets(start, end); - nextInFlow->AdjustOffsetsForBidi(newEnd, end); - } // nextInFlow - } // newEnd != end - } // !NS_FRAME_IS_COMPLETE(aReflowStatus) - } // isBidiFrame - return rv; } diff --git a/mozilla/layout/generic/nsTextFrameThebes.cpp b/mozilla/layout/generic/nsTextFrameThebes.cpp index bf119a54d1a..5dd7aa671aa 100644 --- a/mozilla/layout/generic/nsTextFrameThebes.cpp +++ b/mozilla/layout/generic/nsTextFrameThebes.cpp @@ -139,16 +139,10 @@ // This bit is set on frames that trimmed trailing whitespace characters when // calculating their width during reflow. #define TEXT_TRIMMED_TRAILING_WHITESPACE 0x01000000 -// Set when the frame's text may have a different style from its in-flow -// brethren (e.g. the frame is in first-letter or first-line), so text runs -// may need to be reconstructed when the frame's content offset/length changes. -// We set this on the frame that has in first-letter or first-line, but not -// in-flow siblings outside first-letter or first-line. -#define TEXT_RUN_LAYOUT_DEPENDENT 0x02000000 #define TEXT_REFLOW_FLAGS \ (TEXT_FIRST_LETTER|TEXT_START_OF_LINE|TEXT_END_OF_LINE|TEXT_HYPHEN_BREAK| \ - TEXT_TRIMMED_TRAILING_WHITESPACE|TEXT_RUN_LAYOUT_DEPENDENT) + TEXT_TRIMMED_TRAILING_WHITESPACE) // Cache bits for IsEmpty(). // Set this bit if the textframe is known to be only collapsible whitespace. @@ -308,7 +302,6 @@ public: nsTextFrame(nsStyleContext* aContext) : nsFrame(aContext) { NS_ASSERTION(mContentOffset == 0, "Bogus content offset"); - NS_ASSERTION(mContentLength == 0, "Bogus content length"); } // nsIFrame @@ -401,6 +394,9 @@ 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); + NS_IMETHOD GetOffsets(PRInt32 &start, PRInt32 &end)const; virtual void AdjustOffsetsForBidi(PRInt32 start, PRInt32 end); @@ -507,8 +503,12 @@ public: #endif PRInt32 GetContentOffset() const { return mContentOffset; } - PRInt32 GetContentLength() const { return mContentLength; } - PRInt32 GetContentEnd() const { return mContentOffset + mContentLength; } + PRInt32 GetContentLength() const { return GetContentEnd() - mContentOffset; } + PRInt32 GetContentEnd() const; + // This returns the length the frame thinks it *should* have after it was + // last reflowed (0 if it hasn't been reflowed yet). This should be used only + // when setting up the text offsets for a new continuation frame. + PRInt32 GetContentLengthHint() const { return mContentLengthHint; } // Compute the length of the content mapped by this frame // and all its in-flow siblings. Basically this means starting at mContentOffset @@ -554,8 +554,20 @@ protected: virtual ~nsTextFrame(); nsIFrame* mNextContinuation; + // The key invariant here is that mContentOffset never decreases along + // a next-continuation chain. And of course mContentOffset is always <= the + // the text node's content length, and the mContentOffset for the first frame + // is always 0. Furthermore the text mapped by a frame is determined by + // GetContentOffset() and GetContentLength()/GetContentEnd(), which get + // the length from the difference between this frame's offset and the next + // frame's offset, or the text length if there is no next frame. This means + // the frames always map the text node without overlapping or leaving any gaps. PRInt32 mContentOffset; - PRInt32 mContentLength; + // This does *not* indicate the length of text currently mapped by the frame; + // instead it's a hint saying that this frame *wants* to map this much text + // so if we create a new continuation, this is where that continuation should + // start. + PRInt32 mContentLengthHint; nscoord mAscent; gfxTextRun* mTextRun; @@ -566,8 +578,6 @@ protected: PRBool isRTLChars, PRBool isOddLevel, PRBool isBidiSystem); - - void SetOffsets(PRInt32 start, PRInt32 end); }; static void @@ -712,6 +722,11 @@ nsTextFrameTextRunCache::Shutdown() { gTextRuns = nsnull; } +PRInt32 nsTextFrame::GetContentEnd() const { + nsTextFrame* next = static_cast(GetNextContinuation()); + return next ? next->GetContentOffset() : mContent->GetText()->GetLength(); +} + PRInt32 nsTextFrame::GetInFlowContentLength() { #ifdef IBMBIDI nsTextFrame* nextBidi = nsnull; @@ -1345,12 +1360,9 @@ void BuildTextRunsScanner::ScanFrame(nsIFrame* aFrame) !HasTerminalNewline(mLastFrame)) { nsTextFrame* frame = static_cast(aFrame); mappedFlow->mEndFrame = static_cast(frame->GetNextInFlow()); - // Frames in the same flow can overlap at least temporarily - // (e.g. when first-line builds its textrun, we need to have it suck - // up all the in-flow content because we don't know how long the line - // is going to be). - mappedFlow->mContentEndOffset = - PR_MAX(mappedFlow->mContentEndOffset, frame->GetContentEnd()); + NS_ASSERTION(mappedFlow->mContentEndOffset == frame->GetContentOffset(), + "Overlapping or discontiguous frames => BAD"); + mappedFlow->mContentEndOffset = frame->GetContentEnd(); if (mCurrentFramesAllSameTextRun != frame->GetTextRun()) { mCurrentFramesAllSameTextRun = nsnull; } @@ -1572,10 +1584,8 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) PRInt32 contentLength = contentEnd - contentStart; if (content == lastContent) { - NS_ASSERTION(endOfLastContent >= contentStart, - "Gap in textframes mapping content?!"); - // Text frames can overlap (see comment in ScanFrame below) - contentStart = PR_MAX(contentStart, endOfLastContent); + NS_ASSERTION(endOfLastContent == contentStart, + "Gap or overlap in textframes mapping content?!"); if (contentStart >= contentEnd) continue; userData->mMappedFlows[finalMappedFlowCount - 1].mContentLength += contentLength; @@ -2040,7 +2050,7 @@ nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag, { NS_ASSERTION(mTextRun, "Need textrun here"); - TrimmedOffsets offsets = { mContentOffset, mContentLength }; + TrimmedOffsets offsets = { GetContentOffset(), GetContentLength() }; const nsStyleText* textStyle = GetStyleText(); if (textStyle->WhiteSpaceIsSignificant()) return offsets; @@ -3204,13 +3214,9 @@ nsTextFrame::Init(nsIContent* aContent, NS_ASSERTION(!aPrevInFlow, "Can't be a continuation!"); NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT), "Bogus content!"); - nsresult rv = nsFrame::Init(aContent, aParent, aPrevInFlow); - // Note that if we're created due to bidi splitting the bidi code - // will override what we compute here, so it's ok. // We're not a continuing frame. // mContentOffset = 0; not necessary since we get zeroed out at init - mContentLength = GetInFlowContentLength(); - return rv; + return nsFrame::Init(aContent, aParent, aPrevInFlow); } void @@ -3293,8 +3299,14 @@ nsContinuingTextFrame::Init(nsIContent* aContent, SetPrevInFlow(aPrevInFlow); aPrevInFlow->SetNextInFlow(this); nsTextFrame* prev = static_cast(aPrevInFlow); - mTextRun = prev->GetTextRun(); - mContentOffset = prev->GetContentEnd(); + mContentOffset = prev->GetContentOffset() + prev->GetContentLengthHint(); + if (prev->GetStyleContext() != GetStyleContext()) { + // We're taking part of prev's text, and its style may be different + // so clear its textrun which may no longer be valid (and don't set ours) + prev->ClearTextRun(); + } else { + mTextRun = prev->GetTextRun(); + } #ifdef IBMBIDI if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) { PRInt32 start, end; @@ -3314,7 +3326,6 @@ nsContinuingTextFrame::Init(nsIContent* aContent, SetNextContinuation(nextContinuation); nextContinuation->SetPrevContinuation(this); nextContinuation->GetOffsets(start, end); - mContentLength = PR_MAX(1, start - mContentOffset); } mState |= NS_FRAME_IS_BIDI; } // prev frame is bidi @@ -3545,15 +3556,13 @@ nsTextFrame::CharacterDataChanged(nsPresContext* aPresContext, ClearTextRunsInFlowChain(this); nsTextFrame* targetTextFrame; - nsTextFrame* lastTextFrame; PRInt32 nodeLength = mContent->GetText()->GetLength(); if (aAppend) { - lastTextFrame = static_cast(GetLastContinuation()); - lastTextFrame->mState &= ~TEXT_WHITESPACE_FLAGS; - targetTextFrame = lastTextFrame; + targetTextFrame = static_cast(GetLastContinuation()); + targetTextFrame->mState &= ~TEXT_WHITESPACE_FLAGS; } else { - // Mark all the continuation frames as dirty, and fix up mContentLengths to + // 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. @@ -3565,10 +3574,6 @@ nsTextFrame::CharacterDataChanged(nsPresContext* aPresContext, if (textFrame->mContentOffset > newLength) { textFrame->mContentOffset = newLength; } - if (textFrame->mContentOffset + textFrame->mContentLength > newLength) { - textFrame->mContentLength = newLength - textFrame->mContentOffset; - } - lastTextFrame = textFrame; textFrame = static_cast(textFrame->GetNextContinuation()); if (!textFrame) { break; @@ -3577,8 +3582,6 @@ nsTextFrame::CharacterDataChanged(nsPresContext* aPresContext, } while (1); targetTextFrame = this; } - // Set the length of the last text frame in the chain (necessary if the node grew) - lastTextFrame->mContentLength = nodeLength - lastTextFrame->mContentOffset; // Ask the parent frame to reflow me. aPresContext->GetPresShell()->FrameNeedsReflow(targetTextFrame, @@ -3656,8 +3659,8 @@ nsTextFrame::GetSelectionDetails() { if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) { SelectionDetails* details = - GetFrameSelection()->LookUpSelection(mContent, mContentOffset, - mContentLength, PR_FALSE); + GetFrameSelection()->LookUpSelection(mContent, GetContentOffset(), + GetContentLength(), PR_FALSE); SelectionDetails* sd; for (sd = details; sd; sd = sd->mNext) { sd->mStart += mContentOffset; @@ -4508,7 +4511,7 @@ nsTextFrame::GetPointFromOffset(nsPresContext* aPresContext, if (mState & NS_FRAME_IS_DIRTY) return NS_ERROR_UNEXPECTED; - if (mContentLength <= 0) { + if (GetContentLength() <= 0) { return NS_OK; } @@ -4610,7 +4613,7 @@ nsTextFrame::GetChildFrameContainingOffset(PRInt32 aContentOffset, PRBool nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset) { - NS_ASSERTION(aOffset && *aOffset <= mContentLength, "aOffset out of range"); + NS_ASSERTION(aOffset && *aOffset <= GetContentLength(), "aOffset out of range"); gfxSkipCharsIterator iter = EnsureTextRun(); if (!mTextRun) @@ -4654,7 +4657,8 @@ private: PRBool nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset) { - NS_ASSERTION(aOffset && *aOffset <= mContentLength, "aOffset out of range"); + PRInt32 contentLength = GetContentLength(); + NS_ASSERTION(aOffset && *aOffset <= contentLength, "aOffset out of range"); PRBool selectable; PRUint8 selectStyle; @@ -4669,7 +4673,7 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset) TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_TRUE); // A negative offset means "end of frame". - PRInt32 startOffset = mContentOffset + (*aOffset < 0 ? mContentLength : *aOffset); + PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); if (!aForward) { PRInt32 i; @@ -4697,7 +4701,7 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset) return PR_TRUE; } } - *aOffset = mContentLength; + *aOffset = contentLength; } return PR_FALSE; @@ -4803,7 +4807,8 @@ PRBool nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsKeyboardSelect, PRInt32* aOffset, PRBool* aSawBeforeType) { - NS_ASSERTION (aOffset && *aOffset <= mContentLength, "aOffset out of range"); + PRInt32 contentLength = GetContentLength(); + NS_ASSERTION (aOffset && *aOffset <= contentLength, "aOffset out of range"); PRBool selectable; PRUint8 selectStyle; @@ -4811,7 +4816,7 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool if (selectStyle == NS_STYLE_USER_SELECT_ALL) return PR_FALSE; - PRInt32 offset = mContentOffset + (*aOffset < 0 ? mContentLength : *aOffset); + PRInt32 offset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); ClusterIterator cIter(this, offset, aForward ? 1 : -1); if (!cIter.NextCluster()) @@ -5191,6 +5196,34 @@ HasSoftHyphenBefore(const nsTextFragment* aFrag, gfxTextRun* aTextRun, return PR_FALSE; } +void +nsTextFrame::SetLength(PRInt32 aLength) +{ + mContentLengthHint = aLength; + PRInt32 end = GetContentOffset() + aLength; + nsTextFrame* f = static_cast(GetNextInFlow()); + if (!f) + return; + if (end < f->mContentOffset) { + // Our frame is shrinking. Give the text to our next in flow. + f->mContentOffset = end; + if (f->GetTextRun() != mTextRun) { + ClearTextRun(); + f->ClearTextRun(); + } + return; + } + while (f && f->mContentOffset < end) { + // Our frame is growing. Take text from our in-flow. + f->mContentOffset = end; + if (f->GetTextRun() != mTextRun) { + ClearTextRun(); + f->ClearTextRun(); + } + f = static_cast(f->GetNextInFlow()); + } +} + NS_IMETHODIMP nsTextFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, @@ -5214,25 +5247,17 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // can change whether the frame maps whitespace-only text or not. RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS); - nsTextFrame* prevInFlow = static_cast(GetPrevInFlow()); - if (prevInFlow) { - // Our mContentOffset may be out of date due to our prev-in-flow growing or - // shrinking. Update it. - mContentOffset = prevInFlow->GetContentEnd(); - } - // Temporarily map all possible content while we construct our new textrun. // so that when doing reflow our styles prevail over any part of the // textrun we look at. Note that next-in-flows may be mapping the same // content; gfxTextRun construction logic will ensure that we take priority. PRInt32 maxContentLength = GetInFlowContentLength(); - mContentLength = maxContentLength; // XXX If there's no line layout, we shouldn't even have created this // frame. This may happen if, for example, this is text inside a table // but not inside a cell. For now, just don't reflow. We also don't need to // reflow if there is no content. - if (!aReflowState.mLineLayout || !mContentLength) { + if (!aReflowState.mLineLayout || !maxContentLength) { ClearMetrics(aMetrics); aStatus = NS_FRAME_COMPLETE; return NS_OK; @@ -5271,11 +5296,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, PRBool layoutDependentTextRun = lineLayout.GetFirstLetterStyleOK() || lineLayout.GetInFirstLine(); if (layoutDependentTextRun) { - AddStateBits(TEXT_RUN_LAYOUT_DEPENDENT); - } - if (layoutDependentTextRun || - (prevInFlow && (prevInFlow->GetStateBits() & TEXT_RUN_LAYOUT_DEPENDENT))) { - ClearTextRun(); + SetLength(maxContentLength); } PRUint32 flowEndInTextRun; @@ -5294,8 +5315,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // DOM offsets of the text range we need to measure, after trimming // whitespace, restricting to first-letter, and restricting preformatted text // to nearest newline - PRInt32 length = mContentLength; - PRInt32 offset = mContentOffset; + PRInt32 length = maxContentLength; + PRInt32 offset = GetContentOffset(); // Restrict preformatted text to the nearest newline PRInt32 newLineOffset = -1; @@ -5447,7 +5468,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // Record that whitespace has already been trimmed. AddStateBits(TEXT_TRIMMED_TRAILING_WHITESPACE); } - mContentLength = offset + charsFit - mContentOffset; + PRInt32 contentLength = offset + charsFit - GetContentOffset(); ///////////////////////////////////////////////////////////////////// // Compute output metrics @@ -5526,13 +5547,13 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, } // Compute reflow status - aStatus = mContentLength == maxContentLength + aStatus = contentLength == maxContentLength ? NS_FRAME_COMPLETE : NS_FRAME_NOT_COMPLETE; if (charsFit == 0 && length > 0) { // Couldn't place any text aStatus = NS_INLINE_LINE_BREAK_BEFORE(); - } else if (mContentLength > 0 && mContentLength - 1 == newLineOffset) { + } else if (contentLength > 0 && contentLength - 1 == newLineOffset) { // Ends in \n aStatus = NS_INLINE_LINE_BREAK_AFTER(aStatus); lineLayout.SetLineEndsInBR(PR_TRUE); @@ -5563,10 +5584,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, charsFit - numJustifiableCharacters); } - if (layoutDependentTextRun) { - // Nuke any text run since it may not be valid now that we have reflowed - ClearTextRun(); - } + SetLength(contentLength); Invalidate(nsRect(nsPoint(0, 0), GetSize())); @@ -5598,7 +5616,8 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, AddStateBits(TEXT_END_OF_LINE); - if (!mContentLength) + PRInt32 contentLength = GetContentLength(); + if (!contentLength) return NS_OK; gfxSkipCharsIterator start = EnsureTextRun(&aRC); @@ -5617,11 +5636,11 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, aLastCharIsJustifiable = PR_TRUE; } else if (trimmed.GetEnd() < GetContentEnd()) { gfxSkipCharsIterator end = iter; - PRUint32 endOffset = end.ConvertOriginalToSkipped(mContentOffset + mContentLength); + PRUint32 endOffset = end.ConvertOriginalToSkipped(GetContentOffset() + contentLength); if (trimmedEnd < endOffset) { // We can't be dealing with tabs here ... they wouldn't be trimmed. So it's // OK to pass null for the line container. - PropertyProvider provider(mTextRun, textStyle, frag, this, start, mContentLength, + PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength, nsnull, 0); delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider); // non-compressed whitespace being skipped at end of line -> justifiable @@ -5634,7 +5653,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext, if (!aLastCharIsJustifiable && NS_STYLE_TEXT_ALIGN_JUSTIFY == textStyle->mTextAlign) { // Check if any character in the last cluster is justifiable - PropertyProvider provider(mTextRun, textStyle, frag, this, start, mContentLength, + PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength, nsnull, 0); PRBool isCJK = IsChineseJapaneseLangGroup(this); gfxSkipCharsIterator justificationEnd(iter); @@ -5714,8 +5733,8 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, gfxSkipCharsBuilder skipCharsBuilder; nsTextFrame* textFrame; const nsTextFragment* textFrag = mContent->GetText(); - PRInt32 keptCharsLength = 0; - PRInt32 validCharsLength = 0; + PRUint32 keptCharsLength = 0; + PRUint32 validCharsLength = 0; // Build skipChars and copy text, for each text frame in this continuation block for (textFrame = this; textFrame; @@ -5743,10 +5762,10 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, while (iter.GetOriginalOffset() < trimmedContentOffsets.GetEnd() && keptCharsLength < aSkippedMaxLength) { // For each original char from content text - if (iter.IsOriginalCharSkipped() || ++ validCharsLength <= aSkippedStartOffset) { + if (iter.IsOriginalCharSkipped() || ++validCharsLength <= aSkippedStartOffset) { skipCharsBuilder.SkipChar(); } else { - ++ keptCharsLength; + ++keptCharsLength; skipCharsBuilder.KeepChar(); if (aAppendToString) { aAppendToString->Append( @@ -5787,12 +5806,13 @@ nsTextFrame::ToCString(nsString& aBuf, PRInt32* aTotalContentLength) const // Compute the total length of the text content. *aTotalContentLength = frag->GetLength(); + PRInt32 contentLength = GetContentLength(); // Set current fragment and current fragment offset - if (0 == mContentLength) { + if (0 == contentLength) { return; } - PRInt32 fragOffset = mContentOffset; - PRInt32 n = fragOffset + mContentLength; + PRInt32 fragOffset = GetContentOffset(); + PRInt32 n = fragOffset + contentLength; while (fragOffset < n) { PRUnichar ch = frag->CharAt(fragOffset++); if (ch == '\r') { @@ -5877,7 +5897,7 @@ nsTextFrame::List(FILE* out, PRInt32 aIndent) const // Output the first/last content offset and prev/next in flow info PRBool isComplete = GetContentEnd() == totalContentLength; fprintf(out, "[%d,%d,%c] ", - mContentOffset, mContentLength, + GetContentOffset(), GetContentLength(), isComplete ? 'T':'F'); if (nsnull != mNextSibling) { @@ -5984,20 +6004,24 @@ void nsTextFrame::AdjustOffsetsForBidi(PRInt32 aStart, PRInt32 aEnd) { AddStateBits(NS_FRAME_IS_BIDI); - SetOffsets(aStart, aEnd); - /* - * After Bidi resolution we may need to reassign text runs. - * This is called during bidi resolution from the block container, so we - * shouldn't be holding a local reference to a textrun anywhere. - */ - ClearTextRun(); -} -void -nsTextFrame::SetOffsets(PRInt32 aStart, PRInt32 aEnd) -{ - mContentOffset = aStart; - mContentLength = aEnd - aStart; + nsTextFrame* prev = static_cast(GetPrevInFlow()); + if (prev) { + // the bidi resolver can be very evil when columns/pages are involved. Don't + // let it violate our invariants. + PRInt32 prevOffset = prev->GetContentOffset(); + aStart = PR_MAX(aStart, prevOffset); + aEnd = PR_MAX(aEnd, prevOffset); + } + if (mContentOffset != aStart) { + mContentOffset = aStart; + ClearTextRun(); + if (prev) { + prev->ClearTextRun(); + } + } + + SetLength(aEnd - aStart); } /**