Bug 98546. Fix word break detection to improve select by word where there is punctuation in the word. Also fixes 125172, double clicking in URL bar should select only part of URL. Also fixes bug 133312, word selection with accented letters. r=brade, sr=sfraser

This commit is contained in:
aaronl%netscape.com 2003-01-09 20:56:53 +00:00
Родитель dbe5b54f69
Коммит f703f5398e
17 изменённых файлов: 176 добавлений и 69 удалений

Просмотреть файл

@ -1602,7 +1602,8 @@ nsSelection::MoveCaret(PRUint32 aKeycode, PRBool aContinue, nsSelectionAmount aA
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
pos.SetData(mTracker, desiredX, aAmount, eDirPrevious, offsetused, PR_FALSE,PR_TRUE, PR_TRUE, mLimiter != nsnull);
pos.SetData(mTracker, desiredX, aAmount, eDirPrevious, offsetused, PR_FALSE,
PR_TRUE, PR_TRUE, mLimiter != nsnull, PR_TRUE);
HINT tHint(mHint); //temporary variable so we dont set mHint until it is necessary
switch (aKeycode){
@ -2718,7 +2719,7 @@ nsSelection::HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint&
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
pos.SetData(mTracker, 0, eSelectDir, eDirNext, startPos, PR_FALSE,
PR_TRUE, PR_TRUE, mLimiter != nsnull);
PR_TRUE, PR_TRUE, mLimiter != nsnull, PR_FALSE);
mHint = HINT(beginOfContent);
HINT saveHint = mHint;
newFrame->GetBidiProperty(aPresContext, nsLayoutAtoms::embeddingLevel,

Просмотреть файл

@ -96,7 +96,8 @@ struct nsPeekOffsetStruct
PRBool aEatingWS,
PRBool aPreferLeft,
PRBool aJumpLines,
PRBool aScrollViewStop)
PRBool aScrollViewStop,
PRBool aIsKeyboardSelect)
{
mTracker=aTracker;
mDesiredX=aDesiredX;
@ -107,6 +108,7 @@ struct nsPeekOffsetStruct
mPreferLeft=aPreferLeft;
mJumpLines = aJumpLines;
mScrollViewStop = aScrollViewStop;
mIsKeyboardSelect = aIsKeyboardSelect;
}
nsIFocusTracker *mTracker;
nscoord mDesiredX;
@ -121,6 +123,7 @@ struct nsPeekOffsetStruct
PRBool mPreferLeft;
PRBool mJumpLines;
PRBool mScrollViewStop;
PRBool mIsKeyboardSelect;
};
class nsIScrollableView;

Просмотреть файл

@ -3335,6 +3335,7 @@ PresShell::CompleteMove(PRBool aForward, PRBool aExtend)
pos.mContentOffset = 0;
pos.mContentOffsetEnd = 0;
pos.mScrollViewStop = PR_FALSE;//dont stop on scrolled views.
pos.mIsKeyboardSelect = PR_TRUE;
if (aForward)
{
outsideLimit = 1;//search from end

Просмотреть файл

@ -96,7 +96,8 @@ struct nsPeekOffsetStruct
PRBool aEatingWS,
PRBool aPreferLeft,
PRBool aJumpLines,
PRBool aScrollViewStop)
PRBool aScrollViewStop,
PRBool aIsKeyboardSelect)
{
mTracker=aTracker;
mDesiredX=aDesiredX;
@ -107,6 +108,7 @@ struct nsPeekOffsetStruct
mPreferLeft=aPreferLeft;
mJumpLines = aJumpLines;
mScrollViewStop = aScrollViewStop;
mIsKeyboardSelect = aIsKeyboardSelect;
}
nsIFocusTracker *mTracker;
nscoord mDesiredX;
@ -121,6 +123,7 @@ struct nsPeekOffsetStruct
PRBool mPreferLeft;
PRBool mJumpLines;
PRBool mScrollViewStop;
PRBool mIsKeyboardSelect;
};
class nsIScrollableView;

Просмотреть файл

@ -5983,6 +5983,7 @@ nsBlockFrame::HandleEvent(nsIPresContext* aPresContext,
pos.mDirection = eDirNext;
pos.mDesiredX = aEvent->point.x;
pos.mScrollViewStop = PR_FALSE;
pos.mIsKeyboardSelect = PR_FALSE;
result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
&pos,
mainframe,

Просмотреть файл

@ -1632,7 +1632,8 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_FALSE,
PR_TRUE,
aJumpLines,
PR_TRUE);//limit on scrolled views
PR_TRUE, //limit on scrolled views
PR_FALSE);
rv = PeekOffset(aPresContext, &startpos);
if (NS_FAILED(rv))
return rv;
@ -1645,7 +1646,8 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_FALSE,
PR_FALSE,
aJumpLines,
PR_TRUE);//limit on scrolled views
PR_TRUE, //limit on scrolled views
PR_FALSE);
rv = PeekOffset(aPresContext, &endpos);
if (NS_FAILED(rv))
return rv;

Просмотреть файл

@ -1602,7 +1602,8 @@ nsSelection::MoveCaret(PRUint32 aKeycode, PRBool aContinue, nsSelectionAmount aA
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
pos.SetData(mTracker, desiredX, aAmount, eDirPrevious, offsetused, PR_FALSE,PR_TRUE, PR_TRUE, mLimiter != nsnull);
pos.SetData(mTracker, desiredX, aAmount, eDirPrevious, offsetused, PR_FALSE,
PR_TRUE, PR_TRUE, mLimiter != nsnull, PR_TRUE);
HINT tHint(mHint); //temporary variable so we dont set mHint until it is necessary
switch (aKeycode){
@ -2718,7 +2719,7 @@ nsSelection::HandleDrag(nsIPresContext *aPresContext, nsIFrame *aFrame, nsPoint&
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
pos.SetData(mTracker, 0, eSelectDir, eDirNext, startPos, PR_FALSE,
PR_TRUE, PR_TRUE, mLimiter != nsnull);
PR_TRUE, PR_TRUE, mLimiter != nsnull, PR_FALSE);
mHint = HINT(beginOfContent);
HINT saveHint = mHint;
newFrame->GetBidiProperty(aPresContext, nsLayoutAtoms::embeddingLevel,

Просмотреть файл

@ -4291,7 +4291,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
if (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace,
PR_FALSE) &&
PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset - contentLen >= mContentOffset) ){
if ((aPos->mEatingWS && !isWhitespace) || !aPos->mEatingWS){
aPos->mContentOffset = aPos->mStartOffset - contentLen;
@ -4307,7 +4307,8 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
#endif // IBMBIDI
while (isWhitespace &&
tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen,
&isWhitespace, PR_FALSE)){
&isWhitespace, PR_FALSE,
aPos->mIsKeyboardSelect)){
aPos->mContentOffset -= contentLen;
aPos->mEatingWS = PR_TRUE;
#ifdef IBMBIDI
@ -4342,7 +4343,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE) &&
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset + contentLen <= (mContentLength + mContentOffset))){
if ((aPos->mEatingWS && isWhitespace) || !aPos->mEatingWS){
@ -4357,7 +4358,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE))
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect))
{
if (aPos->mStartOffset + contentLen > (mContentLength + mContentOffset))
goto TryNextFrame;
@ -4379,7 +4380,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
while(tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE))
while(tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect))
{
if (aPos->mStartOffset + contentLen > (mContentLength + mContentOffset))
goto TryNextFrame;

Просмотреть файл

@ -110,8 +110,6 @@ static nsICaseConversion* gCaseConv = nsnull;
nsresult
nsTextTransformer::Initialize()
{
nsresult res = NS_OK;
// read in our global word selection prefs
if ( !sWordSelectPrefInited ) {
nsCOMPtr<nsIPrefBranch> prefBranch =
@ -123,8 +121,8 @@ nsTextTransformer::Initialize()
}
sWordSelectPrefInited = PR_TRUE;
}
return res;
return NS_OK;
}
static nsresult EnsureCaseConv()
{
@ -394,7 +392,8 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen,
PRInt32
nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
PRBool* aWasTransformed)
PRBool* aWasTransformed,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
@ -414,9 +413,13 @@ nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
}
PRBool readingAlphaNumeric = PR_TRUE; //only used in sWordSelectStopAtPunctuation
//we must know if we are starting in alpha numerics.
// We must know if we are starting in alpha numerics.
// Treat high bit chars as alphanumeric, otherwise we get stuck on accented letters
// We can't trust isalnum() results for isalnum()
// Therefore we don't stop at non-ascii (high bit) punctuation,
// which is just fine. The punctuation we care about is low bit.
if (sWordSelectStopAtPunctuation && offset < fragLen)
readingAlphaNumeric = isalnum((unsigned char)*cp);
readingAlphaNumeric = isalnum((unsigned char)*cp) || !IS_ASCII_CHAR(*cp);
for (; offset < fragLen && !breakAfterThis; offset++) {
unsigned char ch = *cp++;
@ -431,8 +434,17 @@ nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
else if (XP_IS_SPACE(ch)) {
break;
}
else if (sWordSelectStopAtPunctuation && ((readingAlphaNumeric && !isalnum(ch)) || (!readingAlphaNumeric && isalnum(ch)) )) {
// on some platforms, punctuation breaks words too.
else if (sWordSelectStopAtPunctuation &&
readingAlphaNumeric && !isalnum(ch) && IS_ASCII_CHAR(ch)) {
if (!aIsKeyboardSelect)
break;
// For keyboard move-by-word, need to pass by at least
// one alphanumeric char before stopping at punct
readingAlphaNumeric = PR_FALSE;
}
else if (sWordSelectStopAtPunctuation &&
!readingAlphaNumeric && (isalnum(ch) || !IS_ASCII_CHAR(ch))) {
// On some platforms, punctuation breaks for word selection
break;
}
else if (IS_DISCARDED(ch)) {
@ -817,7 +829,8 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRBool* aIsWhiteSpaceResult,
PRBool* aWasTransformed,
PRBool aResetTransformBuf,
PRBool aForLineBreak)
PRBool aForLineBreak,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
@ -910,7 +923,9 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
else {
if (!aForLineBreak)
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed);
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen,
aWasTransformed,
aIsKeyboardSelect);
else
offset = ScanNormalAsciiText_F(&wordLen, aWasTransformed);
}
@ -951,7 +966,8 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
else {
if (!aForLineBreak)
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed);
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed,
aIsKeyboardSelect);
else
offset = ScanNormalAsciiText_F(&wordLen, aWasTransformed);
}
@ -1091,13 +1107,20 @@ nsTextTransformer::ScanNormalWhiteSpace_B()
// wordlen==*aWordLen, contentlen=newOffset-currentOffset, isWhitespace=f
PRInt32
nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen)
nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen, PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 offset = mOffset;
PRUnichar* bp = mTransformBuf.GetBufferEnd();
PRUnichar* startbp = mTransformBuf.GetBuffer();
PRUnichar ch = frag->CharAt(offset - 1);
// Treat high bit chars as alphanumeric, otherwise we get stuck on accented letters
// We can't trust isalnum() results for isalnum()
// Therefore we don't stop at non-ascii (high bit) punctuation,
// which is just fine. The punctuation we care about is low bit.
PRBool readingAlphaNumeric = isalnum(ch) || !IS_ASCII_CHAR(ch);
while (--offset >= 0) {
PRUnichar ch = frag->CharAt(offset);
if (CH_NBSP == ch) {
@ -1109,6 +1132,18 @@ nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen)
else if (IS_DISCARDED(ch)) {
continue;
}
else if (sWordSelectStopAtPunctuation && readingAlphaNumeric &&
!isalnum(ch) && IS_ASCII_CHAR(ch)) {
// Break on ascii punctuation
break;
}
else if (sWordSelectStopAtPunctuation && !readingAlphaNumeric &&
(isalnum(ch) || !IS_ASCII_CHAR(ch))) {
if (!aIsKeyboardSelect)
break;
readingAlphaNumeric = PR_TRUE;
}
if (ch > MAX_UNIBYTE) SetHasMultibyte(PR_TRUE);
if (bp == startbp) {
PRInt32 oldLength = mTransformBuf.mBufferLen;
@ -1297,7 +1332,8 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhiteSpaceResult,
PRBool aForLineBreak)
PRBool aForLineBreak,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 offset = mOffset;
@ -1343,7 +1379,7 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
offset = ScanNormalUnicodeText_B(aForLineBreak, &wordLen);
}
else {
offset = ScanNormalAsciiText_B(&wordLen);
offset = ScanNormalAsciiText_B(&wordLen, aIsKeyboardSelect);
}
break;
@ -1378,7 +1414,7 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
offset = ScanNormalUnicodeText_B(aForLineBreak, &wordLen);
}
else {
offset = ScanNormalAsciiText_B(&wordLen);
offset = ScanNormalAsciiText_B(&wordLen, aIsKeyboardSelect);
}
break;
}
@ -1657,7 +1693,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString uc2(st->text);
printf("%s forwards test: '", isAsciiTest ? "ascii" : "unicode");
fputs(NS_LossyConvertUCS2toASCII(uc2).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(uc2).get(), stdout);
printf("'\n");
}
tx.Init2(&frag, 0, preModeValue[preMode], NS_STYLE_TEXT_TRANSFORM_NONE);
@ -1672,7 +1708,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString tmp(bp, wordLen);
printf(" '");
fputs(NS_LossyConvertUCS2toASCII(tmp).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(tmp).get(), stdout);
printf("': ws=%s wordLen=%d (%d) contentLen=%d (offset=%d)\n",
ws ? "yes" : "no",
wordLen, *expectedResults, contentLen, tx.mOffset);
@ -1696,7 +1732,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString uc2(st->text);
printf("%s backwards test: '", isAsciiTest ? "ascii" : "unicode");
fputs(NS_LossyConvertUCS2toASCII(uc2).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(uc2).get(), stdout);
printf("'\n");
}
tx.Init2(&frag, frag.GetLength(), NS_STYLE_WHITESPACE_NORMAL,
@ -1710,7 +1746,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString tmp(bp, wordLen);
printf(" '");
fputs(NS_LossyConvertUCS2toASCII(tmp).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(tmp).get(), stdout);
printf("': ws=%s wordLen=%d contentLen=%d (offset=%d)\n",
ws ? "yes" : "no",
wordLen, contentLen, tx.mOffset);
@ -1732,6 +1768,10 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (error) {
fprintf(stderr, "nsTextTransformer: self test %d failed\n", testNum);
}
else if (gNoisy) {
fprintf(stdout, "nsTextTransformer: self test %d succeeded\n", testNum);
}
testNum++;
}
}

Просмотреть файл

@ -73,6 +73,8 @@ class nsIWordBreaker;
|| ((_ch) >= CH_LRE && (_ch) <= CH_RLO))
#endif // IBMBIDI
#define IS_ASCII_CHAR(ch) ((ch&0xff80) == 0)
#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 128 // used to be 256
// Indicates whether the transformed text should be left as ascii
@ -184,13 +186,15 @@ public:
PRBool* aIsWhitespaceResult,
PRBool* aWasTransformed,
PRBool aResetTransformBuf = PR_TRUE,
PRBool aForLineBreak = PR_TRUE);
PRBool aForLineBreak = PR_TRUE,
PRBool aIsKeyboardSelect = PR_FALSE);
PRUnichar* GetPrevWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhitespaceResult,
PRBool aForLineBreak = PR_TRUE);
PRBool aForLineBreak = PR_TRUE,
PRBool aIsKeyboardSelect = PR_FALSE);
// Returns PR_TRUE if the LEAVE_AS_ASCII flag is set
@ -273,7 +277,8 @@ protected:
PRInt32 ScanNormalAsciiText_F(PRInt32* aWordLen,
PRBool* aWasTransformed);
PRInt32 ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
PRBool* aWasTransformed);
PRBool* aWasTransformed,
PRBool aIsKeyboardSelect);
PRInt32 ScanNormalUnicodeText_F(PRBool aForLineBreak,
PRInt32* aWordLen,
PRBool* aWasTransformed);
@ -285,7 +290,7 @@ protected:
// Helper methods for GetPrevWord (B == backwards)
PRInt32 ScanNormalWhiteSpace_B();
PRInt32 ScanNormalAsciiText_B(PRInt32* aWordLen);
PRInt32 ScanNormalAsciiText_B(PRInt32* aWordLen, PRBool aIsKeyboardSelect);
PRInt32 ScanNormalUnicodeText_B(PRBool aForLineBreak, PRInt32* aWordLen);
PRInt32 ScanPreWrapWhiteSpace_B(PRInt32* aWordLen);
PRInt32 ScanPreData_B(PRInt32* aWordLen);

Просмотреть файл

@ -5983,6 +5983,7 @@ nsBlockFrame::HandleEvent(nsIPresContext* aPresContext,
pos.mDirection = eDirNext;
pos.mDesiredX = aEvent->point.x;
pos.mScrollViewStop = PR_FALSE;
pos.mIsKeyboardSelect = PR_FALSE;
result = nsFrame::GetNextPrevLineFromeBlockFrame(aPresContext,
&pos,
mainframe,

Просмотреть файл

@ -1632,7 +1632,8 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_FALSE,
PR_TRUE,
aJumpLines,
PR_TRUE);//limit on scrolled views
PR_TRUE, //limit on scrolled views
PR_FALSE);
rv = PeekOffset(aPresContext, &startpos);
if (NS_FAILED(rv))
return rv;
@ -1645,7 +1646,8 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
PR_FALSE,
PR_FALSE,
aJumpLines,
PR_TRUE);//limit on scrolled views
PR_TRUE, //limit on scrolled views
PR_FALSE);
rv = PeekOffset(aPresContext, &endpos);
if (NS_FAILED(rv))
return rv;

Просмотреть файл

@ -3335,6 +3335,7 @@ PresShell::CompleteMove(PRBool aForward, PRBool aExtend)
pos.mContentOffset = 0;
pos.mContentOffsetEnd = 0;
pos.mScrollViewStop = PR_FALSE;//dont stop on scrolled views.
pos.mIsKeyboardSelect = PR_TRUE;
if (aForward)
{
outsideLimit = 1;//search from end

Просмотреть файл

@ -4291,7 +4291,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset : -1;
#endif // IBMBIDI
if (tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace,
PR_FALSE) &&
PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset - contentLen >= mContentOffset) ){
if ((aPos->mEatingWS && !isWhitespace) || !aPos->mEatingWS){
aPos->mContentOffset = aPos->mStartOffset - contentLen;
@ -4307,7 +4307,8 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
#endif // IBMBIDI
while (isWhitespace &&
tx.GetPrevWord(PR_FALSE, &wordLen, &contentLen,
&isWhitespace, PR_FALSE)){
&isWhitespace, PR_FALSE,
aPos->mIsKeyboardSelect)){
aPos->mContentOffset -= contentLen;
aPos->mEatingWS = PR_TRUE;
#ifdef IBMBIDI
@ -4342,7 +4343,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
#ifdef IBMBIDI
wordLen = (mState & NS_FRAME_IS_BIDI) ? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE) &&
if (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect) &&
(aPos->mStartOffset + contentLen <= (mContentLength + mContentOffset))){
if ((aPos->mEatingWS && isWhitespace) || !aPos->mEatingWS){
@ -4357,7 +4358,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE))
while (tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect))
{
if (aPos->mStartOffset + contentLen > (mContentLength + mContentOffset))
goto TryNextFrame;
@ -4379,7 +4380,7 @@ nsTextFrame::PeekOffset(nsIPresContext* aPresContext, nsPeekOffsetStruct *aPos)
wordLen = (mState & NS_FRAME_IS_BIDI)
? mContentOffset + mContentLength : -1;
#endif // IBMBIDI
while(tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE))
while(tx.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed, PR_TRUE, PR_FALSE, aPos->mIsKeyboardSelect))
{
if (aPos->mStartOffset + contentLen > (mContentLength + mContentOffset))
goto TryNextFrame;

Просмотреть файл

@ -110,8 +110,6 @@ static nsICaseConversion* gCaseConv = nsnull;
nsresult
nsTextTransformer::Initialize()
{
nsresult res = NS_OK;
// read in our global word selection prefs
if ( !sWordSelectPrefInited ) {
nsCOMPtr<nsIPrefBranch> prefBranch =
@ -123,8 +121,8 @@ nsTextTransformer::Initialize()
}
sWordSelectPrefInited = PR_TRUE;
}
return res;
return NS_OK;
}
static nsresult EnsureCaseConv()
{
@ -394,7 +392,8 @@ nsTextTransformer::ScanNormalAsciiText_F(PRInt32* aWordLen,
PRInt32
nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
PRBool* aWasTransformed)
PRBool* aWasTransformed,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
@ -414,9 +413,13 @@ nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
}
PRBool readingAlphaNumeric = PR_TRUE; //only used in sWordSelectStopAtPunctuation
//we must know if we are starting in alpha numerics.
// We must know if we are starting in alpha numerics.
// Treat high bit chars as alphanumeric, otherwise we get stuck on accented letters
// We can't trust isalnum() results for isalnum()
// Therefore we don't stop at non-ascii (high bit) punctuation,
// which is just fine. The punctuation we care about is low bit.
if (sWordSelectStopAtPunctuation && offset < fragLen)
readingAlphaNumeric = isalnum((unsigned char)*cp);
readingAlphaNumeric = isalnum((unsigned char)*cp) || !IS_ASCII_CHAR(*cp);
for (; offset < fragLen && !breakAfterThis; offset++) {
unsigned char ch = *cp++;
@ -431,8 +434,17 @@ nsTextTransformer::ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
else if (XP_IS_SPACE(ch)) {
break;
}
else if (sWordSelectStopAtPunctuation && ((readingAlphaNumeric && !isalnum(ch)) || (!readingAlphaNumeric && isalnum(ch)) )) {
// on some platforms, punctuation breaks words too.
else if (sWordSelectStopAtPunctuation &&
readingAlphaNumeric && !isalnum(ch) && IS_ASCII_CHAR(ch)) {
if (!aIsKeyboardSelect)
break;
// For keyboard move-by-word, need to pass by at least
// one alphanumeric char before stopping at punct
readingAlphaNumeric = PR_FALSE;
}
else if (sWordSelectStopAtPunctuation &&
!readingAlphaNumeric && (isalnum(ch) || !IS_ASCII_CHAR(ch))) {
// On some platforms, punctuation breaks for word selection
break;
}
else if (IS_DISCARDED(ch)) {
@ -817,7 +829,8 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
PRBool* aIsWhiteSpaceResult,
PRBool* aWasTransformed,
PRBool aResetTransformBuf,
PRBool aForLineBreak)
PRBool aForLineBreak,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 fragLen = frag->GetLength();
@ -910,7 +923,9 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
else {
if (!aForLineBreak)
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed);
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen,
aWasTransformed,
aIsKeyboardSelect);
else
offset = ScanNormalAsciiText_F(&wordLen, aWasTransformed);
}
@ -951,7 +966,8 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
}
else {
if (!aForLineBreak)
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed);
offset = ScanNormalAsciiText_F_ForWordBreak(&wordLen, aWasTransformed,
aIsKeyboardSelect);
else
offset = ScanNormalAsciiText_F(&wordLen, aWasTransformed);
}
@ -1091,13 +1107,20 @@ nsTextTransformer::ScanNormalWhiteSpace_B()
// wordlen==*aWordLen, contentlen=newOffset-currentOffset, isWhitespace=f
PRInt32
nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen)
nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen, PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 offset = mOffset;
PRUnichar* bp = mTransformBuf.GetBufferEnd();
PRUnichar* startbp = mTransformBuf.GetBuffer();
PRUnichar ch = frag->CharAt(offset - 1);
// Treat high bit chars as alphanumeric, otherwise we get stuck on accented letters
// We can't trust isalnum() results for isalnum()
// Therefore we don't stop at non-ascii (high bit) punctuation,
// which is just fine. The punctuation we care about is low bit.
PRBool readingAlphaNumeric = isalnum(ch) || !IS_ASCII_CHAR(ch);
while (--offset >= 0) {
PRUnichar ch = frag->CharAt(offset);
if (CH_NBSP == ch) {
@ -1109,6 +1132,18 @@ nsTextTransformer::ScanNormalAsciiText_B(PRInt32* aWordLen)
else if (IS_DISCARDED(ch)) {
continue;
}
else if (sWordSelectStopAtPunctuation && readingAlphaNumeric &&
!isalnum(ch) && IS_ASCII_CHAR(ch)) {
// Break on ascii punctuation
break;
}
else if (sWordSelectStopAtPunctuation && !readingAlphaNumeric &&
(isalnum(ch) || !IS_ASCII_CHAR(ch))) {
if (!aIsKeyboardSelect)
break;
readingAlphaNumeric = PR_TRUE;
}
if (ch > MAX_UNIBYTE) SetHasMultibyte(PR_TRUE);
if (bp == startbp) {
PRInt32 oldLength = mTransformBuf.mBufferLen;
@ -1297,7 +1332,8 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhiteSpaceResult,
PRBool aForLineBreak)
PRBool aForLineBreak,
PRBool aIsKeyboardSelect)
{
const nsTextFragment* frag = mFrag;
PRInt32 offset = mOffset;
@ -1343,7 +1379,7 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
offset = ScanNormalUnicodeText_B(aForLineBreak, &wordLen);
}
else {
offset = ScanNormalAsciiText_B(&wordLen);
offset = ScanNormalAsciiText_B(&wordLen, aIsKeyboardSelect);
}
break;
@ -1378,7 +1414,7 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
offset = ScanNormalUnicodeText_B(aForLineBreak, &wordLen);
}
else {
offset = ScanNormalAsciiText_B(&wordLen);
offset = ScanNormalAsciiText_B(&wordLen, aIsKeyboardSelect);
}
break;
}
@ -1657,7 +1693,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString uc2(st->text);
printf("%s forwards test: '", isAsciiTest ? "ascii" : "unicode");
fputs(NS_LossyConvertUCS2toASCII(uc2).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(uc2).get(), stdout);
printf("'\n");
}
tx.Init2(&frag, 0, preModeValue[preMode], NS_STYLE_TEXT_TRANSFORM_NONE);
@ -1672,7 +1708,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString tmp(bp, wordLen);
printf(" '");
fputs(NS_LossyConvertUCS2toASCII(tmp).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(tmp).get(), stdout);
printf("': ws=%s wordLen=%d (%d) contentLen=%d (offset=%d)\n",
ws ? "yes" : "no",
wordLen, *expectedResults, contentLen, tx.mOffset);
@ -1696,7 +1732,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString uc2(st->text);
printf("%s backwards test: '", isAsciiTest ? "ascii" : "unicode");
fputs(NS_LossyConvertUCS2toASCII(uc2).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(uc2).get(), stdout);
printf("'\n");
}
tx.Init2(&frag, frag.GetLength(), NS_STYLE_WHITESPACE_NORMAL,
@ -1710,7 +1746,7 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (gNoisy) {
nsAutoString tmp(bp, wordLen);
printf(" '");
fputs(NS_LossyConvertUCS2toASCII(tmp).get(), stdout);
fputs(NS_ConvertUCS2toUTF8(tmp).get(), stdout);
printf("': ws=%s wordLen=%d contentLen=%d (offset=%d)\n",
ws ? "yes" : "no",
wordLen, contentLen, tx.mOffset);
@ -1732,6 +1768,10 @@ nsTextTransformer::SelfTest(nsILineBreaker* aLineBreaker,
if (error) {
fprintf(stderr, "nsTextTransformer: self test %d failed\n", testNum);
}
else if (gNoisy) {
fprintf(stdout, "nsTextTransformer: self test %d succeeded\n", testNum);
}
testNum++;
}
}

Просмотреть файл

@ -73,6 +73,8 @@ class nsIWordBreaker;
|| ((_ch) >= CH_LRE && (_ch) <= CH_RLO))
#endif // IBMBIDI
#define IS_ASCII_CHAR(ch) ((ch&0xff80) == 0)
#define NS_TEXT_TRANSFORMER_AUTO_WORD_BUF_SIZE 128 // used to be 256
// Indicates whether the transformed text should be left as ascii
@ -184,13 +186,15 @@ public:
PRBool* aIsWhitespaceResult,
PRBool* aWasTransformed,
PRBool aResetTransformBuf = PR_TRUE,
PRBool aForLineBreak = PR_TRUE);
PRBool aForLineBreak = PR_TRUE,
PRBool aIsKeyboardSelect = PR_FALSE);
PRUnichar* GetPrevWord(PRBool aInWord,
PRInt32* aWordLenResult,
PRInt32* aContentLenResult,
PRBool* aIsWhitespaceResult,
PRBool aForLineBreak = PR_TRUE);
PRBool aForLineBreak = PR_TRUE,
PRBool aIsKeyboardSelect = PR_FALSE);
// Returns PR_TRUE if the LEAVE_AS_ASCII flag is set
@ -273,7 +277,8 @@ protected:
PRInt32 ScanNormalAsciiText_F(PRInt32* aWordLen,
PRBool* aWasTransformed);
PRInt32 ScanNormalAsciiText_F_ForWordBreak(PRInt32* aWordLen,
PRBool* aWasTransformed);
PRBool* aWasTransformed,
PRBool aIsKeyboardSelect);
PRInt32 ScanNormalUnicodeText_F(PRBool aForLineBreak,
PRInt32* aWordLen,
PRBool* aWasTransformed);
@ -285,7 +290,7 @@ protected:
// Helper methods for GetPrevWord (B == backwards)
PRInt32 ScanNormalWhiteSpace_B();
PRInt32 ScanNormalAsciiText_B(PRInt32* aWordLen);
PRInt32 ScanNormalAsciiText_B(PRInt32* aWordLen, PRBool aIsKeyboardSelect);
PRInt32 ScanNormalUnicodeText_B(PRBool aForLineBreak, PRInt32* aWordLen);
PRInt32 ScanPreWrapWhiteSpace_B(PRInt32* aWordLen);
PRInt32 ScanPreData_B(PRInt32* aWordLen);

Просмотреть файл

@ -174,7 +174,6 @@ pref("mail.windows_xp_integration.unread_count_interval", 300);
// override double-click word selection behavior.
pref("layout.word_select.eat_space_to_next_word", true);
pref("layout.word_select.stop_at_punctuation", false);
// print_extra_margin enables platforms to specify an extra gap or margin
// around the content of the page for Print Preview only