summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/bounds/browser_test_iframe_transform.js
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/browser/bounds/browser_test_iframe_transform.js')
-rw-r--r--accessible/tests/browser/bounds/browser_test_iframe_transform.js209
1 files changed, 209 insertions, 0 deletions
diff --git a/accessible/tests/browser/bounds/browser_test_iframe_transform.js b/accessible/tests/browser/bounds/browser_test_iframe_transform.js
new file mode 100644
index 0000000000..a44ab75faf
--- /dev/null
+++ b/accessible/tests/browser/bounds/browser_test_iframe_transform.js
@@ -0,0 +1,209 @@
+/* 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";
+
+const TRANSLATION_OFFSET = 50;
+const ELEM_ID = "test-elem-id";
+
+// Modify the style of an iframe within the content process. This is different
+// from, e.g., invokeSetStyle, because this function doesn't rely on
+// invokeContentTask, which runs in the context of the iframe itself.
+async function invokeSetStyleIframe(browser, id, style, value) {
+ if (value) {
+ Logger.log(`Setting ${style} style to ${value} for iframe with id: ${id}`);
+ } else {
+ Logger.log(`Removing ${style} style from iframe with id: ${id}`);
+ }
+
+ // Translate the iframe itself (not content within it).
+ await SpecialPowers.spawn(
+ browser,
+ [id, style, value],
+ (iframeId, iframeStyle, iframeValue) => {
+ const elm = content.document.getElementById(iframeId);
+ if (iframeValue) {
+ elm.style[iframeStyle] = iframeValue;
+ } else {
+ delete elm.style[iframeStyle];
+ }
+ }
+ );
+}
+
+// Test the accessible's bounds, comparing them to the content bounds from DOM.
+// This function also accepts an offset, which is necessary in some cases where
+// DOM doesn't know about cross-process offsets.
+function testBoundsWithOffset(browser, iframeDocAcc, id, domElmBounds, offset) {
+ // Get the bounds as reported by the accessible.
+ const acc = findAccessibleChildByID(iframeDocAcc, id);
+ const accX = {};
+ const accY = {};
+ const accWidth = {};
+ const accHeight = {};
+ acc.getBounds(accX, accY, accWidth, accHeight);
+
+ // getContentBoundsForDOMElm's result doesn't include iframe translation
+ // for in-process iframes, but does for out-of-process iframes. To account
+ // for that here, manually add in the translation offset when examining an
+ // in-process iframe.
+ const addTranslationOffset = !gIsRemoteIframe;
+ const expectedX = addTranslationOffset
+ ? domElmBounds[0] + offset
+ : domElmBounds[0];
+ const expectedY = addTranslationOffset
+ ? domElmBounds[1] + offset
+ : domElmBounds[1];
+ const expectedWidth = domElmBounds[2];
+ const expectedHeight = domElmBounds[3];
+
+ let boundsAreEquivalent = true;
+ boundsAreEquivalent &&= accX.value == expectedX;
+ boundsAreEquivalent &&= accY.value == expectedY;
+ boundsAreEquivalent &&= accWidth.value == expectedWidth;
+ boundsAreEquivalent &&= accHeight.value == expectedHeight;
+ return boundsAreEquivalent;
+}
+
+addAccessibleTask(
+ `<div id='${ELEM_ID}'>hello world</div>`,
+ async function (browser, iframeDocAcc, contentDocAcc) {
+ ok(iframeDocAcc, "IFRAME document accessible is present");
+
+ await testBoundsWithContent(iframeDocAcc, ELEM_ID, browser);
+
+ // Translate the iframe, which should modify cross-process offset.
+ await invokeSetStyleIframe(
+ browser,
+ DEFAULT_IFRAME_ID,
+ "transform",
+ `translate(${TRANSLATION_OFFSET}px, ${TRANSLATION_OFFSET}px)`
+ );
+
+ // Allow content to advance to update DOM, then capture the DOM bounds.
+ await waitForContentPaint(browser);
+ const domElmBoundsAfterTranslate = await getContentBoundsForDOMElm(
+ browser,
+ ELEM_ID
+ );
+
+ // Ensure that there's enough time for the cache to update.
+ await untilCacheOk(() => {
+ return testBoundsWithOffset(
+ browser,
+ iframeDocAcc,
+ ELEM_ID,
+ domElmBoundsAfterTranslate,
+ TRANSLATION_OFFSET
+ );
+ }, "Accessible bounds have changed in the cache and match DOM bounds.");
+
+ // Adjust padding of the iframe, then verify bounds adjust properly.
+ // iframes already have a border by default, so we check padding here.
+ const PADDING_OFFSET = 100;
+ await invokeSetStyleIframe(
+ browser,
+ DEFAULT_IFRAME_ID,
+ "padding",
+ `${PADDING_OFFSET}px`
+ );
+
+ // Allow content to advance to update DOM, then capture the DOM bounds.
+ await waitForContentPaint(browser);
+ const domElmBoundsAfterAddingPadding = await getContentBoundsForDOMElm(
+ browser,
+ ELEM_ID
+ );
+
+ await untilCacheOk(() => {
+ return testBoundsWithOffset(
+ browser,
+ iframeDocAcc,
+ ELEM_ID,
+ domElmBoundsAfterAddingPadding,
+ TRANSLATION_OFFSET
+ );
+ }, "Accessible bounds have changed in the cache and match DOM bounds.");
+ },
+ {
+ topLevel: false,
+ iframe: true,
+ remoteIframe: true,
+ iframeAttrs: {
+ style: `height: 100px; width: 100px;`,
+ },
+ }
+);
+
+/**
+ * Test document bounds change notifications.
+ * Note: This uses iframes to change the doc container size in order
+ * to have the doc accessible's bounds change.
+ */
+addAccessibleTask(
+ `<div id="div" style="width: 30px; height: 30px"></div>`,
+ async function (browser, accDoc, foo) {
+ const docWidth = () => {
+ let width = {};
+ accDoc.getBounds({}, {}, width, {});
+ return width.value;
+ };
+
+ await untilCacheIs(docWidth, 0, "Doc width is 0");
+ await invokeSetStyleIframe(browser, DEFAULT_IFRAME_ID, "width", `300px`);
+ await untilCacheIs(docWidth, 300, "Doc width is 300");
+ },
+ {
+ chrome: false,
+ topLevel: false,
+ iframe: true,
+ remoteIframe: true,
+ iframeAttrs: { style: "width: 0;" },
+ }
+);
+
+/**
+ * Test document bounds after re-creating an iframe.
+ */
+addAccessibleTask(
+ `
+<ol id="ol">
+ <iframe id="iframe" src="data:text/html,"></iframe>
+</ol>
+ `,
+ async function (browser, docAcc) {
+ let iframeDoc = findAccessibleChildByID(docAcc, "iframe").firstChild;
+ ok(iframeDoc, "Got the iframe document");
+ const origX = {};
+ const origY = {};
+ iframeDoc.getBounds(origX, origY, {}, {});
+ let reordered = waitForEvent(EVENT_REORDER, docAcc);
+ await invokeContentTask(browser, [], () => {
+ // This will cause a bounds cache update to be queued for the iframe doc.
+ content.document.getElementById("iframe").width = "600";
+ // This will recreate the ol a11y subtree, including the iframe. The
+ // iframe document will be unbound briefly while this happens. We want to
+ // be sure processing the bounds cache update queued above doesn't assert
+ // while the document is unbound. The setTimeout is necessary to get the
+ // cache update to happen at the right time.
+ content.setTimeout(
+ () => (content.document.getElementById("ol").type = "i"),
+ 0
+ );
+ });
+ await reordered;
+ const iframe = findAccessibleChildByID(docAcc, "iframe");
+ // We don't currently fire an event when a DocAccessible is re-bound to a new OuterDoc.
+ await BrowserTestUtils.waitForCondition(() => iframe.firstChild);
+ iframeDoc = iframe.firstChild;
+ ok(iframeDoc, "Got the iframe document after re-creation");
+ const newX = {};
+ const newY = {};
+ iframeDoc.getBounds(newX, newY, {}, {});
+ ok(
+ origX.value == newX.value && origY.value == newY.value,
+ "Iframe document x and y are same after iframe re-creation"
+ );
+ }
+);