Issue #2456 - Intersection Observer - Accept a Document as an explicit root. https://bugzilla.mozilla.org/show_bug.cgi?id=1617154

This commit is contained in:
Brian Smith 2024-01-15 05:54:48 -06:00 • committed by roytam1
commit f44db6a28b
3 changed files with 50 additions and 33 deletions

View file

@ -80,7 +80,14 @@ DOMIntersectionObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
RefPtr<DOMIntersectionObserver> observer = RefPtr<DOMIntersectionObserver> observer =
new DOMIntersectionObserver(window.forget(), aCb); new DOMIntersectionObserver(window.forget(), aCb);
observer->mRoot = aOptions.mRoot; if (!aOptions.mRoot.IsNull()) {
if (aOptions.mRoot.Value().IsElement()) {
observer->mRoot = aOptions.mRoot.Value().GetAsElement();
} else {
MOZ_ASSERT(aOptions.mRoot.Value().IsDocument());
observer->mRoot = aOptions.mRoot.Value().GetAsDocument();
}
}
if (!observer->SetRootMargin(aOptions.mRootMargin)) { if (!observer->SetRootMargin(aOptions.mRootMargin)) {
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR, aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
@ -258,6 +265,30 @@ EdgeInclusiveIntersection(const nsRect& aRect, const nsRect& aOtherRect)
return Some(nsRect(left, top, right - left, bottom - top)); return Some(nsRect(left, top, right - left, bottom - top));
} }
// NOTE: This returns nullptr if |aDocument| is in a cross process.
static nsIDocument* GetTopLevelDocument(const nsIDocument& aDocument) {
nsCOMPtr<nsIPresShell> presShell = aDocument.GetShell();
if (presShell) {
nsIFrame* rootFrame = presShell->GetRootScrollFrame();
if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) {
// Walk up the tree
presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
}
if(presContext && presContext->IsRootContentDocument()) {
return presContext->Document();
}
}
}
return nullptr;
}
enum class BrowsingContextInfo { enum class BrowsingContextInfo {
SimilarOriginBrowsingContext, SimilarOriginBrowsingContext,
DifferentOriginBrowsingContext, DifferentOriginBrowsingContext,
@ -267,14 +298,12 @@ enum class BrowsingContextInfo {
void void
DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time) DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time)
{ {
Element* root = nullptr; nsINode* root = mRoot;
nsIFrame* rootFrame = nullptr; nsIFrame* rootFrame = nullptr;
nsRect rootRect; nsRect rootRect;
if (mRoot) { if (mRoot && mRoot->IsElement()) {
root = mRoot; if ((rootFrame = mRoot->AsElement()->GetPrimaryFrame())) {
rootFrame = root->GetPrimaryFrame();
if (rootFrame) {
nsRect rootRectRelativeToRootFrame; nsRect rootRectRelativeToRootFrame;
if (rootFrame->GetType() == nsGkAtoms::scrollFrame) { if (rootFrame->GetType() == nsGkAtoms::scrollFrame) {
// rootRectRelativeToRootFrame should be the content rect of rootFrame, not including the scrollbars. // rootRectRelativeToRootFrame should be the content rect of rootFrame, not including the scrollbars.
@ -292,30 +321,18 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
containingBlock); containingBlock);
} }
} else { } else {
nsCOMPtr<nsIPresShell> presShell = aDocument->GetShell(); MOZ_ASSERT(!mRoot || mRoot->IsInUncomposedDoc());
if (presShell) { nsIDocument* rootDocument =
rootFrame = presShell->GetRootScrollFrame(); mRoot ? mRoot->GetUncomposedDoc() : GetTopLevelDocument(*aDocument);
if (rootFrame) { if (rootDocument) {
nsPresContext* presContext = rootFrame->PresContext(); if (nsIPresShell* presShell = rootDocument->GetShell()) {
while (!presContext->IsRootContentDocument()) { rootFrame = presShell->GetRootScrollFrame();
// Walk up the tree if (rootFrame) {
presContext = presContext->GetParentPresContext(); root = rootFrame->GetContent()->AsElement();
if (!presContext) { nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
break; if (scrollFrame) {
rootRect = scrollFrame->GetScrollPortRect();
} }
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
}
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
// If we end up with a null root frame for some reason, we'll proceed
// with an empty root intersection rect.
if (scrollFrame) {
rootRect = scrollFrame->GetScrollPortRect();
} }
} }
} }

View file

@ -145,7 +145,7 @@ public:
return mOwner; return mOwner;
} }
Element* GetRoot() const { nsINode* GetRoot() const {
return mRoot; return mRoot;
} }
@ -178,7 +178,7 @@ protected:
nsCOMPtr<nsPIDOMWindowInner> mOwner; nsCOMPtr<nsPIDOMWindowInner> mOwner;
RefPtr<nsIDocument> mDocument; RefPtr<nsIDocument> mDocument;
RefPtr<mozilla::dom::IntersectionCallback> mCallback; RefPtr<mozilla::dom::IntersectionCallback> mCallback;
RefPtr<Element> mRoot; RefPtr<nsINode> mRoot;
nsCSSRect mRootMargin; nsCSSRect mRootMargin;
nsTArray<double> mThresholds; nsTArray<double> mThresholds;

View file

@ -30,7 +30,7 @@ interface IntersectionObserverEntry {
Pref="dom.intersectionObserver.enabled"] Pref="dom.intersectionObserver.enabled"]
interface IntersectionObserver { interface IntersectionObserver {
[Constant] [Constant]
readonly attribute Element? root; readonly attribute Node? root;
[Constant] [Constant]
readonly attribute DOMString rootMargin; readonly attribute DOMString rootMargin;
[Constant,Cached] [Constant,Cached]
@ -56,7 +56,7 @@ dictionary IntersectionObserverEntryInit {
}; };
dictionary IntersectionObserverInit { dictionary IntersectionObserverInit {
Element? root = null; (Element or Document)? root = null;
DOMString rootMargin = "0px"; DOMString rootMargin = "0px";
(double or sequence<double>) threshold = 0; (double or sequence<double>) threshold = 0;
}; };