зеркало из https://github.com/mozilla/pjs.git
Eliminated buffering that the text frame was doing when measuring
text in runs and changed the text transformer code to do the buffering instead. It was already copying the transformed text into its internal buffer anyway, so this saves the extra copy
This commit is contained in:
Родитель
5cad50006d
Коммит
a65319e532
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
|||
* <LI>capitalization
|
||||
* <LI>lowercasing
|
||||
* <LI>uppercasing
|
||||
* <LI>ascii to Unicode
|
||||
* <LI>discarded characters
|
||||
* <LI>conversion of   that is not part of whitespace into a space
|
||||
* </UL>
|
||||
*
|
||||
* 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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
|||
* <LI>capitalization
|
||||
* <LI>lowercasing
|
||||
* <LI>uppercasing
|
||||
* <LI>ascii to Unicode
|
||||
* <LI>discarded characters
|
||||
* <LI>conversion of   that is not part of whitespace into a space
|
||||
* </UL>
|
||||
*
|
||||
* 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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче