summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/e10s/browser_caching_text_bounds.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /accessible/tests/browser/e10s/browser_caching_text_bounds.js
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/tests/browser/e10s/browser_caching_text_bounds.js')
-rw-r--r--accessible/tests/browser/e10s/browser_caching_text_bounds.js549
1 files changed, 549 insertions, 0 deletions
diff --git a/accessible/tests/browser/e10s/browser_caching_text_bounds.js b/accessible/tests/browser/e10s/browser_caching_text_bounds.js
new file mode 100644
index 0000000000..0f50599293
--- /dev/null
+++ b/accessible/tests/browser/e10s/browser_caching_text_bounds.js
@@ -0,0 +1,549 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* import-globals-from ../../mochitest/layout.js */
+loadScripts({ name: "layout.js", dir: MOCHITESTS_DIR });
+
+async function testTextNode(accDoc, browser, id) {
+ await testTextRange(accDoc, browser, id, 0, -1);
+}
+
+async function testChar(accDoc, browser, id, idx) {
+ await testTextRange(accDoc, browser, id, idx, idx + 1);
+}
+
+async function testTextRange(accDoc, browser, id, start, end) {
+ const r = await invokeContentTask(
+ browser,
+ [id, start, end],
+ (_id, _start, _end) => {
+ const htNode = content.document.getElementById(_id);
+ let [eX, eY, eW, eH] = [
+ Number.MAX_SAFE_INTEGER,
+ Number.MAX_SAFE_INTEGER,
+ 0,
+ 0,
+ ];
+ let traversed = 0;
+ let localStart = _start;
+ let endTraversal = false;
+ for (let element of htNode.childNodes) {
+ // ignore whitespace, but not embedded elements
+ let isEmbeddedElement = false;
+ if (element.length == undefined) {
+ let potentialTextContainer = element;
+ while (
+ potentialTextContainer &&
+ potentialTextContainer.length == undefined
+ ) {
+ potentialTextContainer = element.firstChild;
+ }
+ if (potentialTextContainer && potentialTextContainer.length) {
+ // If we can reach some text from this container, use that as part
+ // of our range. This is important when testing with intervening inline
+ // elements. ie. <pre><code>ab%0acd
+ element = potentialTextContainer;
+ } else if (element.firstChild) {
+ isEmbeddedElement = true;
+ } else {
+ continue;
+ }
+ }
+ if (element.length + traversed < _start) {
+ // If our start index is not within this
+ // node, keep looking.
+ traversed += element.length;
+ localStart -= element.length;
+ continue;
+ }
+
+ let rect;
+ if (isEmbeddedElement) {
+ rect = element.getBoundingClientRect();
+ } else {
+ const range = content.document.createRange();
+ range.setStart(element, localStart);
+
+ if (_end != -1 && _end - traversed <= element.length) {
+ // If the current node contains
+ // our end index, stop here.
+ endTraversal = true;
+ range.setEnd(element, _end - traversed);
+ } else {
+ range.setEnd(element, element.length);
+ }
+
+ rect = range.getBoundingClientRect();
+ }
+
+ const oldX = eX == Number.MAX_SAFE_INTEGER ? 0 : eX;
+ const oldY = eY == Number.MAX_SAFE_INTEGER ? 0 : eY;
+ eX = Math.min(eX, rect.x);
+ eY = Math.min(eY, rect.y);
+ eW = Math.abs(Math.max(oldX + eW, rect.x + rect.width) - eX);
+ eH = Math.abs(Math.max(oldY + eH, rect.y + rect.height) - eY);
+
+ if (endTraversal) {
+ break;
+ }
+ localStart = 0;
+ traversed += element.length;
+ }
+ return [Math.round(eX), Math.round(eY), Math.round(eW), Math.round(eH)];
+ }
+ );
+ let hyperTextNode = findAccessibleChildByID(accDoc, id);
+
+ // test against parent-relative coords, because getBoundingClientRect
+ // is relative to the document, not the screen. this won't work on nested
+ // elements (ie. any hypertext whose parent is not the doc).
+ if (end != -1 && end - start == 1) {
+ // If we're only testing a character, use this function because it calls
+ // CharBounds() directly instead of TextBounds().
+ testTextPos(hyperTextNode, start, [r[0], r[1]], COORDTYPE_PARENT_RELATIVE);
+ } else {
+ testTextBounds(hyperTextNode, start, end, r, COORDTYPE_PARENT_RELATIVE);
+ }
+}
+
+/**
+ * Test the text range boundary for simple LtR text
+ */
+addAccessibleTask(
+ `
+ <p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
+ <p id='p2' style='font-family: monospace;'>ل</p>
+ <p id='p3' dir='ltr' style='font-family: monospace;'>Привіт Світ</p>
+ <pre id='p4' style='font-family: monospace;'>a%0abcdef</pre>
+ `,
+ async function(browser, accDoc) {
+ info("Testing simple LtR text");
+ if (isWinNoCache) {
+ ok(true, "skipping tests, running on windows without cache");
+ // We have to do this in at least one of these sub-tasks because
+ // otherwise the test harness complains this file is empty when
+ // it runs on windows without the cache enabled.
+ return;
+ }
+
+ await testTextNode(accDoc, browser, "p1");
+ await testTextNode(accDoc, browser, "p2");
+ await testTextNode(accDoc, browser, "p3");
+ await testTextNode(accDoc, browser, "p4");
+ },
+ {
+ iframe: true,
+ }
+);
+
+/**
+ * Test the partial text range boundary for LtR text
+ */
+addAccessibleTask(
+ `
+ <p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
+ <p id='p2' dir='ltr' style='font-family: monospace;'>Привіт Світ</p>
+ `,
+ async function(browser, accDoc) {
+ info("Testing partial ranges in LtR text");
+ await testTextRange(accDoc, browser, "p1", 0, 4);
+ await testTextRange(accDoc, browser, "p1", 2, 8);
+ await testTextRange(accDoc, browser, "p1", 12, 17);
+ await testTextRange(accDoc, browser, "p2", 0, 4);
+ await testTextRange(accDoc, browser, "p2", 2, 8);
+ await testTextRange(accDoc, browser, "p2", 6, 11);
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test the text boundary for multiline LtR text
+ */
+addAccessibleTask(
+ `
+ <p id='p4' dir='ltr' style='font-family: monospace;'>Привіт Світ<br>Привіт Світ</p>
+ <p id='p5' dir='ltr' style='font-family: monospace;'>Привіт Світ<br> Я ще трохи тексту в другому рядку</p>
+ <p id='p6' style='font-family: monospace;'>hello world I'm on line one<br> and I'm a separate line two with slightly more text</p>
+ <p id='p7' style='font-family: monospace;'>hello world<br>hello world</p>
+ `,
+ async function(browser, accDoc) {
+ info("Testing multiline LtR text");
+ await testTextNode(accDoc, browser, "p4");
+ await testTextNode(accDoc, browser, "p5");
+ // await testTextNode(accDoc, browser, "p6"); // w/o cache, fails width (a 259, e 250), w/ cache wrong w, h in iframe (line wrapping)
+ await testTextNode(accDoc, browser, "p7");
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test the text boundary for simple RtL text
+ */
+addAccessibleTask(
+ `
+ <p id='p1' dir='rtl' style='font-family: monospace;'>Tilimilitryamdiya</p>
+ <p id='p2' dir='rtl' style='font-family: monospace;'>ل</p>
+ <p id='p3' dir='rtl' style='font-family: monospace;'>لل لللل لل</p>
+ <pre id='p4' dir='rtl' style='font-family: monospace;'>a%0abcdef</pre>
+ `,
+ async function(browser, accDoc) {
+ info("Testing simple RtL text");
+ await testTextNode(accDoc, browser, "p1");
+ await testTextNode(accDoc, browser, "p2");
+ await testTextNode(accDoc, browser, "p3");
+ await testTextNode(accDoc, browser, "p4");
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test the text boundary for multiline RtL text
+ */
+addAccessibleTask(
+ `
+ <p id='p4' dir='rtl' style='font-family: monospace;'>لل لللل لل<br>لل لللل لل</p>
+ <p id='p5' dir='rtl' style='font-family: monospace;'>لل لللل لل<br> لل لل لل لل ل لل لل لل</p>
+ <p id='p6' dir='rtl' style='font-family: monospace;'>hello world I'm on line one<br> and I'm a separate line two with slightly more text</p>
+ <p id='p7' dir='rtl' style='font-family: monospace;'>hello world<br>hello world</p>
+ `,
+ async function(browser, accDoc) {
+ info("Testing multiline RtL text");
+ await testTextNode(accDoc, browser, "p4");
+ if (!isCacheEnabled) {
+ await testTextNode(accDoc, browser, "p5"); // w/ cache fails x, w - off by one char
+ }
+ // await testTextNode(accDoc, browser, "p6"); // w/o cache, fails width (a 259, e 250), w/ cache fails w, h in iframe (line wrapping)
+ await testTextNode(accDoc, browser, "p7");
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test the partial text range boundary for RtL text
+ */
+addAccessibleTask(
+ `
+ <p id='p1' dir='rtl' style='font-family: monospace;'>Tilimilitryamdiya</p>
+ <p id='p2' dir='rtl' style='font-family: monospace;'>لل لللل لل</p>
+ `,
+ async function(browser, accDoc) {
+ info("Testing partial ranges in RtL text");
+ await testTextRange(accDoc, browser, "p1", 0, 4);
+ await testTextRange(accDoc, browser, "p1", 2, 8);
+ await testTextRange(accDoc, browser, "p1", 12, 17);
+ await testTextRange(accDoc, browser, "p2", 0, 4);
+ await testTextRange(accDoc, browser, "p2", 2, 8);
+ await testTextRange(accDoc, browser, "p2", 6, 10);
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test simple vertical text in rl and lr layouts
+ */
+addAccessibleTask(
+ `
+ <div style="writing-mode: vertical-rl;">
+ <p id='p1'>你好世界</p>
+ <p id='p2'>hello world</p>
+ <br>
+ <p id='p3'>こんにちは世界</p>
+ </div>
+ <div style="writing-mode: vertical-lr;">
+ <p id='p4'>你好世界</p>
+ <p id='p5'>hello world</p>
+ <br>
+ <p id='p6'>こんにちは世界</p>
+ </div>
+ `,
+ async function(browser, accDoc) {
+ info("Testing vertical-rl");
+ await testTextNode(accDoc, browser, "p1");
+ await testTextNode(accDoc, browser, "p2");
+ await testTextNode(accDoc, browser, "p3");
+ info("Testing vertical-lr");
+ await testTextNode(accDoc, browser, "p4");
+ await testTextNode(accDoc, browser, "p5");
+ await testTextNode(accDoc, browser, "p6");
+ },
+ {
+ topLevel: isCacheEnabled,
+ iframe: isCacheEnabled,
+ }
+);
+
+/**
+ * Test multiline vertical-rl text
+ */
+addAccessibleTask(
+ `
+ <p id='p1' style='writing-mode: vertical-rl;'>你好世界<br>你好世界</p>
+ <p id='p2' style='writing-mode: vertical-rl;'>hello world<br>hello world</p>
+ <br>
+ <p id='p3' style='writing-mode: vertical-rl;'>你好世界<br> 你好世界 你好世界</p>
+ <p id='p4' style='writing-mode: vertical-rl;'>hello world<br> hello world hello world</p>
+ `,
+ async function(browser, accDoc) {
+ info("Testing vertical-rl multiline");
+ await testTextNode(accDoc, browser, "p1");
+ await testTextNode(accDoc, browser, "p2");
+ await testTextNode(accDoc, browser, "p3");
+ // await testTextNode(accDoc, browser, "p4"); // off by 4 with caching, iframe
+ },
+ {
+ topLevel: isCacheEnabled,
+ iframe: isCacheEnabled,
+ }
+);
+
+/**
+ * Test text with embedded chars
+ */
+addAccessibleTask(
+ `<p id='p1' style='font-family: monospace;'>hello <a href="google.com">world</a></p>
+ <p id='p2' style='font-family: monospace;'>hello<br><a href="google.com">world</a></p>
+ <div id='d3'><p></p>hello world</div>
+ <div id='d4'>hello world<p></p></div>
+ <div id='d5'>oh<p></p>hello world</div>`,
+ async function(browser, accDoc) {
+ info("Testing embedded chars");
+ await testTextNode(accDoc, browser, "p1");
+ await testTextNode(accDoc, browser, "p2");
+ await testTextNode(accDoc, browser, "d3");
+ await testTextNode(accDoc, browser, "d4");
+ await testTextNode(accDoc, browser, "d5");
+ },
+ {
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test bounds after text mutations.
+ */
+addAccessibleTask(
+ `<p id="p">a</p>`,
+ async function(browser, docAcc) {
+ await testTextNode(docAcc, browser, "p");
+ const p = findAccessibleChildByID(docAcc, "p");
+ info("Appending a character to text leaf");
+ let textInserted = waitForEvent(EVENT_TEXT_INSERTED, p);
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById("p").firstChild.data = "ab";
+ });
+ await textInserted;
+ await testTextNode(docAcc, browser, "p");
+ },
+ {
+ chrome: true,
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test character bounds on the insertion point at the end of a text box.
+ */
+addAccessibleTask(
+ `<input id="input" value="a">`,
+ async function(browser, docAcc) {
+ const input = findAccessibleChildByID(docAcc, "input");
+ testTextPos(input, 1, [0, 0], COORDTYPE_SCREEN_RELATIVE);
+ },
+ {
+ chrome: true,
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test character bounds after non-br line break.
+ */
+addAccessibleTask(
+ `
+ <style>
+ @font-face {
+ font-family: Ahem;
+ src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs);
+ }
+ pre {
+ font: 20px/20px Ahem;
+ }
+ </style>
+ <pre id="t">XX
+XXX</pre>`,
+ async function(browser, docAcc) {
+ await testChar(docAcc, browser, "t", 3);
+ },
+ {
+ chrome: true,
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test character bounds in a pre with padding.
+ */
+addAccessibleTask(
+ `
+ <style>
+ @font-face {
+ font-family: Ahem;
+ src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs);
+ }
+ pre {
+ font: 20px/20px Ahem;
+ padding: 20px;
+ }
+ </style>
+ <pre id="t">XX
+XXX</pre>`,
+ async function(browser, docAcc) {
+ await testTextNode(docAcc, browser, "t");
+ await testChar(docAcc, browser, "t", 3);
+ },
+ {
+ chrome: true,
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+/**
+ * Test text bounds with an invalid end offset.
+ */
+addAccessibleTask(
+ `<p id="p">a</p>`,
+ async function(browser, docAcc) {
+ const p = findAccessibleChildByID(docAcc, "p");
+ testTextBounds(p, 0, 2, [0, 0, 0, 0], COORDTYPE_SCREEN_RELATIVE);
+ },
+ { chrome: true, topLevel: !isWinNoCache }
+);
+
+/**
+ * Test character bounds in an intervening inline element with non-br line breaks
+ */
+addAccessibleTask(
+ `
+ <style>
+ @font-face {
+ font-family: Ahem;
+ src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs);
+ }
+ pre {
+ font: 20px/20px Ahem;
+ }
+ </style>
+ <pre id="t"><code>XX
+XXX
+XX
+X</pre>`,
+ async function(browser, docAcc) {
+ await testChar(docAcc, browser, "t", 0);
+ await testChar(docAcc, browser, "t", 3);
+ await testChar(docAcc, browser, "t", 7);
+ await testChar(docAcc, browser, "t", 10);
+ },
+ {
+ chrome: true,
+ topLevel: !isWinNoCache,
+ iframe: !isWinNoCache,
+ }
+);
+
+// XXX: There's a fuzziness here of about 8 pixels, implying we aren't taking into
+// account some kind of margin or padding. See bug 1809695.
+// /**
+// * Test character bounds in an intervening inline element with margins
+// * and with non-br line breaks
+// */
+// addAccessibleTask(
+// `
+// <style>
+// @font-face {
+// font-family: Ahem;
+// src: url(${CURRENT_CONTENT_DIR}e10s/fonts/Ahem.sjs);
+// }
+// </style>
+// <div>hello<pre id="t" style="margin-left:100px;margin-top:30px;background-color:blue;">XX
+// XXX
+// XX
+// X</pre></div>`,
+// async function(browser, docAcc) {
+// await testChar(docAcc, browser, "t", 0);
+// await testChar(docAcc, browser, "t", 3);
+// await testChar(docAcc, browser, "t", 7);
+// await testChar(docAcc, browser, "t", 10);
+// },
+// {
+// chrome: true,
+// topLevel: !isWinNoCache,
+// iframe: !isWinNoCache,
+// }
+// );
+
+/**
+ * Test text bounds in a textarea after scrolling.
+ */
+addAccessibleTask(
+ `
+<textarea id="textarea" rows="1">a
+b
+c</textarea>
+ `,
+ async function(browser, docAcc) {
+ // We can't use testChar because Range.getBoundingClientRect isn't supported
+ // inside textareas.
+ const textarea = findAccessibleChildByID(docAcc, "textarea");
+ textarea.QueryInterface(nsIAccessibleText);
+ const oldY = {};
+ textarea.getCharacterExtents(
+ 4,
+ {},
+ oldY,
+ {},
+ {},
+ COORDTYPE_SCREEN_RELATIVE
+ );
+ info("Moving textarea caret to c");
+ await invokeContentTask(browser, [], () => {
+ const textareaDom = content.document.getElementById("textarea");
+ textareaDom.focus();
+ textareaDom.selectionStart = 4;
+ });
+ await waitForContentPaint(browser);
+ const newY = {};
+ textarea.getCharacterExtents(
+ 4,
+ {},
+ newY,
+ {},
+ {},
+ COORDTYPE_SCREEN_RELATIVE
+ );
+ ok(newY.value < oldY.value, "y coordinate smaller after scrolling down");
+ },
+ { chrome: true, topLevel: !isWinNoCache, iframe: !isWinNoCache }
+);