Move caret to correct position when dir=auto for space and LTR text following RTL text.

In getPositionAndOffset, previous block was used when space is entered for dir=auto. While for dir=auto text using previous block gives wrong caret position, which was leading to caret offset not calculated.  In case of RTL, previous inline box position is used.

Since auto scenario, combines RTL and LTR text. In renderText, only render block direction is used. New condition has been added in RenderText to test if dir=auto, then use inlineBlock bidiLevel to decide about caret position rendering.

R=leviw, eae
BUG=296847
TEST=Direction auto tests covering move caret position to the right when
LTR text is entered and adding RTL text to move caret to the left.

Review URL: https://codereview.chromium.org/541823003

git-svn-id: svn://svn.chromium.org/blink/trunk@181701 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 7f57426c
Tests various scenarios for caret position when direction is auto
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS textarea.value is "א!"
1. Caret is at right if text is in LTR direction
PASS textarea.value is "א!\nhello"
Compares lines if they are different
PASS beforeCaretPos[1] is not afterCaretPos[1]
New text is in LTR direction, start of caret will differ
PASS beforeCaretPos[0] is > afterCaretPos[0]
2. Addition of RTL text in middle of LTR text, caret moves to the left of the line.
PASS textarea.value is "א!\nhelloאא"
RTL text added will be move caret to start of position where hello begins
PASS beforeCaretPos[0] is afterCaretPos[0]+afterCaretPos[2]
3. Adding LTR text after RTL should move caret towards right.
PASS textarea.value is "א!\nhelloאאbye"
Start position of caret is same
PASS beforeCaretPos[0]+beforeCaretPos[2] is afterCaretPos[0]
But end position differs
PASS beforeCaretPos[0]+beforeCaretPos[2] is not afterCaretPos[0]+afterCaretPos[2]
4. Adding space, caret should move caret
PASS textarea.value is "א!\nhelloאאbye "
PASS afterCaretPos[0]+afterCaretPos[2] is > beforeCaretPos[0]+beforeCaretPos[2]
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="../../resources/js-test.js"></script>
<textarea id="textarea" dir="auto" style="font-size: 20px; width: 20ex; border: solid thin black; padding: 10px;">&#x05d0;!</textarea>
<script>
description('Tests various scenarios for caret position when direction is auto');
var text = document.getElementById('textarea');
var beforeCaretPos, afterCaretPos;
text.focus();
shouldBeEqualToString('textarea.value', 'א!');
debug('1. Caret is at right if text is in LTR direction');
beforeCaretPos = textInputController.firstRectForCharacterRange(0, 3);
testRunner.execCommand('MoveToEndOfLine');
document.execCommand('InsertLineBreak');
document.execCommand('InsertText', false, 'hello');
afterCaretPos = textInputController.firstRectForCharacterRange(4, 5);
shouldBeEqualToString('textarea.value', 'א!\nhello');
debug('Compares lines if they are different');
shouldNotBe('beforeCaretPos[1]', 'afterCaretPos[1]');
debug('New text is in LTR direction, start of caret will differ');
shouldBeGreaterThan('beforeCaretPos[0]', 'afterCaretPos[0]');
debug('2. Addition of RTL text in middle of LTR text, caret moves to the left of the line.');
beforeCaretPos = afterCaretPos;
document.execCommand('InsertText', false, '\u05d0\u05d0');
afterCaretPos = textInputController.firstRectForCharacterRange(4, 7);
shouldBeEqualToString('textarea.value', 'א!\nhelloאא');
debug('RTL text added will be move caret to start of position where hello begins');
shouldBe('beforeCaretPos[0]', 'afterCaretPos[0]+afterCaretPos[2]');
debug('3. Adding LTR text after RTL should move caret towards right.');
beforeCaretPos = afterCaretPos;
document.execCommand('InsertText', false, 'bye');
afterCaretPos = textInputController.firstRectForCharacterRange(4, 10);
shouldBeEqualToString('textarea.value', 'א!\nhelloאאbye');
debug('Start position of caret is same');
shouldBe('beforeCaretPos[0]+beforeCaretPos[2]', 'afterCaretPos[0]');
debug('But end position differs');
shouldNotBe('beforeCaretPos[0]+beforeCaretPos[2]', 'afterCaretPos[0]+afterCaretPos[2]');
debug('4. Adding space, caret should move caret');
beforeCaretPos = afterCaretPos;
document.execCommand('InsertText', false, ' ');
afterCaretPos = textInputController.firstRectForCharacterRange(4, 11);
shouldBeEqualToString('textarea.value', 'א!\nhelloאאbye ');
shouldBeGreaterThan('afterCaretPos[0]+afterCaretPos[2]', 'beforeCaretPos[0]+beforeCaretPos[2]');
</script>
Test caret position in a textarea with direction auto and having RTL text. When entering a LTR text caret position is changed.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS caretRect[0] is not caretRect1[0]
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<script src="../../resources/js-test.js"></script>
<textarea id="textarea" dir="auto" style="font-size: 20px; width: 20ex; border: solid thin black; padding: 10px;">&#x05d0;!</textarea>
<script>
description('Test caret position in a textarea with direction auto and having RTL text. When entering a LTR text caret position is changed.');
var textarea = document.getElementById('textarea');
textarea.focus();
var caretRect = textInputController.firstRectForCharacterRange(0, 0);
window.testRunner.execCommand('MoveToEndOfLine');
document.execCommand('InsertLineBreak');
document.execCommand('InsertText', false, 'hell');
var caretRect1 = textInputController.firstRectForCharacterRange(1, 0);
shouldNotBe('caretRect[0]', 'caretRect1[0]');
</script>
......@@ -1188,6 +1188,11 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
}
caretOffset = inlineBox->caretLeftmostOffset();
}
} else if (m_anchorNode->selfOrAncestorHasDirAutoAttribute()) {
if (inlineBox->bidiLevel() < level)
caretOffset = inlineBox->caretLeftmostOffset();
else
caretOffset = inlineBox->caretRightmostOffset();
} else {
InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
if (!nextBox || nextBox->bidiLevel() < level) {
......@@ -1197,10 +1202,7 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
break;
inlineBox = prevBox;
}
if (m_anchorNode->selfOrAncestorHasDirAutoAttribute())
caretOffset = inlineBox->bidiLevel() < level ? inlineBox->caretLeftmostOffset() : inlineBox->caretRightmostOffset();
else
caretOffset = inlineBox->caretLeftmostOffset();
caretOffset = inlineBox->caretLeftmostOffset();
} else if (nextBox->bidiLevel() > level) {
// Left edge of a "tertiary" run. Set to the right edge of that run.
while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
......
......@@ -694,6 +694,12 @@ LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, Lay
break;
}
// for dir=auto, use inlineBoxBidiLevel() to test the correct direction for the cursor.
if (rightAligned && (node() && node()->selfOrAncestorHasDirAutoAttribute())) {
if (inlineBox->bidiLevel()%2 != 1)
rightAligned = false;
}
if (rightAligned) {
left = std::max(left, leftEdge);
left = std::min(left, rootRight - caretWidth);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment