From 00ceaa5363ce333f085b4c9d8a585c489370a9e8 Mon Sep 17 00:00:00 2001 From: "reed@reedloden.com" Date: Wed, 7 Nov 2007 20:33:28 -0800 Subject: [PATCH] Bug 391584 - Pass around a context string so we can detect word breaks at the beginning or end of frames [p=roc r=smontagu a=blocking1.9+] --- layout/generic/nsFrame.cpp | 5 +++ layout/generic/nsIFrame.h | 3 ++ layout/generic/nsTextFrameThebes.cpp | 46 ++++++++++++++++++---------- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 9cf3e23f836..b2419f2e64c 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4709,6 +4709,9 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos) jumpedLine && !wordSelectEatSpace && state.mSawBeforeType) { done = PR_TRUE; } else { + if (jumpedLine) { + state.mContext.Truncate(); + } current = nextFrame; offset = nextFrameOffset; // Jumping a line is equivalent to encountering whitespace @@ -4923,6 +4926,8 @@ nsFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsK { NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); PRInt32 startOffset = *aOffset; + // This isn't text, so truncate the context + aState->mContext.Truncate(); if (startOffset < 0) startOffset = 1; if (aForward == (startOffset == 0)) { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 20c1b29895f..4d3c9d76f1a 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -2140,6 +2140,9 @@ protected: PRPackedBool mSawBeforeType; // true when the last character encountered was punctuation PRPackedBool mLastCharWasPunctuation; + // text that's *before* the current frame when aForward is true, *after* + // the current frame when aForward is false. + nsAutoString mContext; PeekWordState() : mAtStart(PR_TRUE), mSawBeforeType(PR_FALSE), mLastCharWasPunctuation(PR_FALSE) {} diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index ed4539d8d31..9ac701381ee 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4420,7 +4420,8 @@ nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset) */ class ClusterIterator { public: - ClusterIterator(nsTextFrame* aTextFrame, PRInt32 aPosition, PRInt32 aDirection); + ClusterIterator(nsTextFrame* aTextFrame, PRInt32 aPosition, PRInt32 aDirection, + nsString& aContext); PRBool NextCluster(); PRBool IsWhitespace(); @@ -4562,7 +4563,7 @@ ClusterIterator::NextCluster() } ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, PRInt32 aPosition, - PRInt32 aDirection) + PRInt32 aDirection, nsString& aContext) : mTextFrame(aTextFrame), mDirection(aDirection), mCharIndex(-1) { mIterator = aTextFrame->EnsureTextRun(); @@ -4584,21 +4585,32 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, PRInt32 aPosition, return; } memset(mWordBreaks.Elements(), PR_FALSE, textLen + 1); - nsAutoString text; - mFrag->AppendTo(text, textOffset, textLen); - nsIWordBreaker* wordBreaker = nsContentUtils::WordBreaker(); - PRInt32 i = 0; - while ((i = wordBreaker->NextWord(text.get(), textLen, i)) >= 0) { - mWordBreaks[i] = PR_TRUE; + PRInt32 textStart; + if (aDirection > 0) { + if (aContext.IsEmpty()) { + // No previous context, so it must be the start of a line or text run + mWordBreaks[0] = PR_TRUE; + } + textStart = aContext.Length(); + mFrag->AppendTo(aContext, textOffset, textLen); + } else { + if (aContext.IsEmpty()) { + // No following context, so it must be the end of a line or text run + mWordBreaks[textLen] = PR_TRUE; + } + textStart = 0; + nsAutoString str; + mFrag->AppendTo(str, textOffset, textLen); + aContext.Insert(str, 0); } - // XXX this never allows word breaks at the start or end of the frame, but to fix - // this we would need to rewrite word-break detection to use the text from - // textruns or something. Not a regression, at least. For now we can make things - // a little better by noting a word break opportunity when the frame starts - // or ends with white-space. - if (textLen > 0) { - mWordBreaks[0] = IsSelectionSpace(mFrag, textOffset); - mWordBreaks[textLen] = IsSelectionSpace(mFrag, textOffset + textLen - 1); + nsIWordBreaker* wordBreaker = nsContentUtils::WordBreaker(); + PRInt32 i; + for (i = 0; i <= textLen; ++i) { + PRInt32 indexInText = i + textStart; + mWordBreaks[i] |= + wordBreaker->BreakInBetween(aContext.get(), indexInText, + aContext.get() + indexInText, + aContext.Length() - indexInText); } } @@ -4616,7 +4628,7 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool return PR_FALSE; PRInt32 offset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); - ClusterIterator cIter(this, offset, aForward ? 1 : -1); + ClusterIterator cIter(this, offset, aForward ? 1 : -1, aState->mContext); if (!cIter.NextCluster()) return PR_FALSE;