| <!DOCTYPE html> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <style> |
| div.test { |
| font-size: 20px; |
| width: 120px; |
| } |
| </style> |
| <body> |
| <script> |
| // This file tests the consistency between hit test and caret displaying that, |
| // caret must be displayed at the exact location where mouse is clicked. |
| |
| const kErrorThreshold = 2; |
| |
| function computeExpectedCaretRect(container, characterIndex, side) { |
| const range = container.ownerDocument.createRange(); |
| range.setStart(container.firstChild, characterIndex); |
| range.setEnd(container.firstChild, characterIndex + 1); |
| const rect = range.getBoundingClientRect(); |
| |
| if (side == 'left') |
| return {x: rect.left, top: rect.top, height: rect.height}; |
| return {x: rect.right, top: rect.top, height: rect.height}; |
| } |
| |
| function clickAt(container, characterIndex, side) { |
| const caretRect = computeExpectedCaretRect(container, characterIndex, side); |
| |
| const xDelta = side === 'left' ? kErrorThreshold : -kErrorThreshold; |
| const x = caretRect.x + xDelta; |
| const y = caretRect.top + caretRect.height / 2; |
| |
| return new Promise((resolve, reject) => { |
| assert_own_property(window, 'chrome'); |
| assert_own_property(window.chrome, 'gpuBenchmarking'); |
| |
| chrome.gpuBenchmarking.pointerActionSequence([{ |
| source: 'mouse', |
| actions: [ |
| {name: 'pointerDown', x: x, y: y}, |
| {name: 'pointerUp'} |
| ]}], resolve); |
| }); |
| } |
| |
| function assertCaretLocation(container, characterIndex, side) { |
| const expectedCaretRect = computeExpectedCaretRect(container, characterIndex, side); |
| const actualCaretRect = internals.absoluteCaretBounds(); |
| |
| assert_approx_equals(actualCaretRect.x, expectedCaretRect.x, kErrorThreshold); |
| assert_approx_equals(actualCaretRect.top, expectedCaretRect.top, kErrorThreshold); |
| } |
| |
| tests = [ |
| // Rendered as "foo CBA" in LTR block. Click the right edge of "A". |
| {html: 'foo \u05D0\u05D1\u05D2', dir: 'ltr', index: 5, side: 'right', name: 'Bidi after collapsed space LTR'}, |
| // Rendered as "foo CBA" in RTL block. Click the left edge of "f". |
| {html: '\u05D0\u05D1\u05D2 foo', dir: 'rtl', index: 5, side: 'left', name: 'Bidi after collapsed space RTL'}, |
| // Rendered as two lines in LTR block: |
| // "foo CBA" |
| // "LKJIHGFED" |
| // Click the left edge of "L". |
| {html: 'foo \u05D0\u05D1\u05D2 \u05D3\u05D4\u05D5\u05D6\u05D7\u05D8\u05D9\u05DA\u05DB', |
| dir: 'ltr', index: 16, side: 'left', name: 'End of RTL text in LTR block after line wrap'}, |
| // Same sample as above. Click the left edge of "C". |
| {html: 'foo \u05D0\u05D1\u05D2 \u05D3\u05D4\u05D5\u05D6\u05D7\u05D8\u05D9\u05DA\u05DB', |
| dir: 'ltr', index: 7, side: 'left', name: 'Logical line end in LTR block before line wrap'}, |
| // Rendered as two lines in RTL block: |
| // "foo CBA" |
| // "abcdefghijklmn" |
| // Click the right edge of "n". |
| {html: '\u05D0\u05D1\u05D2 foo abcdefghijklmn', |
| dir: 'rtl', index: 22, side: 'right', name: 'End of LTR text in RTL block after line wrap'}, |
| // Same sample as above. Click the right edge of "foo". |
| {html: '\u05D0\u05D1\u05D2 foo abcdefghijklmn', |
| dir: 'rtl', index: 7, side: 'right', name: 'Logical line end in RTL block before line wrap'}, |
| ]; |
| |
| function runTest(testCase) { |
| const html = testCase.html; |
| const dir = testCase.dir; |
| const index = testCase.index; |
| const side = testCase.side; |
| const name = testCase.name; |
| promise_test(async () => { |
| const container = document.createElement('div'); |
| container.classList.add('test'); |
| container.contentEditable = 'true'; |
| container.dir = dir; |
| container.innerHTML = html; |
| document.body.appendChild(container); |
| |
| await clickAt(container, index, side); |
| assertCaretLocation(container, index, side); |
| }, name); |
| } |
| |
| tests.forEach(runTest); |
| </script> |
| </body> |