closes #520: Document.elementsFromPoint() M1164427

This commit is contained in:
Cameron Kaiser 2018-09-12 19:00:20 -07:00
parent e5c93de89f
commit 7e7cdb504d
4 changed files with 83 additions and 16 deletions

View File

@ -3274,15 +3274,39 @@ nsIDocument::ElementFromPoint(float aX, float aY)
return ElementFromPointHelper(aX, aY, false, true); 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* Element*
nsDocument::ElementFromPointHelper(float aX, float aY, nsDocument::ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame, bool aIgnoreRootScrollFrame,
bool aFlushLayout) bool aFlushLayout)
{ {
// As per the the spec, we return null if either coord is negative nsAutoTArray<RefPtr<Element>, 1> elementArray;
if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) { 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 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 x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY); nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
@ -3290,32 +3314,58 @@ nsDocument::ElementFromPointHelper(float aX, float aY,
// Make sure the layout information we get is up-to-date, and // Make sure the layout information we get is up-to-date, and
// ensure we get a root frame (for everything but XUL) // ensure we get a root frame (for everything but XUL)
if (aFlushLayout) if (aFlags & nsIDocument::FLUSH_LAYOUT) {
FlushPendingNotifications(Flush_Layout); FlushPendingNotifications(Flush_Layout);
}
nsIPresShell *ps = GetShell(); nsIPresShell *ps = GetShell();
if (!ps) { if (!ps) {
return nullptr; return;
} }
nsIFrame *rootFrame = ps->GetRootFrame(); nsIFrame *rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading // XUL docs, unlike HTML, have no frame tree until everything's done loading
if (!rootFrame) { if (!rootFrame) {
return nullptr; // return null to premature XUL callers as a reminder to wait return; // return null to premature XUL callers as a reminder to wait
} }
nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, 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 | nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
(aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0)); ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
if (!ptFrame) {
return nullptr; // Dunno when this would ever happen, as we should at least have a root frame under us?
if (outFrames.IsEmpty()) {
return;
} }
nsIContent* elem = GetContentInThisDocument(ptFrame); // Used to filter out repeated elements in sequence.
if (elem && !elem->IsElement()) { nsIContent* lastAdded = nullptr;
elem = elem->GetParent();
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;
}
}
} }
return elem ? elem->AsElement() : nullptr;
} }
nsresult nsresult

View File

@ -1032,6 +1032,10 @@ public:
bool aIgnoreRootScrollFrame, bool aIgnoreRootScrollFrame,
bool aFlushLayout) override; 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, virtual nsresult NodesFromRectHelper(float aX, float aY,
float aTopSize, float aRightSize, float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize, float aBottomSize, float aLeftSize,

View File

@ -1672,6 +1672,16 @@ public:
bool aIgnoreRootScrollFrame, bool aIgnoreRootScrollFrame,
bool aFlushLayout) = 0; 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, virtual nsresult NodesFromRectHelper(float aX, float aY,
float aTopSize, float aRightSize, float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize, float aBottomSize, float aLeftSize,
@ -2531,6 +2541,9 @@ public:
virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0; virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0; virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
Element* ElementFromPoint(float aX, float aY); 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 * Retrieve the location of the caret position (DOM node and character

View File

@ -278,7 +278,7 @@ partial interface Document {
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface
partial interface Document { partial interface Document {
Element? elementFromPoint (float x, float y); Element? elementFromPoint (float x, float y);
sequence<Element> elementsFromPoint (float x, float y);
CaretPosition? caretPositionFromPoint (float x, float y); CaretPosition? caretPositionFromPoint (float x, float y);
readonly attribute Element? scrollingElement; readonly attribute Element? scrollingElement;