Bug 1774330: Only return ancestors from ChildAtPoint r=eeejay

Differential Revision: https://phabricator.services.mozilla.com/D160849
This commit is contained in:
Morgan Rae Reschenberg 2022-11-15 19:30:12 +00:00
Родитель f76ebbd777
Коммит 46439cea0c
3 изменённых файлов: 105 добавлений и 10 удалений

Просмотреть файл

@ -380,12 +380,16 @@ Accessible* RemoteAccessibleBase<Derived>::ChildAtPoint(
MOZ_ASSERT(innerDoc->IsDoc()); MOZ_ASSERT(innerDoc->IsDoc());
// Search the embedded document's viewport cache so we return the // Search the embedded document's viewport cache so we return the
// deepest descendant in that embedded document. // deepest descendant in that embedded document.
return innerDoc->ChildAtPoint(aX, aY, Accessible* deepestAcc = innerDoc->ChildAtPoint(
EWhichChildAtPoint::DeepestChild); aX, aY, EWhichChildAtPoint::DeepestChild);
MOZ_ASSERT(!deepestAcc || deepestAcc->IsRemote());
lastMatch = deepestAcc ? deepestAcc->AsRemote() : nullptr;
break;
} }
// If there is no embedded document, the iframe itself is the deepest // If there is no embedded document, the iframe itself is the deepest
// descendant. // descendant.
return acc; lastMatch = acc;
break;
} }
if (acc == this) { if (acc == this) {
@ -417,6 +421,12 @@ Accessible* RemoteAccessibleBase<Derived>::ChildAtPoint(
if (!lastMatch && Bounds().Contains(aX, aY)) { if (!lastMatch && Bounds().Contains(aX, aY)) {
return this; return this;
} }
// If we end up with a match that is not in the ancestor chain
// of the accessible this call originated on, we should ignore it.
// This can happen when the aX, aY given are outside `this`.
if (lastMatch && !IsDoc() && !IsAncestorOf(lastMatch)) {
return nullptr;
}
return lastMatch; return lastMatch;
} }

Просмотреть файл

@ -129,3 +129,76 @@ addAccessibleTask(
iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" }, iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
} }
); );
addAccessibleTask(
`
<div id="container">
<h1 id="a">A</h1><h1 id="b">B</h1>
</div>
`,
async function(browser, accDoc) {
const a = findAccessibleChildByID(accDoc, "a");
const b = findAccessibleChildByID(accDoc, "b");
const dpr = await getContentDPR(browser);
// eslint-disable-next-line no-unused-vars
const [x, y, w, h] = Layout.getBounds(a, dpr);
// The point passed below will be made relative to `b`, but
// we'd like to test a point within `a`. Pass `a`s negative
// width for an x offset. Pass zero as a y offset,
// assuming the headings are on the same line.
await testChildAtPoint(dpr, -w, 0, b, null, null);
},
{
iframe: true,
remoteIframe: true,
// Ensure that all hittest elements are in view.
iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
}
);
addAccessibleTask(
`
<style>
div {
width: 50px;
height: 50px;
position: relative;
}
div > div {
width: 30px;
height: 30px;
position: absolute;
opacity: 0.9;
}
</style>
<div id="a" style="background-color: orange;">
<div id="aa" style="background-color: purple;"></div>
</div>
<div id="b" style="background-color: yellowgreen;">
<div id="bb" style="top: -30px; background-color: turquoise"></div>
</div>`,
async function(browser, accDoc) {
const a = findAccessibleChildByID(accDoc, "a");
const aa = findAccessibleChildByID(accDoc, "aa");
const dpr = await getContentDPR(browser);
// eslint-disable-next-line no-unused-vars
const [_, y, w] = Layout.getBounds(a, dpr);
// test upper left of `a`
await testChildAtPoint(dpr, 1, 1, a, aa, aa);
// test upper right of `a`
await testChildAtPoint(dpr, w - 1, 1, a, a, a);
// test just outside upper left of `a`
await testChildAtPoint(dpr, 1, y - 1, a, null, null);
if (isCacheEnabled) {
// test halfway down/left of `a`
await testChildAtPoint(dpr, 1, Math.round(y / 2), a, null, null);
}
},
{
iframe: false,
remoteIframe: false,
// Ensure that all hittest elements are in view.
iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
}
);

Просмотреть файл

@ -37,7 +37,7 @@ function getChildAtPoint(container, x, y, findDeepestChild) {
} catch (e) { } catch (e) {
// Failed to get child at point. // Failed to get child at point.
} }
info("could not get child at point");
return null; return null;
} }
@ -45,19 +45,31 @@ async function testChildAtPoint(dpr, x, y, container, child, grandChild) {
const [containerX, containerY] = Layout.getBounds(container, dpr); const [containerX, containerY] = Layout.getBounds(container, dpr);
x += containerX; x += containerX;
y += containerY; y += containerY;
let actual = null;
await untilCacheIs( await untilCacheIs(
() => getChildAtPoint(container, x, y, false), () => {
actual = getChildAtPoint(container, x, y, false);
return actual;
},
child, child,
`Wrong direct child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName( `Wrong direct child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName(
container container
)}, sought ${child ? roleToString(child.role) : "unknown"}` )}, sought ${CommonUtils.prettyName(
child
)} and got ${CommonUtils.prettyName(actual)}`
); );
actual = null;
await untilCacheIs( await untilCacheIs(
() => getChildAtPoint(container, x, y, true), () => {
actual = getChildAtPoint(container, x, y, true);
return actual;
},
grandChild, grandChild,
`Wrong deepest child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName( `Wrong deepest child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName(
container container
)}, sought ${grandChild ? roleToString(grandChild.role) : "unknown"}` )}, sought ${CommonUtils.prettyName(
grandChild
)} and got ${CommonUtils.prettyName(actual)}`
); );
} }
@ -78,14 +90,14 @@ async function hitTest(browser, container, child, grandChild) {
child, child,
`Wrong direct child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName( `Wrong direct child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName(
container container
)}, sought ${child ? roleToString(child.role) : "unknown"}` )}, sought ${CommonUtils.prettyName(child)}`
); );
await untilCacheIs( await untilCacheIs(
() => getChildAtPoint(container, x, y, true), () => getChildAtPoint(container, x, y, true),
grandChild, grandChild,
`Wrong deepest child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName( `Wrong deepest child accessible at the point (${x}, ${y}) of ${CommonUtils.prettyName(
container container
)}, sought ${grandChild ? roleToString(grandChild.role) : "unknown"}` )}, sought ${CommonUtils.prettyName(grandChild)}`
); );
} }