diff options
Diffstat (limited to 'accessible/tests/browser/bounds')
11 files changed, 808 insertions, 0 deletions
diff --git a/accessible/tests/browser/bounds/browser.ini b/accessible/tests/browser/bounds/browser.ini new file mode 100644 index 0000000000..abbe6f925a --- /dev/null +++ b/accessible/tests/browser/bounds/browser.ini @@ -0,0 +1,24 @@ +[DEFAULT] +subsuite = a11y +support-files = + head.js + !/accessible/tests/browser/shared-head.js + !/accessible/tests/browser/*.jsm + !/accessible/tests/mochitest/*.js + !/accessible/tests/mochitest/letters.gif + +[browser_accessible_moved.js] +[browser_position.js] +[browser_test_resolution.js] +skip-if = os == 'win' # bug 1372296 +[browser_test_zoom.js] +skip-if = true # Bug 1734271 +[browser_test_zoom_text.js] +https_first_disabled = true +skip-if = os == 'win' # bug 1372296 +[browser_zero_area.js] +[browser_test_display_contents.js] +[browser_test_simple_transform.js] +[browser_test_iframe_transform.js] +skip-if = + os == "win" && os_version == "6.1" # Skip on Azure - frequent failure diff --git a/accessible/tests/browser/bounds/browser_accessible_moved.js b/accessible/tests/browser/bounds/browser_accessible_moved.js new file mode 100644 index 0000000000..b3251bd112 --- /dev/null +++ b/accessible/tests/browser/bounds/browser_accessible_moved.js @@ -0,0 +1,49 @@ +/* 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"; + +function assertBoundsNonZero(acc) { + // XXX We don't use getBounds because it uses BoundsInCSSPixels(), but that + // isn't implemented for the cache yet. + let x = {}; + let y = {}; + let width = {}; + let height = {}; + acc.getBounds(x, y, width, height); + ok(x.value > 0, "x is non-0"); + ok(y.value > 0, "y is non-0"); + ok(width.value > 0, "width is non-0"); + ok(height.value > 0, "height is non-0"); +} + +/** + * Test that bounds aren't 0 after an Accessible is moved (but not re-created). + */ +addAccessibleTask( + ` +<div id="root" role="group"><div id="scrollable" role="presentation" style="height: 1px;"><button id="button">test</button></div></div> + `, + async function(browser, docAcc) { + let button = findAccessibleChildByID(docAcc, "button"); + assertBoundsNonZero(button); + + const root = findAccessibleChildByID(docAcc, "root"); + let reordered = waitForEvent(EVENT_REORDER, root); + // scrollable wasn't in the a11y tree, but this will force it to be created. + // button will be moved inside it. + await invokeContentTask(browser, [], () => { + content.document.getElementById("scrollable").style.overflow = "scroll"; + }); + await reordered; + + const scrollable = findAccessibleChildByID(docAcc, "scrollable"); + assertBoundsNonZero(scrollable); + // XXX button's RemoteAccessible was recreated, so we have to fetch it + // again. This shouldn't be necessary once bug 1739050 is fixed. + button = findAccessibleChildByID(docAcc, "button"); + assertBoundsNonZero(button); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_position.js b/accessible/tests/browser/bounds/browser_position.js new file mode 100644 index 0000000000..616db89a73 --- /dev/null +++ b/accessible/tests/browser/bounds/browser_position.js @@ -0,0 +1,32 @@ +/* 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"; + +/** + * Test changing the left/top CSS properties. + */ +addAccessibleTask( + ` +<div id="div" style="position: relative; left: 0px; top: 0px; width: fit-content;"> + test +</div> + `, + async function(browser, docAcc) { + await testBoundsWithContent(docAcc, "div", browser); + info("Changing left"); + await invokeContentTask(browser, [], () => { + content.document.getElementById("div").style.left = "200px"; + }); + await waitForContentPaint(browser); + await testBoundsWithContent(docAcc, "div", browser); + info("Changing top"); + await invokeContentTask(browser, [], () => { + content.document.getElementById("div").style.top = "200px"; + }); + await waitForContentPaint(browser); + await testBoundsWithContent(docAcc, "div", browser); + }, + { chrome: true, topLevel: true, iframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_test_display_contents.js b/accessible/tests/browser/bounds/browser_test_display_contents.js new file mode 100644 index 0000000000..881eaa5c7e --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_display_contents.js @@ -0,0 +1,48 @@ +/* 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 */ + +async function testContentBounds(browser, acc) { + let [ + expectedX, + expectedY, + expectedWidth, + expectedHeight, + ] = await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc)); + + let contentDPR = await getContentDPR(browser); + let [x, y, width, height] = getBounds(acc, contentDPR); + let prettyAccName = prettyName(acc); + is(x, expectedX, "Wrong x coordinate of " + prettyAccName); + is(y, expectedY, "Wrong y coordinate of " + prettyAccName); + is(width, expectedWidth, "Wrong width of " + prettyAccName); + ok(height >= expectedHeight, "Wrong height of " + prettyAccName); +} + +async function runTests(browser, accDoc) { + let p = findAccessibleChildByID(accDoc, "div"); + let p2 = findAccessibleChildByID(accDoc, "p"); + + await testContentBounds(browser, p); + await testContentBounds(browser, p2); +} + +/** + * Test accessible bounds for accs with display:contents + */ +addAccessibleTask( + ` + <div id="div">before + <ul id="ul" style="display: contents;"> + <li id="li" style="display: contents;"> + <p id="p">item</p> + </li> + </ul> + </div>`, + runTests, + { iframe: true, remoteIframe: true } +); 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..6b0b2b9ebb --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_iframe_transform.js @@ -0,0 +1,210 @@ +/* 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. This manual adjustment isn't necessary without the cache + // since, without it, accessible bounds don't include the translation offset either. + const addTranslationOffset = !gIsRemoteIframe && isCacheEnabled; + 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: isCacheEnabled /* works, but timing is tricky with no cache */, + 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" + ); + } +); diff --git a/accessible/tests/browser/bounds/browser_test_resolution.js b/accessible/tests/browser/bounds/browser_test_resolution.js new file mode 100644 index 0000000000..0b0b47418d --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_resolution.js @@ -0,0 +1,72 @@ +/* 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 */ + +async function testScaledBounds(browser, accDoc, scale, id, type = "object") { + let acc = findAccessibleChildByID(accDoc, id); + + // Get document offset + let [docX, docY] = getBounds(accDoc); + + // Get the unscaled bounds of the accessible + let [x, y, width, height] = + type == "text" + ? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) + : getBounds(acc); + + await invokeContentTask(browser, [scale], _scale => { + const { Layout } = ChromeUtils.importESModule( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs" + ); + Layout.setResolution(content.document, _scale); + }); + + let [scaledX, scaledY, scaledWidth, scaledHeight] = + type == "text" + ? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) + : getBounds(acc); + + let name = prettyName(acc); + isWithin(scaledWidth, width * scale, 2, "Wrong scaled width of " + name); + isWithin(scaledHeight, height * scale, 2, "Wrong scaled height of " + name); + isWithin(scaledX - docX, (x - docX) * scale, 2, "Wrong scaled x of " + name); + isWithin(scaledY - docY, (y - docY) * scale, 2, "Wrong scaled y of " + name); + + await invokeContentTask(browser, [], () => { + const { Layout } = ChromeUtils.importESModule( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs" + ); + Layout.setResolution(content.document, 1.0); + }); +} + +async function runTests(browser, accDoc) { + // The scrollbars get in the way of container bounds calculation. + await SpecialPowers.pushPrefEnv({ + set: [["ui.useOverlayScrollbars", 1]], + }); + + await testScaledBounds(browser, accDoc, 2.0, "p1"); + await testScaledBounds(browser, accDoc, 0.5, "p2"); + await testScaledBounds(browser, accDoc, 3.5, "b1"); + + await testScaledBounds(browser, accDoc, 2.0, "p1", "text"); + await testScaledBounds(browser, accDoc, 0.75, "p2", "text"); +} + +/** + * Test accessible boundaries when page is zoomed + */ +addAccessibleTask( + ` +<p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p> +<p id="p2">para 2</p> +<button id="b1">Hello</button> +`, + runTests, + { iframe: true, remoteIframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_test_simple_transform.js b/accessible/tests/browser/bounds/browser_test_simple_transform.js new file mode 100644 index 0000000000..348cbd3429 --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_simple_transform.js @@ -0,0 +1,116 @@ +/* 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"; + +// test basic translation +addAccessibleTask( + `<p id="translate">hello world</p>`, + async function(browser, iframeDocAcc, contentDocAcc) { + ok(iframeDocAcc, "IFRAME document accessible is present"); + await testBoundsWithContent(iframeDocAcc, "translate", browser); + + await invokeContentTask(browser, [], () => { + let p = content.document.getElementById("translate"); + p.style = "transform: translate(100px, 100px);"; + }); + + await waitForContentPaint(browser); + await testBoundsWithContent(iframeDocAcc, "translate", browser); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); + +// Test translation with two children. +addAccessibleTask( + ` +<div role="main" style="translate: 0 300px;"> + <p id="p1">hello</p> + <p id="p2">world</p> +</div> + `, + async function(browser, docAcc) { + await testBoundsWithContent(docAcc, "p1", browser); + await testBoundsWithContent(docAcc, "p2", browser); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); + +// test basic rotation +addAccessibleTask( + `<p id="rotate">hello world</p>`, + async function(browser, iframeDocAcc, contentDocAcc) { + ok(iframeDocAcc, "IFRAME document accessible is present"); + await testBoundsWithContent(iframeDocAcc, "rotate", browser); + + await invokeContentTask(browser, [], () => { + let p = content.document.getElementById("rotate"); + p.style = "transform: rotate(-40deg);"; + }); + + await waitForContentPaint(browser); + await testBoundsWithContent(iframeDocAcc, "rotate", browser); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); + +// test basic scale +addAccessibleTask( + `<p id="scale">hello world</p>`, + async function(browser, iframeDocAcc, contentDocAcc) { + ok(iframeDocAcc, "IFRAME document accessible is present"); + await testBoundsWithContent(iframeDocAcc, "scale", browser); + + await invokeContentTask(browser, [], () => { + let p = content.document.getElementById("scale"); + p.style = "transform: scale(2);"; + }); + + await waitForContentPaint(browser); + await testBoundsWithContent(iframeDocAcc, "scale", browser); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); + +// Test will-change: transform with no transform. +addAccessibleTask( + ` +<div id="willChangeTop" style="will-change: transform;"> + <p>hello</p> + <p id="willChangeTopP2">world</p> +</div> +<div role="group"> + <div id="willChangeInner" style="will-change: transform;"> + <p>hello</p> + <p id="willChangeInnerP2">world</p> + </div> +</div> + `, + async function(browser, docAcc) { + if (isCacheEnabled) { + // Even though willChangeTop has no transform, it has + // will-change: transform, which means nsIFrame::IsTransformed returns + // true. We don't cache identity matrices, but because there is an offset + // to the root frame, layout includes this in the returned transform + // matrix. That means we get a non-identity matrix and thus we cache it. + // This is why we only test the identity matrix cache optimization for + // willChangeInner. + let hasTransform; + try { + const willChangeInner = findAccessibleChildByID( + docAcc, + "willChangeInner" + ); + willChangeInner.cache.getStringProperty("transform"); + hasTransform = true; + } catch (e) { + hasTransform = false; + } + ok(!hasTransform, "willChangeInner has no cached transform"); + } + await testBoundsWithContent(docAcc, "willChangeTopP2", browser); + await testBoundsWithContent(docAcc, "willChangeInnerP2", browser); + }, + { topLevel: true, iframe: true, remoteIframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_test_zoom.js b/accessible/tests/browser/bounds/browser_test_zoom.js new file mode 100644 index 0000000000..2f59184154 --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_zoom.js @@ -0,0 +1,69 @@ +/* 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 */ + +async function testContentBounds(browser, acc) { + let [ + expectedX, + expectedY, + expectedWidth, + expectedHeight, + ] = await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc)); + + let contentDPR = await getContentDPR(browser); + let [x, y, width, height] = getBounds(acc, contentDPR); + let prettyAccName = prettyName(acc); + is(x, expectedX, "Wrong x coordinate of " + prettyAccName); + is(y, expectedY, "Wrong y coordinate of " + prettyAccName); + is(width, expectedWidth, "Wrong width of " + prettyAccName); + ok(height >= expectedHeight, "Wrong height of " + prettyAccName); +} + +async function runTests(browser, accDoc) { + let p1 = findAccessibleChildByID(accDoc, "p1"); + let p2 = findAccessibleChildByID(accDoc, "p2"); + let imgmap = findAccessibleChildByID(accDoc, "imgmap"); + if (!imgmap.childCount) { + // An image map may not be available even after the doc and image load + // is complete. We don't recieve any DOM events for this change either, + // so we need to wait for a REORDER. + await waitForEvent(EVENT_REORDER, "imgmap"); + } + let area = imgmap.firstChild; + + await testContentBounds(browser, p1); + await testContentBounds(browser, p2); + await testContentBounds(browser, area); + + await SpecialPowers.spawn(browser, [], () => { + const { Layout } = ChromeUtils.importESModule( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs" + ); + Layout.zoomDocument(content.document, 2.0); + }); + + await testContentBounds(browser, p1); + await testContentBounds(browser, p2); + await testContentBounds(browser, area); +} + +/** + * Test accessible boundaries when page is zoomed + */ +addAccessibleTask( + ` +<p id="p1">para 1</p><p id="p2">para 2</p> +<map name="atoz_map" id="map"> + <area id="area1" href="http://mozilla.org" + coords=17,0,30,14" alt="mozilla.org" shape="rect"> +</map> +<img id="imgmap" width="447" height="15" + usemap="#atoz_map" + src="http://example.com/a11y/accessible/tests/mochitest/letters.gif">`, + runTests, + { iframe: true, remoteIframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_test_zoom_text.js b/accessible/tests/browser/bounds/browser_test_zoom_text.js new file mode 100644 index 0000000000..3f40b698bf --- /dev/null +++ b/accessible/tests/browser/bounds/browser_test_zoom_text.js @@ -0,0 +1,86 @@ +/* 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 */ + +async function runTests(browser, accDoc) { + async function testTextNode(id) { + let hyperTextNode = findAccessibleChildByID(accDoc, id); + let textNode = hyperTextNode.firstChild; + + let contentDPR = await getContentDPR(browser); + let [x, y, width, height] = getBounds(textNode, contentDPR); + testTextBounds( + hyperTextNode, + 0, + -1, + [x, y, width, height], + COORDTYPE_SCREEN_RELATIVE + ); + // A 0 range should return an empty rect. + testTextBounds( + hyperTextNode, + 0, + 0, + [0, 0, 0, 0], + COORDTYPE_SCREEN_RELATIVE + ); + } + + async function testEmptyInputNode(id) { + let inputNode = findAccessibleChildByID(accDoc, id); + + let [x, y, width, height] = getBounds(inputNode); + testTextBounds( + inputNode, + 0, + -1, + [x, y, width, height], + COORDTYPE_SCREEN_RELATIVE + ); + // A 0 range in an empty input should still return + // rect of input node. + testTextBounds( + inputNode, + 0, + 0, + [x, y, width, height], + COORDTYPE_SCREEN_RELATIVE + ); + } + + await testTextNode("p1"); + await testTextNode("p2"); + await testEmptyInputNode("i1"); + + await SpecialPowers.spawn(browser, [], () => { + const { Layout } = ChromeUtils.importESModule( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs" + ); + Layout.zoomDocument(content.document, 2.0); + }); + + await testTextNode("p1"); + + await SpecialPowers.spawn(browser, [], () => { + const { Layout } = ChromeUtils.importESModule( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.sys.mjs" + ); + Layout.zoomDocument(content.document, 1.0); + }); +} + +/** + * Test the text range boundary when page is zoomed + */ +addAccessibleTask( + ` + <p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p> + <p id='p2'>ل</p> + <form><input id='i1' /></form>`, + runTests, + { iframe: true, remoteIframe: true } +); diff --git a/accessible/tests/browser/bounds/browser_zero_area.js b/accessible/tests/browser/bounds/browser_zero_area.js new file mode 100644 index 0000000000..b583f2791b --- /dev/null +++ b/accessible/tests/browser/bounds/browser_zero_area.js @@ -0,0 +1,81 @@ +/* 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 */ + +async function testContentBounds(browser, acc, expectedWidth, expectedHeight) { + let [expectedX, expectedY] = await getContentBoundsForDOMElm( + browser, + getAccessibleDOMNodeID(acc) + ); + + let contentDPR = await getContentDPR(browser); + let [x, y, width, height] = getBounds(acc, contentDPR); + let prettyAccName = prettyName(acc); + is(x, expectedX, "Wrong x coordinate of " + prettyAccName); + is(y, expectedY, "Wrong y coordinate of " + prettyAccName); + is(width, expectedWidth, "Wrong width of " + prettyAccName); + is(height, expectedHeight, "Wrong height of " + prettyAccName); +} +/** + * Test accessible bounds with different combinations of overflow and + * non-zero frame area. + */ +addAccessibleTask( + ` + <div id="a1" style="height:100px; width:100px; background:green;"></div> + <div id="a2" style="height:100px; width:100px; background:green;"><div style="height:300px; max-width: 300px; background:blue;"></div></div> + <div id="a3" style="height:0; width:0;"><div style="height:200px; width:200px; background:green;"></div></div> + `, + async function(browser, accDoc) { + const a1 = findAccessibleChildByID(accDoc, "a1"); + const a2 = findAccessibleChildByID(accDoc, "a2"); + const a3 = findAccessibleChildByID(accDoc, "a3"); + await testContentBounds(browser, a1, 100, 100); + await testContentBounds(browser, a2, 100, 100); + await testContentBounds(browser, a3, 200, 200); + } +); + +/** + * Ensure frames with zero area have their x, y coordinates correctly reported + * in bounds() + */ +addAccessibleTask( + ` +<br> +<div id="a" style="height:0; width:0;"></div> +`, + async function(browser, accDoc) { + const a = findAccessibleChildByID(accDoc, "a"); + await testContentBounds(browser, a, 0, 0); + } +); + +/** + * Ensure accessibles have accurately signed dimensions and position when + * offscreen. + */ +addAccessibleTask( + ` +<input type="radio" id="radio" style="left: -671091em; position: absolute;"> +`, + async function(browser, accDoc) { + const radio = findAccessibleChildByID(accDoc, "radio"); + const contentDPR = await getContentDPR(browser); + const [x, y, width, height] = getBounds(radio, contentDPR); + ok(x < 0, "X coordinate should be negative"); + ok(y > 0, "Y coordinate should be positive"); + ok(width > 0, "Width should be positive"); + ok(height > 0, "Height should be positive"); + // Note: the exact values of x, y, width, and height + // are inconsistent with the DOM element values of those + // fields, so we don't check our bounds against them with + // `testContentBounds` here. DOM reports a negative width, + // positive height, and a slightly different (+/- 20) + // x and y. + } +); diff --git a/accessible/tests/browser/bounds/head.js b/accessible/tests/browser/bounds/head.js new file mode 100644 index 0000000000..f4d20e636c --- /dev/null +++ b/accessible/tests/browser/bounds/head.js @@ -0,0 +1,21 @@ +/* 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"; + +// Load the shared-head file first. +/* import-globals-from ../shared-head.js */ + +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js", + this +); + +// Loading and common.js from accessible/tests/mochitest/ for all tests, as +// well as events.js. +loadScripts( + { name: "common.js", dir: MOCHITESTS_DIR }, + { name: "layout.js", dir: MOCHITESTS_DIR }, + { name: "promisified-events.js", dir: MOCHITESTS_DIR } +); |