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);
}
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)
{
// As per the the spec, we return null if either coord is negative
if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) {
nsAutoTArray<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);
@ -3290,32 +3314,58 @@ nsDocument::ElementFromPointHelper(float aX, float aY,
// Make sure the layout information we get is up-to-date, and
// ensure we get a root frame (for everything but XUL)
if (aFlushLayout)
if (aFlags & nsIDocument::FLUSH_LAYOUT) {
FlushPendingNotifications(Flush_Layout);
}
nsIPresShell *ps = GetShell();
if (!ps) {
return nullptr;
return;
}
nsIFrame *rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading
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 |
(aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
if (!ptFrame) {
return nullptr;
((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;
}
nsIContent* elem = GetContentInThisDocument(ptFrame);
if (elem && !elem->IsElement()) {
elem = elem->GetParent();
// 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;
}
}
}
return elem ? elem->AsElement() : nullptr;
}
nsresult

View File

@ -1029,8 +1029,12 @@ public:
const nsAString& aAttrValue) const override;
virtual Element* ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame,
bool aFlushLayout) override;
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,

View File

@ -1672,6 +1672,16 @@ public:
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,
@ -2531,6 +2541,9 @@ public:
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

View File

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