Bug 1581974 - Change DOMIntersectionObserver::Update to use the BrowsingContext parent chain. r=jwatt

Using the BrowsingUsing parent chain is able to avoid 1) obtaining a wrong
root in cross-process documents and also avoid 2) not being able to obtain
the proper root in same-origin documents in the case where there is a
cross-process document in between the top level document and the same-origin
documents.

dom/base/test/test_intersectionobservers.html is a test of case 1).
testing/web-platform/tests/intersection-observer/same-origin-grand-child-iframe.sub.html
is a test case of case 2).

Differential Revision: https://phabricator.services.mozilla.com/D46432
This commit is contained in:
Hiroyuki Ikezoe
2019-09-20 04:59:56 +00:00
parent b2d5c0664a
commit d9a5336c96
5 changed files with 69 additions and 28 deletions

View File

@@ -230,8 +230,26 @@ static BrowsingContextOrigin SimilarOrigin(const Element& aTarget,
: BrowsingContextOrigin::Different;
}
// NOTE: This returns nullptr if |aDocument| is in a cross process.
static Document* GetTopLevelDocument(const Document& aDocument) {
BrowsingContext* browsingContext = aDocument.GetBrowsingContext();
if (!browsingContext) {
return nullptr;
}
nsPIDOMWindowOuter* topWindow = browsingContext->Top()->GetDOMWindow();
if (!topWindow) {
// If we don't have a DOMWindow, We are not in same origin.
return nullptr;
}
return topWindow->GetExtantDoc();
}
void DOMIntersectionObserver::Update(Document* aDocument,
DOMHighResTimeStamp time) {
MOZ_ASSERT(aDocument);
nsRect rootRect;
nsIFrame* rootFrame = nullptr;
Element* root = mRoot;
@@ -252,28 +270,14 @@ void DOMIntersectionObserver::Update(Document* aDocument,
rootRect = nsLayoutUtils::TransformFrameRectToAncestor(
rootFrame, rootRectRelativeToRootFrame, containingBlock);
}
} else if (PresShell* presShell = aDocument->GetPresShell()) {
// FIXME(emilio): This shouldn't probably go through the presShell and just
// through the document tree.
rootFrame = presShell->GetRootScrollFrame();
if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) {
presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
nsIFrame* rootScrollFrame =
presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
} else if (Document* topLevelDocument = GetTopLevelDocument(*aDocument)) {
if (PresShell* presShell = topLevelDocument->GetPresShell()) {
rootFrame = presShell->GetRootScrollFrame();
if (rootFrame) {
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
rootRect = scrollFrame->GetScrollPortRect();
}
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
rootRect = scrollFrame->GetScrollPortRect();
}
}
@@ -401,12 +405,11 @@ void DOMIntersectionObserver::Update(Document* aDocument,
}
if (target->UpdateIntersectionObservation(this, threshold)) {
QueueIntersectionObserverEntry(target, time,
origin == BrowsingContextOrigin::Different
? Nothing()
: Some(rootIntersectionRect),
targetRect, intersectionRect,
intersectionRatio);
QueueIntersectionObserverEntry(
target, time,
origin == BrowsingContextOrigin::Similar ? Some(rootIntersectionRect)
: Nothing(),
targetRect, intersectionRect, intersectionRatio);
}
}
}