Bug 1513658 - Implement DocumentOrShadowRoot.node(s)FromPoint. r=smaug

ChromeOnly for now, needs tests that I'll make sure to land with.

Differential Revision: https://phabricator.services.mozilla.com/D14360

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2018-12-24 12:33:22 +00:00
Родитель 7fdb132838
Коммит b0bc11783b
5 изменённых файлов: 149 добавлений и 7 удалений

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

@ -330,6 +330,18 @@ void DocumentOrShadowRoot::ElementsFromPoint(
aElements);
}
void DocumentOrShadowRoot::NodesFromPoint(float aX, float aY,
nsTArray<RefPtr<nsINode>>& aNodes) {
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
aNodes);
}
nsINode* DocumentOrShadowRoot::NodeFromPoint(float aX, float aY) {
AutoTArray<RefPtr<nsINode>, 1> nodes;
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::No, nodes);
return nodes.SafeElementAt(0);
}
Element* DocumentOrShadowRoot::ElementFromPointHelper(
float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout) {
EnumSet<FrameForPointOption> options;

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

@ -48,7 +48,7 @@ class DocumentOrShadowRoot {
public:
explicit DocumentOrShadowRoot(nsIDocument&);
explicit DocumentOrShadowRoot(mozilla::dom::ShadowRoot&);
explicit DocumentOrShadowRoot(ShadowRoot&);
// Unusual argument naming is because of cycle collection macros.
static void Traverse(DocumentOrShadowRoot* tmp,
@ -103,8 +103,10 @@ class DocumentOrShadowRoot {
Element* GetFullscreenElement();
Element* ElementFromPoint(float aX, float aY);
void ElementsFromPoint(float aX, float aY,
nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
nsINode* NodeFromPoint(float aX, float aY);
void ElementsFromPoint(float aX, float aY, nsTArray<RefPtr<Element>>&);
void NodesFromPoint(float aX, float aY, nsTArray<RefPtr<nsINode>>&);
/**
* Helper for elementFromPoint implementation that allows
@ -214,8 +216,8 @@ class DocumentOrShadowRoot {
*/
Element* GetRetargetedFocusedElement();
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
nsTArray<RefPtr<StyleSheet>> mStyleSheets;
RefPtr<StyleSheetList> mDOMStyleSheets;
/*
* mIdentifierMap works as follows for IDs:

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

@ -75,6 +75,7 @@ skip-if = os == 'linux'
tags = fullscreen
# disabled on OS X for intermittent failures--bug-798848
skip-if = toolkit == 'cocoa'
[test_nodesFromPoint.html]
[test_nodesFromRect.html]
[test_parsingMode.html]
[test_popup_blocker_chrome.xul]

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

@ -0,0 +1,119 @@
<!doctype html>
<meta charset="utf-8">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<style>
div { text-align: justify; max-height: 100vh; }
</style>
<div id="testElement"></div>
<script>
// TODO(emilio): Upstream to WPT once there's a spec for this and our
// implementation is not [ChromeOnly].
const testElement = document.getElementById("testElement");
testElement.innerHTML = "X ".repeat(5000);
{
const rect = testElement.getBoundingClientRect();
const node =
document.nodeFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
is(node, testElement.firstChild, "Should return the text node");
const nodes =
document.nodesFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
const expected = [testElement.firstChild, testElement, document.body, document.documentElement];
is(nodes.length, expected.length, "Not the amount of expected nodes");
for (let i = 0; i < nodes.length; ++i)
is(nodes[i], expected[i]);
}
// Make the test slotted, and add some fallback that we'll test later as well.
{
// Work around the sanitizer by building the DOM manually....
const slot = document.createElement("slot");
slot.innerHTML = "Y ".repeat(5000);
const wrapper = document.createElement("div");
wrapper.appendChild(slot);
testElement.attachShadow({ mode: "open" }).appendChild(wrapper);
}
{
const rect = testElement.getBoundingClientRect();
const node =
document.nodeFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
is(node, testElement.firstChild, "Should return the text node");
const nodes =
document.nodesFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
const expected = [testElement.firstChild, testElement, document.body, document.documentElement];
is(nodes.length, expected.length, "Not the amount of expected nodes (returned nodes in the shadow?)");
for (let i = 0; i < nodes.length; ++i)
is(nodes[i], expected[i]);
}
{
const rect = testElement.getBoundingClientRect();
const node =
testElement.shadowRoot.nodeFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
is(node, testElement.shadowRoot.firstChild, "Should return the div wrapping the text node");
const nodes =
testElement.shadowRoot.nodesFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
const expected = [testElement.shadowRoot.firstChild];
is(nodes.length, expected.length, "Not the amount of expected nodes (returned nodes outside of the shadow?)");
for (let i = 0; i < nodes.length; ++i)
is(nodes[i], expected[i]);
}
// Show the fallback.
testElement.firstChild.remove();
{
const rect = testElement.getBoundingClientRect();
const fallbackText = testElement.shadowRoot.querySelector("slot").firstChild;
const node =
testElement.shadowRoot.nodeFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
is(node, fallbackText, "Should return the fallback text");
const nodes =
testElement.shadowRoot.nodesFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
const expected = [fallbackText, testElement.shadowRoot.firstChild];
is(nodes.length, expected.length, "Not the amount of expected nodes (returned nodes outside of the shadow?)");
for (let i = 0; i < nodes.length; ++i)
is(nodes[i], expected[i]);
}
// Test the fallback from the document.
{
const rect = testElement.getBoundingClientRect();
const node =
document.nodeFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
is(node, testElement, "Should return the element, since the fallback text is in the shadow");
const nodes =
document.nodesFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
const expected = [testElement, document.body, document.documentElement];
is(nodes.length, expected.length, "Not the amount of expected nodes (returned nodes inside of the shadow?)");
for (let i = 0; i < nodes.length; ++i)
is(nodes[i], expected[i]);
}
</script>

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

@ -12,8 +12,16 @@
interface DocumentOrShadowRoot {
// Not implemented yet: bug 1430308.
// Selection? getSelection();
Element? elementFromPoint (float x, float y);
sequence<Element> elementsFromPoint (float x, float y);
Element? elementFromPoint(float x, float y);
sequence<Element> elementsFromPoint(float x, float y);
// TODO: Avoid making these ChromeOnly, see:
// https://github.com/w3c/csswg-drafts/issues/556
[ChromeOnly]
Node? nodeFromPoint(float x, float y);
[ChromeOnly]
sequence<Node> nodesFromPoint(float x, float y);
// Not implemented yet: bug 1430307.
// CaretPosition? caretPositionFromPoint (float x, float y);