diff --git a/mozilla/layout/generic/nsTextFrame.cpp b/mozilla/layout/generic/nsTextFrame.cpp index 862a892a2f9..6919fc35238 100644 --- a/mozilla/layout/generic/nsTextFrame.cpp +++ b/mozilla/layout/generic/nsTextFrame.cpp @@ -1790,9 +1790,6 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 // Transform text from content into renderable form nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE); - PrepareUnicodeText(tx, ip, paintBuf, textLength, width); - - ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge nsresult result(NS_OK); switch (aAmount){ case eSelectNoAmount : { @@ -1803,6 +1800,11 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 } break; case eSelectCharacter : { + PrepareUnicodeText(tx, ip, paintBuf, textLength, width); + ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge + nsIFrame *frameUsed = nsnull; + PRInt32 start; + PRBool found = PR_TRUE; if (aDirection == eDirPrevious){ PRInt32 i; for (i = aStartOffset -1; i >=0; i--){ @@ -1813,45 +1815,85 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 } } if (i <0){ - nsIFrame *prev = GetPrevInFlow(); - if (prev){ - return prev->PeekOffset(eSelectCharacter, aDirection, -1, aResultFrame, + found = PR_FALSE; + frameUsed = GetPrevInFlow(); + start = -1; + } + } + else if (aDirection == eDirNext){ + PRInt32 i; + for (i = aStartOffset +1; i <= mContentLength; i++){ + if (ip[i] > ip[aStartOffset]){ + *aResultFrame = this; + *aFrameOffset = i; + break; + } + } + if (aStartOffset == 0 && (mFlags & TEXT_SKIP_LEADING_WS)) + i--; //back up because we just skipped over some white space. why skip over the char also? + if (i > mContentLength){ + found = PR_FALSE; + frameUsed = GetNextInFlow(); + start = 0; + } + } + if (!found){ + if (frameUsed){ + return frameUsed->PeekOffset(eSelectCharacter, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + else {//reached end ask the frame for help + return nsFrame::PeekOffset(eSelectCharacter, aDirection, start, aResultFrame, aFrameOffset, aContentOffset); - } - else {//reached end ask the frame for help - return nsFrame::PeekOffset(eSelectCharacter, aDirection, -1, aResultFrame, - aFrameOffset, aContentOffset); - } } } - else - if (aDirection == eDirNext){ - PRInt32 i; - for (i = aStartOffset +1; i <= mContentLength; i++){ - if (ip[i] > ip[aStartOffset]){ - *aResultFrame = this; - *aFrameOffset = i; - break; - } - } - if (aStartOffset == 0 && (mFlags & TEXT_SKIP_LEADING_WS)) - i--; //back up because we just skipped over some white space. why skip over the char also? - if (i > mContentLength){ - nsIFrame *next = GetNextInFlow(); - if (next){ - return next->PeekOffset(eSelectCharacter, aDirection, 0, aResultFrame, - aFrameOffset, aContentOffset); - } - else {//reached end ask the frame for help - return nsFrame::PeekOffset(eSelectCharacter, aDirection, 0, aResultFrame, - aFrameOffset, aContentOffset); - } - } - } - *aContentOffset = mContentOffset; - } + *aContentOffset = mContentOffset; + } break; - case eSelectWord : + case eSelectWord : { + nsIFrame *frameUsed = nsnull; + PRInt32 start; + PRBool found = PR_TRUE; + PRBool isWhitespace; + PRInt32 wordLen, contentLen; + if (aDirection == eDirPrevious){ + tx.Init(this, mContentOffset + aStartOffset); + if (tx.GetPrevWord(PR_FALSE, wordLen, contentLen, isWhitespace)){ + *aFrameOffset = aStartOffset - contentLen; + //check for whitespace next. + if (isWhitespace && tx.GetPrevWord(PR_FALSE, wordLen, contentLen, isWhitespace)) + *aFrameOffset -= contentLen; + found = PR_TRUE; + } + frameUsed = GetPrevInFlow(); + start = -1; //start at end + } + else if (aDirection == eDirNext){ + tx.Init(this, mContentOffset + aStartOffset ); + if (tx.GetNextWord(PR_FALSE, wordLen, contentLen, isWhitespace)){ + *aFrameOffset = aStartOffset + contentLen; + //check for whitespace next. + if (tx.GetNextWord(PR_FALSE, wordLen, contentLen, isWhitespace) && isWhitespace) + *aFrameOffset += contentLen; + found = PR_TRUE; + } + frameUsed = GetNextInFlow(); + start = 0; + } + if (!found || (*aFrameOffset > mContentLength) || (*aFrameOffset < mContentOffset)){ //gone too far + if (frameUsed){ + return frameUsed->PeekOffset(aAmount, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + else {//reached end ask the frame for help + return nsFrame::PeekOffset(aAmount, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + } + *aContentOffset = mContentOffset; + *aResultFrame = this; + } + break; case eSelectLine : default: result = NS_ERROR_FAILURE; break; } diff --git a/mozilla/layout/generic/nsTextTransformer.cpp b/mozilla/layout/generic/nsTextTransformer.cpp index db13896ac4e..e8c1fbb0044 100644 --- a/mozilla/layout/generic/nsTextTransformer.cpp +++ b/mozilla/layout/generic/nsTextTransformer.cpp @@ -379,6 +379,270 @@ nsTextTransformer::GetNextWord(PRBool aInWord, return mBuffer; } +PRUnichar* +nsTextTransformer::GetPrevWord(PRBool aInWord, + PRInt32& aWordLenResult, + PRInt32& aContentLenResult, + PRBool& aIsWhitespaceResult) +{ + NS_PRECONDITION(mOffset <= mContentLength, "bad offset"); + + // See if the content has been exhausted + if (mOffset == 0) { + aWordLenResult = 0; + aContentLenResult = 0; + return nsnull; + } + + PRUnichar* bp = mBuffer; + PRUnichar* bufEnd = mBuffer + mBufferLength; + const nsTextFragment* frag = mCurrentFrag; + const nsTextFragment* lastFrag = mFrags;//1st is the last + PRInt32 wordLen = 1; + PRInt32 contentLen = 1; + + // Set the isWhitespace flag by examining the next character in the + // text fragment. + PRInt32 offset = mCurrentFragOffset-1; + PRUnichar firstChar; + if (frag->Is2b()) { + const PRUnichar* up = frag->Get2b(); + firstChar = up[offset]; + } + else { + const unsigned char* cp = (const unsigned char*) frag->Get1b(); + if (offset > 0) + firstChar = PRUnichar(cp[offset]); + else + firstChar = PRUnichar(cp[0]); + } + PRBool isWhitespace = XP_IS_SPACE(firstChar); + offset--; + if (isWhitespace) { + if (NS_STYLE_WHITESPACE_PRE == mWhiteSpace) { + if ('\t' == firstChar) { + // Leave tab alone so that caller can expand it + } + else if ('\n' == firstChar) { + // Advance content past newline but do not allow newline to + // remain in the word. + wordLen--; + } + else { + firstChar = ' '; + } + } + else { + firstChar = ' '; + } + } + else if (CH_NBSP == firstChar) { + firstChar = ' '; + } + else { + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(firstChar)) { + firstChar = XP_TO_LOWER(firstChar); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(firstChar)) { + firstChar = XP_TO_UPPER(firstChar); + } + break; + } + } + *bp++ = firstChar; + mCurrentFragOffset = offset +1; + if (offset < 0) { + if (mCurrentFrag == mFrags){ + goto really_done; + } + mCurrentFrag = --frag; + offset = mCurrentFrag->GetLength()-1; + } + if (isWhitespace && (NS_STYLE_WHITESPACE_PRE == mWhiteSpace)) { + goto really_done; + } + + PRInt32 numChars; + do { + PRInt32 fragLen = frag->GetLength(); + + // Scan characters in this fragment that are the same kind as the + // isWhitespace flag indicates. + if (frag->Is2b()) { + const PRUnichar* cp0 = frag->Get2b(); + const PRUnichar* end = cp0; + const PRUnichar* cp = cp0 + offset; + if (isWhitespace) { + while (cp > end) { + PRUnichar ch = *cp; + if (XP_IS_SPACE(ch)) { + cp--; + continue; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + } + else { + while (cp > end) { + PRUnichar ch = *cp; + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp--; + + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(ch)) { + ch = XP_TO_LOWER(ch); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(ch)) { + ch = XP_TO_UPPER(ch); + } + break; + } + + // Store character in buffer; grow buffer if we have to + NS_ASSERTION(bp < bufEnd, "whoops"); + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + } + } + else { + const unsigned char* cp0 = (const unsigned char*) frag->Get1b(); + const unsigned char* end = cp0; + const unsigned char* cp = cp0 + offset; + if (isWhitespace) { + while (cp > end) { + PRUnichar ch = PRUnichar(*cp); + if (XP_IS_SPACE(ch)) { + cp--; + continue; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + } + else { + while (cp > end) { + PRUnichar ch = PRUnichar(*cp); + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp--; + + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(ch)) { + ch = XP_TO_LOWER(ch); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(ch)) { + ch = XP_TO_UPPER(ch); + } + break; + } + + // Store character in buffer; grow buffer if we have to + NS_ASSERTION(bp < bufEnd, "whoops"); + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + } + } + + // Advance to next text fragment + if (frag != lastFrag) + { + frag--; + mCurrentFrag = frag; + mCurrentFragOffset = mCurrentFrag->GetLength()-1; + offset = mCurrentFragOffset; + } + else + mCurrentFragOffset = 0; + } + while (frag > lastFrag); + + done:; + + if (!aInWord && !isWhitespace && + (NS_STYLE_TEXT_TRANSFORM_CAPITALIZE == mTextTransform)) { + PRInt32 n = wordLen; + PRUnichar* bp = mBuffer; + for (; --n >= 0; bp++) { + PRUnichar ch = *bp; + if (' ' == ch) { + // Skip over NBSP's that were mapped to space + continue; + } + if (XP_IS_LOWERCASE(ch)) { + *bp = XP_TO_UPPER(ch); + } + break; + } + } + + really_done:; + mOffset -= contentLen; + NS_ASSERTION(mOffset >= 0, "whoops"); + aWordLenResult = wordLen; + aContentLenResult = contentLen; + aIsWhitespaceResult = isWhitespace; + + return mBuffer; +} + PRUnichar* nsTextTransformer::GetTextAt(PRInt32 aOffset) { diff --git a/mozilla/layout/generic/nsTextTransformer.h b/mozilla/layout/generic/nsTextTransformer.h index b3546cc7905..795fc0c61f9 100644 --- a/mozilla/layout/generic/nsTextTransformer.h +++ b/mozilla/layout/generic/nsTextTransformer.h @@ -64,6 +64,10 @@ public: PRInt32& aContentLenResult, PRBool& aIsWhitespaceResult); + PRUnichar* GetPrevWord(PRBool aInWord, + PRInt32& aWordLenResult, + PRInt32& aContentLenResult, + PRBool& aIsWhitespaceResult); PRBool HasMultibyte() const { return mHasMultibyte; } diff --git a/mozilla/layout/html/base/src/nsTextFrame.cpp b/mozilla/layout/html/base/src/nsTextFrame.cpp index 862a892a2f9..6919fc35238 100644 --- a/mozilla/layout/html/base/src/nsTextFrame.cpp +++ b/mozilla/layout/html/base/src/nsTextFrame.cpp @@ -1790,9 +1790,6 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 // Transform text from content into renderable form nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE); - PrepareUnicodeText(tx, ip, paintBuf, textLength, width); - - ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge nsresult result(NS_OK); switch (aAmount){ case eSelectNoAmount : { @@ -1803,6 +1800,11 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 } break; case eSelectCharacter : { + PrepareUnicodeText(tx, ip, paintBuf, textLength, width); + ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge + nsIFrame *frameUsed = nsnull; + PRInt32 start; + PRBool found = PR_TRUE; if (aDirection == eDirPrevious){ PRInt32 i; for (i = aStartOffset -1; i >=0; i--){ @@ -1813,45 +1815,85 @@ TextFrame::PeekOffset(nsSelectionAmount aAmount, nsDirection aDirection, PRInt32 } } if (i <0){ - nsIFrame *prev = GetPrevInFlow(); - if (prev){ - return prev->PeekOffset(eSelectCharacter, aDirection, -1, aResultFrame, + found = PR_FALSE; + frameUsed = GetPrevInFlow(); + start = -1; + } + } + else if (aDirection == eDirNext){ + PRInt32 i; + for (i = aStartOffset +1; i <= mContentLength; i++){ + if (ip[i] > ip[aStartOffset]){ + *aResultFrame = this; + *aFrameOffset = i; + break; + } + } + if (aStartOffset == 0 && (mFlags & TEXT_SKIP_LEADING_WS)) + i--; //back up because we just skipped over some white space. why skip over the char also? + if (i > mContentLength){ + found = PR_FALSE; + frameUsed = GetNextInFlow(); + start = 0; + } + } + if (!found){ + if (frameUsed){ + return frameUsed->PeekOffset(eSelectCharacter, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + else {//reached end ask the frame for help + return nsFrame::PeekOffset(eSelectCharacter, aDirection, start, aResultFrame, aFrameOffset, aContentOffset); - } - else {//reached end ask the frame for help - return nsFrame::PeekOffset(eSelectCharacter, aDirection, -1, aResultFrame, - aFrameOffset, aContentOffset); - } } } - else - if (aDirection == eDirNext){ - PRInt32 i; - for (i = aStartOffset +1; i <= mContentLength; i++){ - if (ip[i] > ip[aStartOffset]){ - *aResultFrame = this; - *aFrameOffset = i; - break; - } - } - if (aStartOffset == 0 && (mFlags & TEXT_SKIP_LEADING_WS)) - i--; //back up because we just skipped over some white space. why skip over the char also? - if (i > mContentLength){ - nsIFrame *next = GetNextInFlow(); - if (next){ - return next->PeekOffset(eSelectCharacter, aDirection, 0, aResultFrame, - aFrameOffset, aContentOffset); - } - else {//reached end ask the frame for help - return nsFrame::PeekOffset(eSelectCharacter, aDirection, 0, aResultFrame, - aFrameOffset, aContentOffset); - } - } - } - *aContentOffset = mContentOffset; - } + *aContentOffset = mContentOffset; + } break; - case eSelectWord : + case eSelectWord : { + nsIFrame *frameUsed = nsnull; + PRInt32 start; + PRBool found = PR_TRUE; + PRBool isWhitespace; + PRInt32 wordLen, contentLen; + if (aDirection == eDirPrevious){ + tx.Init(this, mContentOffset + aStartOffset); + if (tx.GetPrevWord(PR_FALSE, wordLen, contentLen, isWhitespace)){ + *aFrameOffset = aStartOffset - contentLen; + //check for whitespace next. + if (isWhitespace && tx.GetPrevWord(PR_FALSE, wordLen, contentLen, isWhitespace)) + *aFrameOffset -= contentLen; + found = PR_TRUE; + } + frameUsed = GetPrevInFlow(); + start = -1; //start at end + } + else if (aDirection == eDirNext){ + tx.Init(this, mContentOffset + aStartOffset ); + if (tx.GetNextWord(PR_FALSE, wordLen, contentLen, isWhitespace)){ + *aFrameOffset = aStartOffset + contentLen; + //check for whitespace next. + if (tx.GetNextWord(PR_FALSE, wordLen, contentLen, isWhitespace) && isWhitespace) + *aFrameOffset += contentLen; + found = PR_TRUE; + } + frameUsed = GetNextInFlow(); + start = 0; + } + if (!found || (*aFrameOffset > mContentLength) || (*aFrameOffset < mContentOffset)){ //gone too far + if (frameUsed){ + return frameUsed->PeekOffset(aAmount, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + else {//reached end ask the frame for help + return nsFrame::PeekOffset(aAmount, aDirection, start, aResultFrame, + aFrameOffset, aContentOffset); + } + } + *aContentOffset = mContentOffset; + *aResultFrame = this; + } + break; case eSelectLine : default: result = NS_ERROR_FAILURE; break; } diff --git a/mozilla/layout/html/base/src/nsTextTransformer.cpp b/mozilla/layout/html/base/src/nsTextTransformer.cpp index db13896ac4e..e8c1fbb0044 100644 --- a/mozilla/layout/html/base/src/nsTextTransformer.cpp +++ b/mozilla/layout/html/base/src/nsTextTransformer.cpp @@ -379,6 +379,270 @@ nsTextTransformer::GetNextWord(PRBool aInWord, return mBuffer; } +PRUnichar* +nsTextTransformer::GetPrevWord(PRBool aInWord, + PRInt32& aWordLenResult, + PRInt32& aContentLenResult, + PRBool& aIsWhitespaceResult) +{ + NS_PRECONDITION(mOffset <= mContentLength, "bad offset"); + + // See if the content has been exhausted + if (mOffset == 0) { + aWordLenResult = 0; + aContentLenResult = 0; + return nsnull; + } + + PRUnichar* bp = mBuffer; + PRUnichar* bufEnd = mBuffer + mBufferLength; + const nsTextFragment* frag = mCurrentFrag; + const nsTextFragment* lastFrag = mFrags;//1st is the last + PRInt32 wordLen = 1; + PRInt32 contentLen = 1; + + // Set the isWhitespace flag by examining the next character in the + // text fragment. + PRInt32 offset = mCurrentFragOffset-1; + PRUnichar firstChar; + if (frag->Is2b()) { + const PRUnichar* up = frag->Get2b(); + firstChar = up[offset]; + } + else { + const unsigned char* cp = (const unsigned char*) frag->Get1b(); + if (offset > 0) + firstChar = PRUnichar(cp[offset]); + else + firstChar = PRUnichar(cp[0]); + } + PRBool isWhitespace = XP_IS_SPACE(firstChar); + offset--; + if (isWhitespace) { + if (NS_STYLE_WHITESPACE_PRE == mWhiteSpace) { + if ('\t' == firstChar) { + // Leave tab alone so that caller can expand it + } + else if ('\n' == firstChar) { + // Advance content past newline but do not allow newline to + // remain in the word. + wordLen--; + } + else { + firstChar = ' '; + } + } + else { + firstChar = ' '; + } + } + else if (CH_NBSP == firstChar) { + firstChar = ' '; + } + else { + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(firstChar)) { + firstChar = XP_TO_LOWER(firstChar); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(firstChar)) { + firstChar = XP_TO_UPPER(firstChar); + } + break; + } + } + *bp++ = firstChar; + mCurrentFragOffset = offset +1; + if (offset < 0) { + if (mCurrentFrag == mFrags){ + goto really_done; + } + mCurrentFrag = --frag; + offset = mCurrentFrag->GetLength()-1; + } + if (isWhitespace && (NS_STYLE_WHITESPACE_PRE == mWhiteSpace)) { + goto really_done; + } + + PRInt32 numChars; + do { + PRInt32 fragLen = frag->GetLength(); + + // Scan characters in this fragment that are the same kind as the + // isWhitespace flag indicates. + if (frag->Is2b()) { + const PRUnichar* cp0 = frag->Get2b(); + const PRUnichar* end = cp0; + const PRUnichar* cp = cp0 + offset; + if (isWhitespace) { + while (cp > end) { + PRUnichar ch = *cp; + if (XP_IS_SPACE(ch)) { + cp--; + continue; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + } + else { + while (cp > end) { + PRUnichar ch = *cp; + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp--; + + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(ch)) { + ch = XP_TO_LOWER(ch); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(ch)) { + ch = XP_TO_UPPER(ch); + } + break; + } + + // Store character in buffer; grow buffer if we have to + NS_ASSERTION(bp < bufEnd, "whoops"); + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + } + } + else { + const unsigned char* cp0 = (const unsigned char*) frag->Get1b(); + const unsigned char* end = cp0; + const unsigned char* cp = cp0 + offset; + if (isWhitespace) { + while (cp > end) { + PRUnichar ch = PRUnichar(*cp); + if (XP_IS_SPACE(ch)) { + cp--; + continue; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + contentLen += numChars; + } + else { + while (cp > end) { + PRUnichar ch = PRUnichar(*cp); + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp--; + + switch (mTextTransform) { + case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: + if (XP_IS_UPPERCASE(ch)) { + ch = XP_TO_LOWER(ch); + } + break; + case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: + if (XP_IS_LOWERCASE(ch)) { + ch = XP_TO_UPPER(ch); + } + break; + } + + // Store character in buffer; grow buffer if we have to + NS_ASSERTION(bp < bufEnd, "whoops"); + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset -= numChars; + goto done; + } + numChars = (cp0 + offset) - cp; + wordLen += numChars; + contentLen += numChars; + } + } + + // Advance to next text fragment + if (frag != lastFrag) + { + frag--; + mCurrentFrag = frag; + mCurrentFragOffset = mCurrentFrag->GetLength()-1; + offset = mCurrentFragOffset; + } + else + mCurrentFragOffset = 0; + } + while (frag > lastFrag); + + done:; + + if (!aInWord && !isWhitespace && + (NS_STYLE_TEXT_TRANSFORM_CAPITALIZE == mTextTransform)) { + PRInt32 n = wordLen; + PRUnichar* bp = mBuffer; + for (; --n >= 0; bp++) { + PRUnichar ch = *bp; + if (' ' == ch) { + // Skip over NBSP's that were mapped to space + continue; + } + if (XP_IS_LOWERCASE(ch)) { + *bp = XP_TO_UPPER(ch); + } + break; + } + } + + really_done:; + mOffset -= contentLen; + NS_ASSERTION(mOffset >= 0, "whoops"); + aWordLenResult = wordLen; + aContentLenResult = contentLen; + aIsWhitespaceResult = isWhitespace; + + return mBuffer; +} + PRUnichar* nsTextTransformer::GetTextAt(PRInt32 aOffset) { diff --git a/mozilla/layout/html/base/src/nsTextTransformer.h b/mozilla/layout/html/base/src/nsTextTransformer.h index b3546cc7905..795fc0c61f9 100644 --- a/mozilla/layout/html/base/src/nsTextTransformer.h +++ b/mozilla/layout/html/base/src/nsTextTransformer.h @@ -64,6 +64,10 @@ public: PRInt32& aContentLenResult, PRBool& aIsWhitespaceResult); + PRUnichar* GetPrevWord(PRBool aInWord, + PRInt32& aWordLenResult, + PRInt32& aContentLenResult, + PRBool& aIsWhitespaceResult); PRBool HasMultibyte() const { return mHasMultibyte; }