summaryrefslogtreecommitdiff
path: root/dom/base
diff options
context:
space:
mode:
authorFranklinDM <mrmineshafter17@gmail.com>2023-03-03 21:48:01 +0800
committerFranklinDM <mrmineshafter17@gmail.com>2023-03-04 21:32:11 +0800
commit6ffdfa793ee9d16de0c1218dbe9188e8a7279f14 (patch)
tree981815ab10c70de5dd0aea279313d2ee9fbab89d /dom/base
parentfb9484caa34c14a91f3eca8c6465767c2ab00315 (diff)
downloaduxp-6ffdfa793ee9d16de0c1218dbe9188e8a7279f14.tar.gz
Issue #2135 - Bug 1430301: Implement ShadowRoot.elementFromPoint/elementsFromPoint
Diffstat (limited to 'dom/base')
-rw-r--r--dom/base/DocumentOrShadowRoot.cpp118
-rw-r--r--dom/base/DocumentOrShadowRoot.h23
-rw-r--r--dom/base/nsDocument.cpp102
-rw-r--r--dom/base/nsDocument.h18
-rw-r--r--dom/base/nsIDocument.h34
5 files changed, 152 insertions, 143 deletions
diff --git a/dom/base/DocumentOrShadowRoot.cpp b/dom/base/DocumentOrShadowRoot.cpp
index f8f9d5a28c..876d265cc1 100644
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -10,6 +10,8 @@
#include "nsFocusManager.h"
#include "ShadowRoot.h"
#include "XULDocument.h"
+#include "nsLayoutUtils.h"
+#include "nsSVGUtils.h"
class nsINode;
class nsIDocument;
@@ -180,5 +182,121 @@ DocumentOrShadowRoot::GetFullscreenElement()
return nullptr;
}
+Element*
+DocumentOrShadowRoot::ElementFromPoint(float aX, float aY)
+{
+ return ElementFromPointHelper(aX, aY, false, true);
+}
+
+void
+DocumentOrShadowRoot::ElementsFromPoint(float aX, float aY,
+ nsTArray<RefPtr<Element>>& aElements)
+{
+ ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
+}
+
+Element*
+DocumentOrShadowRoot::ElementFromPointHelper(float aX, float aY,
+ bool aIgnoreRootScrollFrame,
+ bool aFlushLayout)
+{
+ AutoTArray<RefPtr<Element>, 1> elementArray;
+ ElementsFromPointHelper(aX, aY,
+ ((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
+ (aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
+ nsIDocument::IS_ELEMENT_FROM_POINT),
+ elementArray);
+ if (elementArray.IsEmpty()) {
+ return nullptr;
+ }
+ return elementArray[0];
+}
+
+void
+DocumentOrShadowRoot::ElementsFromPointHelper(float aX, float aY,
+ uint32_t aFlags,
+ nsTArray<RefPtr<mozilla::dom::Element>>& aElements)
+{
+ // As per the the spec, we return null if either coord is negative
+ if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
+ return;
+ }
+
+ nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
+ nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
+ nsPoint pt(x, y);
+
+ nsCOMPtr<nsIDocument> doc = AsNode().OwnerDoc();
+
+ // Make sure the layout information we get is up-to-date, and
+ // ensure we get a root frame (for everything but XUL)
+ if (aFlags & nsIDocument::FLUSH_LAYOUT) {
+ doc->FlushPendingNotifications(Flush_Layout);
+ }
+
+ nsIPresShell* ps = doc->GetShell();
+ if (!ps) {
+ return;
+ }
+ nsIFrame* rootFrame = ps->GetRootFrame();
+
+ // XUL docs, unlike HTML, have no frame tree until everything's done loading
+ if (!rootFrame) {
+ return; // return null to premature XUL callers as a reminder to wait
+ }
+
+ nsTArray<nsIFrame*> outFrames;
+ // Emulate what GetFrameAtPoint does, since we want all the frames under our
+ // point.
+ nsLayoutUtils::GetFramesForArea(rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
+ nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
+ ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
+
+ // Dunno when this would ever happen, as we should at least have a root frame under us?
+ if (outFrames.IsEmpty()) {
+ return;
+ }
+
+ // Used to filter out repeated elements in sequence.
+ nsIContent* lastAdded = nullptr;
+
+ for (uint32_t i = 0; i < outFrames.Length(); i++) {
+ nsIContent* node = doc->GetContentInThisDocument(outFrames[i]);
+
+ if (!node || !node->IsElement()) {
+ // If this helper is called via ElementsFromPoint, we need to make sure
+ // our frame is an element. Otherwise return whatever the top frame is
+ // even if it isn't the top-painted element.
+ // SVG 'text' element's SVGTextFrame doesn't respond to hit-testing, so
+ // if 'node' is a child of such an element then we need to manually defer
+ // to the parent here.
+ if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) &&
+ !outFrames[i]->IsSVGText()) {
+ continue;
+ }
+ node = node->GetParent();
+ if (node) {
+ ShadowRoot* shadow = ShadowRoot::FromNode(node);
+ node = shadow->Host();
+ }
+ }
+
+ //XXXsmaug There is plenty of unspec'ed behavior here
+ // https://github.com/w3c/webcomponents/issues/735
+ // https://github.com/w3c/webcomponents/issues/736
+ node = Retarget(node);
+
+ if (node && node != lastAdded) {
+ aElements.AppendElement(node->AsElement());
+ lastAdded = node;
+ // If this helper is called via ElementFromPoint, just return the first
+ // element we find.
+ if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
+ return;
+ }
+ }
+ }
+}
+
}
}
diff --git a/dom/base/DocumentOrShadowRoot.h b/dom/base/DocumentOrShadowRoot.h
index e056078275..962f7ac0b5 100644
--- a/dom/base/DocumentOrShadowRoot.h
+++ b/dom/base/DocumentOrShadowRoot.h
@@ -117,6 +117,29 @@ public:
Element* GetPointerLockElement();
Element* GetFullscreenElement();
+ Element* ElementFromPoint(float aX, float aY);
+ void ElementsFromPoint(float aX, float aY,
+ nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
+
+ /**
+ * Helper for nsIDOMDocument::elementFromPoint implementation that allows
+ * ignoring the scroll frame and/or avoiding layout flushes.
+ *
+ * @see nsIDOMWindowUtils::elementFromPoint
+ */
+ Element* ElementFromPointHelper(float aX, float aY,
+ bool aIgnoreRootScrollFrame,
+ bool aFlushLayout);
+ enum ElementsFromPointFlags
+ {
+ IGNORE_ROOT_SCROLL_FRAME = 1,
+ FLUSH_LAYOUT = 2,
+ IS_ELEMENT_FROM_POINT = 4
+ };
+
+ void ElementsFromPointHelper(float aX, float aY, uint32_t aFlags,
+ nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
+
protected:
nsIContent* Retarget(nsIContent* aContent) const;
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 562d9e1735..cbb71feaed 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3120,106 +3120,6 @@ nsDocument::ElementFromPoint(float aX, float aY, nsIDOMElement** aReturn)
return NS_OK;
}
-Element*
-nsIDocument::ElementFromPoint(float aX, float aY)
-{
- return ElementFromPointHelper(aX, aY, false, true);
-}
-
-void
-nsIDocument::ElementsFromPoint(float aX, float aY,
- nsTArray<RefPtr<Element>>& aElements)
-{
- ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
-}
-
-Element*
-nsDocument::ElementFromPointHelper(float aX, float aY,
- bool aIgnoreRootScrollFrame,
- bool aFlushLayout)
-{
- AutoTArray<RefPtr<Element>, 1> elementArray;
- ElementsFromPointHelper(aX, aY,
- ((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
- (aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
- nsIDocument::IS_ELEMENT_FROM_POINT),
- elementArray);
- if (elementArray.IsEmpty()) {
- return nullptr;
- }
- return elementArray[0];
-}
-
-void
-nsDocument::ElementsFromPointHelper(float aX, float aY,
- uint32_t aFlags,
- nsTArray<RefPtr<mozilla::dom::Element>>& aElements)
-{
- // As per the the spec, we return null if either coord is negative
- if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
- return;
- }
-
- nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
- nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
- nsPoint pt(x, y);
-
- // Make sure the layout information we get is up-to-date, and
- // ensure we get a root frame (for everything but XUL)
- if (aFlags & nsIDocument::FLUSH_LAYOUT) {
- FlushPendingNotifications(Flush_Layout);
- }
-
- nsIPresShell *ps = GetShell();
- if (!ps) {
- return;
- }
- nsIFrame *rootFrame = ps->GetRootFrame();
-
- // XUL docs, unlike HTML, have no frame tree until everything's done loading
- if (!rootFrame) {
- return; // return null to premature XUL callers as a reminder to wait
- }
-
- nsTArray<nsIFrame*> outFrames;
- // Emulate what GetFrameAtPoint does, since we want all the frames under our
- // point.
- nsLayoutUtils::GetFramesForArea(rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
- nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
- ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
-
- // Dunno when this would ever happen, as we should at least have a root frame under us?
- if (outFrames.IsEmpty()) {
- return;
- }
-
- // Used to filter out repeated elements in sequence.
- nsIContent* lastAdded = nullptr;
-
- for (uint32_t i = 0; i < outFrames.Length(); i++) {
- nsIContent* node = GetContentInThisDocument(outFrames[i]);
-
- if (!node || !node->IsElement()) {
- // If this helper is called via ElementsFromPoint, we need to make sure
- // our frame is an element. Otherwise return whatever the top frame is
- // even if it isn't the top-painted element.
- if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT)) {
- continue;
- }
- node = node->GetParent();
- }
- if (node && node != lastAdded) {
- aElements.AppendElement(node->AsElement());
- lastAdded = node;
- // If this helper is called via ElementFromPoint, just return the first
- // element we find.
- if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
- return;
- }
- }
- }
-}
-
nsresult
nsDocument::NodesFromRectHelper(float aX, float aY,
float aTopSize, float aRightSize,
@@ -8387,7 +8287,7 @@ nsDocument::DoUnblockOnload()
}
nsIContent*
-nsDocument::GetContentInThisDocument(nsIFrame* aFrame) const
+nsIDocument::GetContentInThisDocument(nsIFrame* aFrame) const
{
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 1c10d7b5c3..923fb49ae9 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -692,14 +692,6 @@ public:
nsIAtom* aAttrName,
const nsAString& aAttrValue) const override;
- virtual Element* ElementFromPointHelper(float aX, float aY,
- bool aIgnoreRootScrollFrame,
- bool aFlushLayout) override;
-
- virtual void ElementsFromPointHelper(float aX, float aY,
- uint32_t aFlags,
- nsTArray<RefPtr<mozilla::dom::Element>>& aElements) override;
-
virtual nsresult NodesFromRectHelper(float aX, float aY,
float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize,
@@ -1312,16 +1304,6 @@ private:
nsresult InitCSP(nsIChannel* aChannel);
- /**
- * Find the (non-anonymous) content in this document for aFrame. It will
- * be aFrame's content node if that content is in this document and not
- * anonymous. Otherwise, when aFrame is in a subdocument, we use the frame
- * element containing the subdocument containing aFrame, and/or find the
- * nearest non-anonymous ancestor in this document.
- * Returns null if there is no such element.
- */
- nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
-
// Just like EnableStyleSheetsForSet, but doesn't check whether
// aSheetSet is null and allows the caller to control whether to set
// aSheetSet as the preferred set in the CSSLoader.
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index dcaee4fabd..d64827aa6d 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1811,26 +1811,6 @@ public:
nsIAtom* aAttrName,
const nsAString& aAttrValue) const = 0;
- /**
- * Helper for nsIDOMDocument::elementFromPoint implementation that allows
- * ignoring the scroll frame and/or avoiding layout flushes.
- *
- * @see nsIDOMWindowUtils::elementFromPoint
- */
- virtual Element* ElementFromPointHelper(float aX, float aY,
- bool aIgnoreRootScrollFrame,
- bool aFlushLayout) = 0;
-
- enum ElementsFromPointFlags {
- IGNORE_ROOT_SCROLL_FRAME = 1,
- FLUSH_LAYOUT = 2,
- IS_ELEMENT_FROM_POINT = 4
- };
-
- virtual void ElementsFromPointHelper(float aX, float aY,
- uint32_t aFlags,
- nsTArray<RefPtr<mozilla::dom::Element>>& aElements) = 0;
-
virtual nsresult NodesFromRectHelper(float aX, float aY,
float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize,
@@ -2664,10 +2644,6 @@ public:
void GetPreferredStyleSheetSet(nsAString& aSheetSet);
virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
- Element* ElementFromPoint(float aX, float aY);
- void ElementsFromPoint(float aX,
- float aY,
- nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
/**
* Retrieve the location of the caret position (DOM node and character
@@ -2835,6 +2811,16 @@ public:
bool ModuleScriptsEnabled();
+ /**
+ * Find the (non-anonymous) content in this document for aFrame. It will
+ * be aFrame's content node if that content is in this document and not
+ * anonymous. Otherwise, when aFrame is in a subdocument, we use the frame
+ * element containing the subdocument containing aFrame, and/or find the
+ * nearest non-anonymous ancestor in this document.
+ * Returns null if there is no such element.
+ */
+ nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
+
virtual void AddResizeObserver(mozilla::dom::ResizeObserver* aResizeObserver) = 0;
virtual void ScheduleResizeObserversNotification() const = 0;