Bug 240933 - Part 3: Correct the caret movement throughout textareas (and pre elements with caret browsing turned on as well); r=roc a=dbaron

--HG--
extra : rebase_source : 9f015607bc84a11137ab11ba47c14e98c20e3970
This commit is contained in:
Ehsan Akhgari 2010-07-13 21:49:16 -04:00
Родитель 93e95a8bd1
Коммит 8de2c3cb19
4 изменённых файлов: 88 добавлений и 22 удалений

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

@ -5348,6 +5348,7 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
{ {
PRBool eatingNonRenderableWS = PR_FALSE; PRBool eatingNonRenderableWS = PR_FALSE;
PRBool done = PR_FALSE; PRBool done = PR_FALSE;
PRBool jumpedLine = PR_FALSE;
while (!done) { while (!done) {
PRBool movingInFrameDirection = PRBool movingInFrameDirection =
@ -5359,7 +5360,6 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
done = current->PeekOffsetCharacter(movingInFrameDirection, &offset); done = current->PeekOffsetCharacter(movingInFrameDirection, &offset);
if (!done) { if (!done) {
PRBool jumpedLine;
result = result =
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual, current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
aPos->mJumpLines, aPos->mScrollViewStop, aPos->mJumpLines, aPos->mScrollViewStop,
@ -5380,6 +5380,15 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
aPos->mResultContent = range.content; aPos->mResultContent = range.content;
// Output offset is relative to content, not frame // Output offset is relative to content, not frame
aPos->mContentOffset = offset < 0 ? range.end : range.start + offset; aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
// If we're dealing with a text frame and moving backward positions us at
// the end of that line, decrease the offset by one to make sure that
// we're placed before the linefeed character on the previous line.
if (offset < 0 && jumpedLine &&
aPos->mDirection == eDirPrevious &&
current->GetStyleText()->NewlineIsSignificant() &&
current->HasTerminalNewline()) {
--aPos->mContentOffset;
}
break; break;
} }

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

@ -5425,8 +5425,7 @@ IsAcceptableCaretPosition(const gfxSkipCharsIterator& aIter, gfxTextRun* aTextRu
PRUint32 index = aIter.GetSkippedOffset(); PRUint32 index = aIter.GetSkippedOffset();
if (!aTextRun->IsClusterStart(index)) if (!aTextRun->IsClusterStart(index))
return PR_FALSE; return PR_FALSE;
return !(aFrame->GetStyleText()->NewlineIsSignificant() && return PR_TRUE;
aTextRun->GetChar(index) == '\n');
} }
PRBool PRBool
@ -5451,8 +5450,8 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset);
if (!aForward) { if (!aForward) {
PRInt32 i; // If at the beginning of the line, look at the previous continuation
for (i = NS_MIN(trimmed.GetEnd(), startOffset) - 1; for (PRInt32 i = NS_MIN(trimmed.GetEnd(), startOffset) - 1;
i >= trimmed.mStart; --i) { i >= trimmed.mStart; --i) {
iter.SetOriginalOffset(i); iter.SetOriginalOffset(i);
if (IsAcceptableCaretPosition(iter, mTextRun, this)) { if (IsAcceptableCaretPosition(iter, mTextRun, this)) {
@ -5462,16 +5461,19 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
} }
*aOffset = 0; *aOffset = 0;
} else { } else {
PRInt32 i; // If we're at the end of a line, look at the next continuation
for (i = startOffset + 1; i <= trimmed.GetEnd(); ++i) { iter.SetOriginalOffset(startOffset);
iter.SetOriginalOffset(i); if (iter.GetSkippedOffset() <= PRUint32(trimmed.GetEnd()) &&
// XXX we can't necessarily stop at the end of this frame, !(iter.GetSkippedOffset() < PRUint32(trimmed.GetEnd()) &&
// but we really have no choice right now. We need to do a deeper GetStyleText()->NewlineIsSignificant() &&
// fix/restructuring of PeekOffsetCharacter mTextRun->GetChar(iter.GetSkippedOffset()) == '\n')) {
if (i == trimmed.GetEnd() || for (PRInt32 i = startOffset + 1; i <= trimmed.GetEnd(); ++i) {
IsAcceptableCaretPosition(iter, mTextRun, this)) { iter.SetOriginalOffset(i);
*aOffset = i - mContentOffset; if (i == trimmed.GetEnd() ||
return PR_TRUE; IsAcceptableCaretPosition(iter, mTextRun, this)) {
*aOffset = i - mContentOffset;
return PR_TRUE;
}
} }
} }
*aOffset = contentLength; *aOffset = contentLength;

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

@ -18,6 +18,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=288789
&#x05d0;a&#x05d1; &#x05d0;a&#x05d1;
</textarea>
<textarea id="tb">
abc
</textarea> </textarea>
</div> </div>
<pre id="test"> <pre id="test">
@ -50,9 +55,59 @@ function test() {
textarea.focus(); textarea.focus();
collapse(0); collapse(0);
testLeft(1); ok(true, "Testing forward movement in RTL mode");
collapse(5); for (var i = 0; i < textarea.textContent.length; ++i) {
testRight(4); if (i == 0) {
testRight(i);
}
if (textarea.textContent[i] == 'a') {
testLeft(i);
} else {
testLeft(i + 1);
}
if (i == textarea.textContent.length - 1) {
testLeft(i + 1);
}
}
ok(true, "Testing backward movement in RTL mode");
for (var i = textarea.textContent.length; i > 0; --i) {
if (i == textarea.textContent.length) {
testLeft(i);
}
if (i > 0 && textarea.textContent[i - 1] == 'a') {
testRight(i);
} else {
testRight(i - 1);
}
if (i == 1) {
testRight(i - 1);
}
}
textarea = $("tb");
textarea.focus();
collapse(0);
ok(true, "Testing forward movement in LTR mode");
for (var i = 0; i < textarea.textContent.length; ++i) {
if (i == 0) {
testLeft(i);
}
testRight(i + 1);
if (i == textarea.textContent.length - 1) {
testRight(i + 1);
}
}
ok(true, "Testing backward movement in LTR mode");
for (var i = textarea.textContent.length; i > 0; --i) {
if (i == textarea.textContent.length) {
testRight(i);
}
testLeft(i - 1);
if (i == 1) {
testLeft(i - 1);
}
}
SimpleTest.finish(); SimpleTest.finish();
} }

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

@ -68,13 +68,13 @@ function test() {
editor.innerHTML = "<pre>aa\nbb</pre>"; editor.innerHTML = "<pre>aa\nbb</pre>";
sel.collapse(editor.firstChild.firstChild, 0); sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 1); testRight(editor.firstChild.firstChild, 1);
// at the 'bb' but HINTLEFT so appears at the end of the first line // at the end of the first line, before the \n
testRight(editor.firstChild.firstChild, 3); testRight(editor.firstChild.firstChild, 2);
testRight(editor.firstChild.firstChild, 3); testRight(editor.firstChild.firstChild, 3);
testRight(editor.firstChild.firstChild, 4); testRight(editor.firstChild.firstChild, 4);
testLeft(editor.firstChild.firstChild, 3); testLeft(editor.firstChild.firstChild, 3);
// at the 'bb' but HINTLEFT so appears at the end of the first line // at the end of the first line, before the \n
testLeft(editor.firstChild.firstChild, 3); testLeft(editor.firstChild.firstChild, 2);
testLeft(editor.firstChild.firstChild, 1); testLeft(editor.firstChild.firstChild, 1);
testLeft(editor.firstChild.firstChild, 0); testLeft(editor.firstChild.firstChild, 0);