diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index b0c998825a1..591ac528ef4 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -3359,19 +3359,9 @@ struct SegmentData {
PRInt32 ContentLen() {return PRInt32(mContentLen);}
};
-#define IS_ODD_NUMBER(n) \
- (0 != ((n) & 0x1))
-
-#define IS_EVEN_NUMBER(n) \
- (0 == ((n) & 0x1))
-
-#define IS_32BIT_ALIGNED_PTR(p) \
- (0 == (long(p) & 0x3))
-
struct TextRun {
- PRUnichar mBufSpace[256];
- PRUnichar* mBuf;
- PRInt32 mBufSize, mBufLength;
+ // Total number of characters and the accumulated content length
+ PRInt32 mTotalNumChars, mTotalContentLen;
// Words and whitespace each count as a segment
PRInt32 mNumSegments;
@@ -3384,22 +3374,14 @@ struct TextRun {
TextRun()
{
- mBuf = mBufSpace;
- mBufSize = 256;
- mBufLength = mNumSegments = 0;
+ Reset();
}
- ~TextRun()
- {
- if (mBuf != mBufSpace) {
- delete []mBuf;
- }
- }
-
void Reset()
{
- mBufLength = 0;
mNumSegments = 0;
+ mTotalNumChars = 0;
+ mTotalContentLen = 0;
}
// Returns PR_TRUE if we're currently buffering text
@@ -3408,87 +3390,15 @@ struct TextRun {
return mNumSegments > 0;
}
- void GrowBuffer(PRInt32 aMinBufSize)
- {
- // Allocate a new buffer
- do {
- mBufSize += 100;
- } while (mBufSize < aMinBufSize);
-
- PRUnichar* newBufSpace = new PRUnichar[mBufSize];
- memcpy(newBufSpace, mBuf, mBufLength * sizeof(PRUnichar));
- if (mBuf != mBufSpace) {
- delete []mBuf;
- }
- mBuf = newBufSpace;
- }
-
- void AddWhitespace(PRUnichar* aText,
- PRInt32 aNumChars,
- PRInt32 aContentLen)
+ void AddSegment(PRInt32 aNumChars, PRInt32 aContentLen, PRBool aIsWhitespace)
{
NS_PRECONDITION(mNumSegments < TEXT_MAX_NUM_SEGMENTS, "segment overflow");
- NS_PRECONDITION(IS_32BIT_ALIGNED_PTR(aText), "unexpected alignment of text pointer");
- // See if we have room in the buffer
- PRInt32 newBufLength = mBufLength + aNumChars;
- if (newBufLength > mBufSize) {
- GrowBuffer(newBufLength);
- }
-
- if (1 == aNumChars) {
- mBuf[mBufLength] = *aText;
- } else {
- ::memcpy(&mBuf[mBufLength], aText, aNumChars * sizeof(PRUnichar*));
- }
- mBufLength = newBufLength;
-
- mBreaks[mNumSegments] = mBufLength;
- mSegments[mNumSegments].mIsWhitespace = PR_TRUE;
- mSegments[mNumSegments].mContentLen = PRUint32(aContentLen);
- if (mNumSegments > 0) {
- mSegments[mNumSegments].mContentLen += mSegments[mNumSegments - 1].ContentLen();
- }
- mNumSegments++;
- }
-
- void AddWord(PRUnichar* aText,
- PRInt32 aNumChars,
- PRInt32 aContentLen)
- {
- NS_PRECONDITION(mNumSegments < TEXT_MAX_NUM_SEGMENTS, "segment overflow");
- NS_PRECONDITION(IS_32BIT_ALIGNED_PTR(aText), "unexpected alignment of text pointer");
-
- // See if we have room in the buffer
- PRInt32 newBufLength = mBufLength + aNumChars;
- if (newBufLength > mBufSize) {
- GrowBuffer(newBufLength);
- }
-
- if (IS_EVEN_NUMBER(mBufLength)) {
- // We have a small amount of text (a single word) and we're at a point
- // in our buffer that is 32-bit aligned so copy 32-bit chunks at a time
- int* dest = (int*)&mBuf[mBufLength];
- int* src = (int*)aText;
- for (int i = aNumChars / 2; i > 0; i--) {
- *dest++ = *src++;
- }
- if (IS_ODD_NUMBER(aNumChars)) {
- // Copy the one remaining character
- *((PRUnichar*)dest) = *((PRUnichar*)src);
- }
-
- } else {
- ::memcpy(&mBuf[mBufLength], aText, aNumChars * sizeof(PRUnichar*));
- }
- mBufLength = newBufLength;
-
- mBreaks[mNumSegments] = mBufLength;
- mSegments[mNumSegments].mIsWhitespace = PR_FALSE;
- mSegments[mNumSegments].mContentLen = PRUint32(aContentLen);
- if (mNumSegments > 0) {
- mSegments[mNumSegments].mContentLen += mSegments[mNumSegments - 1].ContentLen();
- }
+ mTotalNumChars += aNumChars;
+ mBreaks[mNumSegments] = mTotalNumChars;
+ mSegments[mNumSegments].mIsWhitespace = aIsWhitespace;
+ mTotalContentLen += aContentLen;
+ mSegments[mNumSegments].mContentLen = PRUint32(mTotalContentLen);
mNumSegments++;
}
};
@@ -3512,6 +3422,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
nscoord prevMaxWordWidth = 0;
PRInt32 lastWordLen = 0;
PRInt32 lastWordWidth = 0;
+ PRUnichar* lastWordPtr = nsnull;
PRBool textStartsWithNBSP = PR_FALSE;
PRBool endsInWhitespace = PR_FALSE;
PRBool endsInNewline = PR_FALSE;
@@ -3535,7 +3446,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Get next word/whitespace from the text
PRBool isWhitespace;
PRInt32 wordLen, contentLen;
- PRUnichar* bp = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace);
+ PRUnichar* bp = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace,
+ textRun.mNumSegments == 0);
if (nsnull == bp) {
if (textRun.IsBuffering()) {
// Measure the remaining text
@@ -3550,6 +3462,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
}
}
lastWordLen = wordLen;
+ lastWordPtr = bp;
aTextData.mInWord = PR_FALSE;
// Measure the word/whitespace
@@ -3578,7 +3491,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
width = aTs.mSpaceWidth * wordLen;
}
else if (textRun.IsBuffering()) {
- textRun.AddWhitespace(bp, wordLen, contentLen);
+ // Add a whitespace segment
+ textRun.AddSegment(wordLen, contentLen, PR_TRUE);
continue;
}
else {
@@ -3627,10 +3541,10 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
if (aTextData.mMeasureText) {
if (measureTextRuns && !justDidFirstLetter) {
// Add another word to the text run
- textRun.AddWord(bp, wordLen, contentLen);
+ textRun.AddSegment(wordLen, contentLen, PR_FALSE);
// See if we should measure the text
- if ((textRun.mBufLength >= estimatedNumChars) ||
+ if ((textRun.mTotalNumChars >= estimatedNumChars) ||
(textRun.mNumSegments >= (TEXT_MAX_NUM_SEGMENTS - 1))) {
goto MeasureTextRun;
}
@@ -3688,7 +3602,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
MeasureTextRun:
#ifdef _WIN32
PRInt32 numCharsFit;
- aReflowState.rendContext->GetWidth(textRun.mBuf, textRun.mBufLength,
+ aReflowState.rendContext->GetWidth(aTx.GetWordBuffer(), textRun.mTotalNumChars,
maxWidth - aTextData.mX,
textRun.mBreaks, textRun.mNumSegments,
width, numCharsFit);
@@ -3700,7 +3614,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Find the index of the last segment that fit
PRInt32 lastSegment = textRun.mNumSegments - 1;
- if (textRun.mBufLength != numCharsFit) {
+ if (numCharsFit != textRun.mTotalNumChars) {
for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ;
NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment");
}
@@ -3719,15 +3633,18 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
column += numCharsFit;
aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen();
endsInWhitespace = textRun.mSegments[lastSegment].IsWhitespace();
+ // Since we measure multiple words we don't know what the last word
+ // width is
+ lastWordWidth = -1;
// If all the text didn't fit, then we're done
- if (textRun.mBufLength != numCharsFit) {
+ if (numCharsFit != textRun.mTotalNumChars) {
break;
}
if (nsnull == bp) {
- // No more text so we're all finished. Advance the offset in case we
- // just consumed a bunch of discarded characters
+ // No more text so we're all finished. Advance the offset in case the last
+ // call to GetNextWord() discarded characters
aTextData.mOffset += contentLen;
break;
}
@@ -3735,7 +3652,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Reset the number of text run segments
textRun.Reset();
- // Estimate the number of characters we think will fit
+ // Estimate the remaining number of characters we think will fit
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
estimatedNumChars += estimatedNumChars / 20;
#else
@@ -3800,26 +3717,27 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
ListTag(stdout, next);
printf("\n");
#endif
- PRUnichar* pWordBuf = aTx.GetWordBuffer();
- PRUint32 wordBufLen = aTx.GetWordBufferLength();
+ PRUnichar* pWordBuf = lastWordPtr;
+ PRUint32 wordBufLen = aTx.GetWordBufferLength() -
+ (lastWordPtr - aTx.GetWordBuffer());
// Look ahead in the text-run and compute the final word
// width, taking into account any style changes and stopping
// at the first breakable point.
- if (!aTextData.mMeasureText) {
- // We didn't measure any text so we don't know lastWordWidth.
- // We have to compute it now
+ if (!aTextData.mMeasureText || (lastWordWidth == -1)) {
+ // We either didn't measure any text or we measured multiple words
+ // at once so either way we don't know lastWordWidth. We'll have to
+ // compute it now
if (prevOffset == startingOffset) {
// There's only one word, so we don't have to measure after all
lastWordWidth = aTextData.mX;
}
else if (aTs.mSmallCaps) {
- MeasureSmallCapsText(aReflowState, aTs, aTx.GetWordBuffer(),
+ MeasureSmallCapsText(aReflowState, aTs, pWordBuf,
lastWordLen, &lastWordWidth);
}
else {
- aReflowState.rendContext->GetWidth(aTx.GetWordBuffer(),
- lastWordLen, lastWordWidth);
+ aReflowState.rendContext->GetWidth(pWordBuf, lastWordLen, lastWordWidth);
if (aTs.mLetterSpacing) {
lastWordWidth += aTs.mLetterSpacing * lastWordLen;
}
diff --git a/layout/generic/nsTextTransformer.cpp b/layout/generic/nsTextTransformer.cpp
index 466a4e6a99c..5ddb1e6b98b 100644
--- a/layout/generic/nsTextTransformer.cpp
+++ b/layout/generic/nsTextTransformer.cpp
@@ -122,7 +122,8 @@ nsTextTransformer::nsTextTransformer(nsILineBreaker* aLineBreaker,
mTextTransform(NS_STYLE_TEXT_TRANSFORM_NONE),
mMode(eNormal),
mLineBreaker(aLineBreaker),
- mWordBreaker(aWordBreaker)
+ mWordBreaker(aWordBreaker),
+ mBufferPos(0)
{
MOZ_COUNT_CTOR(nsTextTransformer);
@@ -196,7 +197,7 @@ nsTextTransformer::ScanNormalWhiteSpace_F()
}
}
- mTransformBuf.mBuffer[0] = ' ';
+ mTransformBuf.mBuffer[mBufferPos++] = ' ';
return offset;
}
@@ -207,11 +208,14 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
+ const unsigned char* cp = (const unsigned char*)frag->Get1b();
+ cp += offset;
for (; offset < fragLen; offset++) {
- PRUnichar ch = frag->CharAt(offset);
+ PRUnichar ch = *cp++;
if (XP_IS_SPACE(ch)) {
break;
}
@@ -234,9 +238,10 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -254,7 +259,7 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
if (CH_NBSP == firstChar) {
firstChar = ' ';
}
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
if (firstChar > MAX_UNIBYTE) mHasMultibyte = PR_TRUE;
// Only evaluate complex breaking logic if there are more characters
@@ -264,12 +269,10 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
const PRUnichar* cp = cp0 + offset;
PRBool breakBetween = PR_FALSE;
if (aForLineBreak) {
- mLineBreaker->BreakInBetween(mTransformBuf.GetBuffer(), 1,
- cp, (fragLen-offset), &breakBetween);
+ mLineBreaker->BreakInBetween(&firstChar, 1, cp, (fragLen-offset), &breakBetween);
}
else {
- mWordBreaker->BreakInBetween(mTransformBuf.GetBuffer(), 1,
- cp, (fragLen-offset), &breakBetween);
+ mWordBreaker->BreakInBetween(&firstChar, 1, cp, (fragLen-offset), &breakBetween);
}
if (!breakBetween) {
@@ -284,16 +287,20 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
}
numChars = (PRInt32) (next - (PRUint32) offset) + 1;
- // Grow buffer before copying
- nsresult rv = mTransformBuf.GrowTo(numChars);
+ // Since we know the number of characters we're adding grow the buffer
+ // now before we start copying
+ nsresult rv = mTransformBuf.GrowTo(mBufferPos + numChars);
if (NS_FAILED(rv)) {
- numChars = mTransformBuf.GetBufferLength();
+ numChars = mTransformBuf.GetBufferLength() - mBufferPos;
}
+ offset += numChars - 1;
+
// 1. convert nbsp into space
- // 2. check mHasMultibyte flag
- // 3. copy buffer
- PRUnichar* bp = mTransformBuf.GetBuffer() + 1;
+ // 2. check for discarded characters
+ // 3. check mHasMultibyte flag
+ // 4. copy buffer
+ PRUnichar* bp = &mTransformBuf.mBuffer[mBufferPos];
const PRUnichar* end = cp + numChars - 1;
while (cp < end) {
PRUnichar ch = *cp++;
@@ -302,15 +309,13 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
}
else if (IS_DISCARDED(ch) || (ch == 0x0a) || (ch == 0x0d)) {
// Strip discarded characters from the transformed output
+ numChars--;
continue;
}
if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE;
*bp++ = ch;
+ mBufferPos++;
}
-
- // Recompute offset and numChars in case we stripped something
- offset += numChars - 1;
- numChars = bp - mTransformBuf.GetBuffer();
}
}
@@ -325,10 +330,13 @@ nsTextTransformer::ScanPreWrapWhiteSpace_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
for (; offset < fragLen; offset++) {
+ // This function is used for both Unicode and ascii strings so don't
+ // make any assumptions about what kind of data it is
PRUnichar ch = frag->CharAt(offset);
if (!XP_IS_SPACE(ch) || (ch == '\t') || (ch == '\n')) {
if (IS_DISCARDED(ch)) {
@@ -348,9 +356,10 @@ nsTextTransformer::ScanPreWrapWhiteSpace_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ' ';
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -361,10 +370,13 @@ nsTextTransformer::ScanPreData_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
for (; offset < fragLen; offset++) {
+ // This function is used for both Unicode and ascii strings so don't
+ // make any assumptions about what kind of data it is
PRUnichar ch = frag->CharAt(offset);
if ((ch == '\t') || (ch == '\n')) {
break;
@@ -387,9 +399,10 @@ nsTextTransformer::ScanPreData_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -398,10 +411,11 @@ PRInt32
nsTextTransformer::ScanPreAsciiData_F(PRInt32* aWordLen)
{
const nsTextFragment* frag = mFrag;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
const unsigned char* cp = (const unsigned char*) frag->Get1b();
const unsigned char* end = cp + frag->GetLength();
+ PRInt32 prevBufferPos = mBufferPos;
cp += mOffset;
while (cp < end) {
@@ -428,9 +442,10 @@ nsTextTransformer::ScanPreAsciiData_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return cp - ((const unsigned char*)frag->Get1b());
}
@@ -441,6 +456,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhiteSpaceResult,
+ PRBool aResetTransformBuf,
PRBool aForLineBreak)
{
const nsTextFragment* frag = mFrag;
@@ -449,6 +465,14 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRInt32 wordLen = 0;
PRBool isWhitespace = PR_FALSE;
PRUnichar* result = nsnull;
+ PRBool prevBufferPos;
+
+ // See if we should reset the current buffer position back to the
+ // beginning of the buffer
+ if (aResetTransformBuf) {
+ mBufferPos = 0;
+ }
+ prevBufferPos = mBufferPos;
// Fix word breaking problem w/ PREFORMAT and PREWRAP
// for word breaking, we should really go to the normal code
@@ -482,7 +506,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
case ePreformatted:
if (('\n' == firstChar) || ('\t' == firstChar)) {
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
offset++;
wordLen = 1;
isWhitespace = PR_TRUE;
@@ -498,7 +522,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
case ePreWrap:
if (XP_IS_SPACE(firstChar)) {
if (('\n' == firstChar) || ('\t' == firstChar)) {
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
offset++;
wordLen = 1;
}
@@ -515,7 +539,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
break;
}
- result = mTransformBuf.GetBuffer();
+ result = &mTransformBuf.mBuffer[prevBufferPos];
if (!isWhitespace) {
switch (mTextTransform) {
diff --git a/layout/generic/nsTextTransformer.h b/layout/generic/nsTextTransformer.h
index f8a987daeea..dee2b532758 100644
--- a/layout/generic/nsTextTransformer.h
+++ b/layout/generic/nsTextTransformer.h
@@ -35,7 +35,7 @@ class nsIWordBreaker;
#define CH_NBSP 160
#define CH_SHY 173
-#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 100
+#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 256
// A growable text buffer that tries to avoid using malloc by having a
// builtin buffer. Ideally used as an automatic variable.
@@ -67,6 +67,9 @@ public:
*
capitalization
* lowercasing
* uppercasing
+ * ascii to Unicode
+ * discarded characters
+ * conversion of   that is not part of whitespace into a space
*
*
* Note that no transformations are applied that would impact word
@@ -85,9 +88,8 @@ public:
~nsTextTransformer();
/**
- * Initialize the text transform. This is when the transformation
- * occurs. Subsequent calls to GetTransformedTextFor will just
- * return the result of the single transformation.
+ * Initialize the text transform. Use GetNextWord() and GetPrevWord()
+ * to iterate the text
*/
nsresult Init(nsIFrame* aFrame,
nsIContent* aContent,
@@ -97,10 +99,22 @@ public:
return mFrag ? mFrag->GetLength() : 0;
}
+ /**
+ * Iterates the next word in the text fragment.
+ *
+ * Returns a pointer to the word, the number of characters in the word, the
+ * content length of the word, and whether it is whitespace. The content
+ * length can be greater than the word length if whitespace compression
+ * occured or if characters were discarded
+ *
+ * The default behavior is to reset the transform buffer to the beginning,
+ * but you can choose to not reste it and buffer across multiple words
+ */
PRUnichar* GetNextWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhitespaceResult,
+ PRBool aResetTransformBuf = PR_TRUE,
PRBool aForLineBreak = PR_TRUE);
PRUnichar* GetPrevWord(PRBool aInWord,
@@ -169,6 +183,10 @@ protected:
// GetPrevWord
nsAutoTextBuffer mTransformBuf;
+ // Our current position within the buffer. Used when iterating the next
+ // word, because we may be requested to buffer across multiple words
+ PRInt32 mBufferPos;
+
#ifdef DEBUG
static void SelfTest(nsILineBreaker* aLineBreaker,
nsIWordBreaker* aWordBreaker);
diff --git a/layout/html/base/src/nsTextFrame.cpp b/layout/html/base/src/nsTextFrame.cpp
index b0c998825a1..591ac528ef4 100644
--- a/layout/html/base/src/nsTextFrame.cpp
+++ b/layout/html/base/src/nsTextFrame.cpp
@@ -3359,19 +3359,9 @@ struct SegmentData {
PRInt32 ContentLen() {return PRInt32(mContentLen);}
};
-#define IS_ODD_NUMBER(n) \
- (0 != ((n) & 0x1))
-
-#define IS_EVEN_NUMBER(n) \
- (0 == ((n) & 0x1))
-
-#define IS_32BIT_ALIGNED_PTR(p) \
- (0 == (long(p) & 0x3))
-
struct TextRun {
- PRUnichar mBufSpace[256];
- PRUnichar* mBuf;
- PRInt32 mBufSize, mBufLength;
+ // Total number of characters and the accumulated content length
+ PRInt32 mTotalNumChars, mTotalContentLen;
// Words and whitespace each count as a segment
PRInt32 mNumSegments;
@@ -3384,22 +3374,14 @@ struct TextRun {
TextRun()
{
- mBuf = mBufSpace;
- mBufSize = 256;
- mBufLength = mNumSegments = 0;
+ Reset();
}
- ~TextRun()
- {
- if (mBuf != mBufSpace) {
- delete []mBuf;
- }
- }
-
void Reset()
{
- mBufLength = 0;
mNumSegments = 0;
+ mTotalNumChars = 0;
+ mTotalContentLen = 0;
}
// Returns PR_TRUE if we're currently buffering text
@@ -3408,87 +3390,15 @@ struct TextRun {
return mNumSegments > 0;
}
- void GrowBuffer(PRInt32 aMinBufSize)
- {
- // Allocate a new buffer
- do {
- mBufSize += 100;
- } while (mBufSize < aMinBufSize);
-
- PRUnichar* newBufSpace = new PRUnichar[mBufSize];
- memcpy(newBufSpace, mBuf, mBufLength * sizeof(PRUnichar));
- if (mBuf != mBufSpace) {
- delete []mBuf;
- }
- mBuf = newBufSpace;
- }
-
- void AddWhitespace(PRUnichar* aText,
- PRInt32 aNumChars,
- PRInt32 aContentLen)
+ void AddSegment(PRInt32 aNumChars, PRInt32 aContentLen, PRBool aIsWhitespace)
{
NS_PRECONDITION(mNumSegments < TEXT_MAX_NUM_SEGMENTS, "segment overflow");
- NS_PRECONDITION(IS_32BIT_ALIGNED_PTR(aText), "unexpected alignment of text pointer");
- // See if we have room in the buffer
- PRInt32 newBufLength = mBufLength + aNumChars;
- if (newBufLength > mBufSize) {
- GrowBuffer(newBufLength);
- }
-
- if (1 == aNumChars) {
- mBuf[mBufLength] = *aText;
- } else {
- ::memcpy(&mBuf[mBufLength], aText, aNumChars * sizeof(PRUnichar*));
- }
- mBufLength = newBufLength;
-
- mBreaks[mNumSegments] = mBufLength;
- mSegments[mNumSegments].mIsWhitespace = PR_TRUE;
- mSegments[mNumSegments].mContentLen = PRUint32(aContentLen);
- if (mNumSegments > 0) {
- mSegments[mNumSegments].mContentLen += mSegments[mNumSegments - 1].ContentLen();
- }
- mNumSegments++;
- }
-
- void AddWord(PRUnichar* aText,
- PRInt32 aNumChars,
- PRInt32 aContentLen)
- {
- NS_PRECONDITION(mNumSegments < TEXT_MAX_NUM_SEGMENTS, "segment overflow");
- NS_PRECONDITION(IS_32BIT_ALIGNED_PTR(aText), "unexpected alignment of text pointer");
-
- // See if we have room in the buffer
- PRInt32 newBufLength = mBufLength + aNumChars;
- if (newBufLength > mBufSize) {
- GrowBuffer(newBufLength);
- }
-
- if (IS_EVEN_NUMBER(mBufLength)) {
- // We have a small amount of text (a single word) and we're at a point
- // in our buffer that is 32-bit aligned so copy 32-bit chunks at a time
- int* dest = (int*)&mBuf[mBufLength];
- int* src = (int*)aText;
- for (int i = aNumChars / 2; i > 0; i--) {
- *dest++ = *src++;
- }
- if (IS_ODD_NUMBER(aNumChars)) {
- // Copy the one remaining character
- *((PRUnichar*)dest) = *((PRUnichar*)src);
- }
-
- } else {
- ::memcpy(&mBuf[mBufLength], aText, aNumChars * sizeof(PRUnichar*));
- }
- mBufLength = newBufLength;
-
- mBreaks[mNumSegments] = mBufLength;
- mSegments[mNumSegments].mIsWhitespace = PR_FALSE;
- mSegments[mNumSegments].mContentLen = PRUint32(aContentLen);
- if (mNumSegments > 0) {
- mSegments[mNumSegments].mContentLen += mSegments[mNumSegments - 1].ContentLen();
- }
+ mTotalNumChars += aNumChars;
+ mBreaks[mNumSegments] = mTotalNumChars;
+ mSegments[mNumSegments].mIsWhitespace = aIsWhitespace;
+ mTotalContentLen += aContentLen;
+ mSegments[mNumSegments].mContentLen = PRUint32(mTotalContentLen);
mNumSegments++;
}
};
@@ -3512,6 +3422,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
nscoord prevMaxWordWidth = 0;
PRInt32 lastWordLen = 0;
PRInt32 lastWordWidth = 0;
+ PRUnichar* lastWordPtr = nsnull;
PRBool textStartsWithNBSP = PR_FALSE;
PRBool endsInWhitespace = PR_FALSE;
PRBool endsInNewline = PR_FALSE;
@@ -3535,7 +3446,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Get next word/whitespace from the text
PRBool isWhitespace;
PRInt32 wordLen, contentLen;
- PRUnichar* bp = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace);
+ PRUnichar* bp = aTx.GetNextWord(aTextData.mInWord, &wordLen, &contentLen, &isWhitespace,
+ textRun.mNumSegments == 0);
if (nsnull == bp) {
if (textRun.IsBuffering()) {
// Measure the remaining text
@@ -3550,6 +3462,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
}
}
lastWordLen = wordLen;
+ lastWordPtr = bp;
aTextData.mInWord = PR_FALSE;
// Measure the word/whitespace
@@ -3578,7 +3491,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
width = aTs.mSpaceWidth * wordLen;
}
else if (textRun.IsBuffering()) {
- textRun.AddWhitespace(bp, wordLen, contentLen);
+ // Add a whitespace segment
+ textRun.AddSegment(wordLen, contentLen, PR_TRUE);
continue;
}
else {
@@ -3627,10 +3541,10 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
if (aTextData.mMeasureText) {
if (measureTextRuns && !justDidFirstLetter) {
// Add another word to the text run
- textRun.AddWord(bp, wordLen, contentLen);
+ textRun.AddSegment(wordLen, contentLen, PR_FALSE);
// See if we should measure the text
- if ((textRun.mBufLength >= estimatedNumChars) ||
+ if ((textRun.mTotalNumChars >= estimatedNumChars) ||
(textRun.mNumSegments >= (TEXT_MAX_NUM_SEGMENTS - 1))) {
goto MeasureTextRun;
}
@@ -3688,7 +3602,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
MeasureTextRun:
#ifdef _WIN32
PRInt32 numCharsFit;
- aReflowState.rendContext->GetWidth(textRun.mBuf, textRun.mBufLength,
+ aReflowState.rendContext->GetWidth(aTx.GetWordBuffer(), textRun.mTotalNumChars,
maxWidth - aTextData.mX,
textRun.mBreaks, textRun.mNumSegments,
width, numCharsFit);
@@ -3700,7 +3614,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Find the index of the last segment that fit
PRInt32 lastSegment = textRun.mNumSegments - 1;
- if (textRun.mBufLength != numCharsFit) {
+ if (numCharsFit != textRun.mTotalNumChars) {
for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ;
NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment");
}
@@ -3719,15 +3633,18 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
column += numCharsFit;
aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen();
endsInWhitespace = textRun.mSegments[lastSegment].IsWhitespace();
+ // Since we measure multiple words we don't know what the last word
+ // width is
+ lastWordWidth = -1;
// If all the text didn't fit, then we're done
- if (textRun.mBufLength != numCharsFit) {
+ if (numCharsFit != textRun.mTotalNumChars) {
break;
}
if (nsnull == bp) {
- // No more text so we're all finished. Advance the offset in case we
- // just consumed a bunch of discarded characters
+ // No more text so we're all finished. Advance the offset in case the last
+ // call to GetNextWord() discarded characters
aTextData.mOffset += contentLen;
break;
}
@@ -3735,7 +3652,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
// Reset the number of text run segments
textRun.Reset();
- // Estimate the number of characters we think will fit
+ // Estimate the remaining number of characters we think will fit
estimatedNumChars = (maxWidth - aTextData.mX) / aTs.mAveCharWidth;
estimatedNumChars += estimatedNumChars / 20;
#else
@@ -3800,26 +3717,27 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
ListTag(stdout, next);
printf("\n");
#endif
- PRUnichar* pWordBuf = aTx.GetWordBuffer();
- PRUint32 wordBufLen = aTx.GetWordBufferLength();
+ PRUnichar* pWordBuf = lastWordPtr;
+ PRUint32 wordBufLen = aTx.GetWordBufferLength() -
+ (lastWordPtr - aTx.GetWordBuffer());
// Look ahead in the text-run and compute the final word
// width, taking into account any style changes and stopping
// at the first breakable point.
- if (!aTextData.mMeasureText) {
- // We didn't measure any text so we don't know lastWordWidth.
- // We have to compute it now
+ if (!aTextData.mMeasureText || (lastWordWidth == -1)) {
+ // We either didn't measure any text or we measured multiple words
+ // at once so either way we don't know lastWordWidth. We'll have to
+ // compute it now
if (prevOffset == startingOffset) {
// There's only one word, so we don't have to measure after all
lastWordWidth = aTextData.mX;
}
else if (aTs.mSmallCaps) {
- MeasureSmallCapsText(aReflowState, aTs, aTx.GetWordBuffer(),
+ MeasureSmallCapsText(aReflowState, aTs, pWordBuf,
lastWordLen, &lastWordWidth);
}
else {
- aReflowState.rendContext->GetWidth(aTx.GetWordBuffer(),
- lastWordLen, lastWordWidth);
+ aReflowState.rendContext->GetWidth(pWordBuf, lastWordLen, lastWordWidth);
if (aTs.mLetterSpacing) {
lastWordWidth += aTs.mLetterSpacing * lastWordLen;
}
diff --git a/layout/html/base/src/nsTextTransformer.cpp b/layout/html/base/src/nsTextTransformer.cpp
index 466a4e6a99c..5ddb1e6b98b 100644
--- a/layout/html/base/src/nsTextTransformer.cpp
+++ b/layout/html/base/src/nsTextTransformer.cpp
@@ -122,7 +122,8 @@ nsTextTransformer::nsTextTransformer(nsILineBreaker* aLineBreaker,
mTextTransform(NS_STYLE_TEXT_TRANSFORM_NONE),
mMode(eNormal),
mLineBreaker(aLineBreaker),
- mWordBreaker(aWordBreaker)
+ mWordBreaker(aWordBreaker),
+ mBufferPos(0)
{
MOZ_COUNT_CTOR(nsTextTransformer);
@@ -196,7 +197,7 @@ nsTextTransformer::ScanNormalWhiteSpace_F()
}
}
- mTransformBuf.mBuffer[0] = ' ';
+ mTransformBuf.mBuffer[mBufferPos++] = ' ';
return offset;
}
@@ -207,11 +208,14 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
+ const unsigned char* cp = (const unsigned char*)frag->Get1b();
+ cp += offset;
for (; offset < fragLen; offset++) {
- PRUnichar ch = frag->CharAt(offset);
+ PRUnichar ch = *cp++;
if (XP_IS_SPACE(ch)) {
break;
}
@@ -234,9 +238,10 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -254,7 +259,7 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
if (CH_NBSP == firstChar) {
firstChar = ' ';
}
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
if (firstChar > MAX_UNIBYTE) mHasMultibyte = PR_TRUE;
// Only evaluate complex breaking logic if there are more characters
@@ -264,12 +269,10 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
const PRUnichar* cp = cp0 + offset;
PRBool breakBetween = PR_FALSE;
if (aForLineBreak) {
- mLineBreaker->BreakInBetween(mTransformBuf.GetBuffer(), 1,
- cp, (fragLen-offset), &breakBetween);
+ mLineBreaker->BreakInBetween(&firstChar, 1, cp, (fragLen-offset), &breakBetween);
}
else {
- mWordBreaker->BreakInBetween(mTransformBuf.GetBuffer(), 1,
- cp, (fragLen-offset), &breakBetween);
+ mWordBreaker->BreakInBetween(&firstChar, 1, cp, (fragLen-offset), &breakBetween);
}
if (!breakBetween) {
@@ -284,16 +287,20 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
}
numChars = (PRInt32) (next - (PRUint32) offset) + 1;
- // Grow buffer before copying
- nsresult rv = mTransformBuf.GrowTo(numChars);
+ // Since we know the number of characters we're adding grow the buffer
+ // now before we start copying
+ nsresult rv = mTransformBuf.GrowTo(mBufferPos + numChars);
if (NS_FAILED(rv)) {
- numChars = mTransformBuf.GetBufferLength();
+ numChars = mTransformBuf.GetBufferLength() - mBufferPos;
}
+ offset += numChars - 1;
+
// 1. convert nbsp into space
- // 2. check mHasMultibyte flag
- // 3. copy buffer
- PRUnichar* bp = mTransformBuf.GetBuffer() + 1;
+ // 2. check for discarded characters
+ // 3. check mHasMultibyte flag
+ // 4. copy buffer
+ PRUnichar* bp = &mTransformBuf.mBuffer[mBufferPos];
const PRUnichar* end = cp + numChars - 1;
while (cp < end) {
PRUnichar ch = *cp++;
@@ -302,15 +309,13 @@ nsTextTransformer::ScanNormalUnicodeText_F(PRBool aForLineBreak,
}
else if (IS_DISCARDED(ch) || (ch == 0x0a) || (ch == 0x0d)) {
// Strip discarded characters from the transformed output
+ numChars--;
continue;
}
if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE;
*bp++ = ch;
+ mBufferPos++;
}
-
- // Recompute offset and numChars in case we stripped something
- offset += numChars - 1;
- numChars = bp - mTransformBuf.GetBuffer();
}
}
@@ -325,10 +330,13 @@ nsTextTransformer::ScanPreWrapWhiteSpace_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
for (; offset < fragLen; offset++) {
+ // This function is used for both Unicode and ascii strings so don't
+ // make any assumptions about what kind of data it is
PRUnichar ch = frag->CharAt(offset);
if (!XP_IS_SPACE(ch) || (ch == '\t') || (ch == '\n')) {
if (IS_DISCARDED(ch)) {
@@ -348,9 +356,10 @@ nsTextTransformer::ScanPreWrapWhiteSpace_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ' ';
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -361,10 +370,13 @@ nsTextTransformer::ScanPreData_F(PRInt32* aWordLen)
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
PRInt32 offset = mOffset;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
+ PRInt32 prevBufferPos = mBufferPos;
for (; offset < fragLen; offset++) {
+ // This function is used for both Unicode and ascii strings so don't
+ // make any assumptions about what kind of data it is
PRUnichar ch = frag->CharAt(offset);
if ((ch == '\t') || (ch == '\n')) {
break;
@@ -387,9 +399,10 @@ nsTextTransformer::ScanPreData_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return offset;
}
@@ -398,10 +411,11 @@ PRInt32
nsTextTransformer::ScanPreAsciiData_F(PRInt32* aWordLen)
{
const nsTextFragment* frag = mFrag;
- PRUnichar* bp = mTransformBuf.GetBuffer();
+ PRUnichar* bp = mTransformBuf.GetBuffer() + mBufferPos;
PRUnichar* endbp = mTransformBuf.GetBufferEnd();
const unsigned char* cp = (const unsigned char*) frag->Get1b();
const unsigned char* end = cp + frag->GetLength();
+ PRInt32 prevBufferPos = mBufferPos;
cp += mOffset;
while (cp < end) {
@@ -428,9 +442,10 @@ nsTextTransformer::ScanPreAsciiData_F(PRInt32* aWordLen)
endbp = mTransformBuf.GetBufferEnd();
}
*bp++ = ch;
+ mBufferPos++;
}
- *aWordLen = bp - mTransformBuf.GetBuffer();
+ *aWordLen = mBufferPos - prevBufferPos;
return cp - ((const unsigned char*)frag->Get1b());
}
@@ -441,6 +456,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhiteSpaceResult,
+ PRBool aResetTransformBuf,
PRBool aForLineBreak)
{
const nsTextFragment* frag = mFrag;
@@ -449,6 +465,14 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRInt32 wordLen = 0;
PRBool isWhitespace = PR_FALSE;
PRUnichar* result = nsnull;
+ PRBool prevBufferPos;
+
+ // See if we should reset the current buffer position back to the
+ // beginning of the buffer
+ if (aResetTransformBuf) {
+ mBufferPos = 0;
+ }
+ prevBufferPos = mBufferPos;
// Fix word breaking problem w/ PREFORMAT and PREWRAP
// for word breaking, we should really go to the normal code
@@ -482,7 +506,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
case ePreformatted:
if (('\n' == firstChar) || ('\t' == firstChar)) {
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
offset++;
wordLen = 1;
isWhitespace = PR_TRUE;
@@ -498,7 +522,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
case ePreWrap:
if (XP_IS_SPACE(firstChar)) {
if (('\n' == firstChar) || ('\t' == firstChar)) {
- mTransformBuf.mBuffer[0] = firstChar;
+ mTransformBuf.mBuffer[mBufferPos++] = firstChar;
offset++;
wordLen = 1;
}
@@ -515,7 +539,7 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
break;
}
- result = mTransformBuf.GetBuffer();
+ result = &mTransformBuf.mBuffer[prevBufferPos];
if (!isWhitespace) {
switch (mTextTransform) {
diff --git a/layout/html/base/src/nsTextTransformer.h b/layout/html/base/src/nsTextTransformer.h
index f8a987daeea..dee2b532758 100644
--- a/layout/html/base/src/nsTextTransformer.h
+++ b/layout/html/base/src/nsTextTransformer.h
@@ -35,7 +35,7 @@ class nsIWordBreaker;
#define CH_NBSP 160
#define CH_SHY 173
-#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 100
+#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 256
// A growable text buffer that tries to avoid using malloc by having a
// builtin buffer. Ideally used as an automatic variable.
@@ -67,6 +67,9 @@ public:
* capitalization
* lowercasing
* uppercasing
+ * ascii to Unicode
+ * discarded characters
+ * conversion of   that is not part of whitespace into a space
*
*
* Note that no transformations are applied that would impact word
@@ -85,9 +88,8 @@ public:
~nsTextTransformer();
/**
- * Initialize the text transform. This is when the transformation
- * occurs. Subsequent calls to GetTransformedTextFor will just
- * return the result of the single transformation.
+ * Initialize the text transform. Use GetNextWord() and GetPrevWord()
+ * to iterate the text
*/
nsresult Init(nsIFrame* aFrame,
nsIContent* aContent,
@@ -97,10 +99,22 @@ public:
return mFrag ? mFrag->GetLength() : 0;
}
+ /**
+ * Iterates the next word in the text fragment.
+ *
+ * Returns a pointer to the word, the number of characters in the word, the
+ * content length of the word, and whether it is whitespace. The content
+ * length can be greater than the word length if whitespace compression
+ * occured or if characters were discarded
+ *
+ * The default behavior is to reset the transform buffer to the beginning,
+ * but you can choose to not reste it and buffer across multiple words
+ */
PRUnichar* GetNextWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhitespaceResult,
+ PRBool aResetTransformBuf = PR_TRUE,
PRBool aForLineBreak = PR_TRUE);
PRUnichar* GetPrevWord(PRBool aInWord,
@@ -169,6 +183,10 @@ protected:
// GetPrevWord
nsAutoTextBuffer mTransformBuf;
+ // Our current position within the buffer. Used when iterating the next
+ // word, because we may be requested to buffer across multiple words
+ PRInt32 mBufferPos;
+
#ifdef DEBUG
static void SelfTest(nsILineBreaker* aLineBreaker,
nsIWordBreaker* aWordBreaker);