mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 14:55:44 -04:00
IntersectionObserver bug fix
This commit is contained in:
parent
8dc6679bf5
commit
a86941a552
@ -11,6 +11,7 @@
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -79,7 +80,20 @@ already_AddRefed<DOMIntersectionObserver> DOMIntersectionObserver::Constructor(
|
||||
RefPtr<DOMIntersectionObserver> observer =
|
||||
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());
|
||||
if (!StaticPrefs::
|
||||
dom_IntersectionObserverExplicitDocumentRoot_enabled()) {
|
||||
aRv.ThrowTypeError<dom::MSG_DOES_NOT_IMPLEMENT_INTERFACE>(
|
||||
"'root' member of IntersectionObserverInit", "Element");
|
||||
return nullptr;
|
||||
}
|
||||
observer->mRoot = aOptions.mRoot.Value().GetAsDocument();
|
||||
}
|
||||
}
|
||||
|
||||
if (!observer->SetRootMargin(aOptions.mRootMargin)) {
|
||||
aRv.ThrowSyntaxError("rootMargin must be specified in pixels or percent.");
|
||||
@ -207,7 +221,7 @@ enum class BrowsingContextOrigin { Similar, Different, Unknown };
|
||||
// contexts" is gone, but this is still in the spec, see
|
||||
// https://github.com/w3c/IntersectionObserver/issues/161
|
||||
static BrowsingContextOrigin SimilarOrigin(const Element& aTarget,
|
||||
const Element* aRoot) {
|
||||
const nsINode* aRoot) {
|
||||
if (!aRoot) {
|
||||
return BrowsingContextOrigin::Unknown;
|
||||
}
|
||||
@ -330,9 +344,9 @@ void DOMIntersectionObserver::Update(Document* aDocument,
|
||||
// the inflation until later.
|
||||
nsRect rootRect;
|
||||
nsIFrame* rootFrame = nullptr;
|
||||
Element* root = mRoot;
|
||||
if (mRoot) {
|
||||
if ((rootFrame = mRoot->GetPrimaryFrame())) {
|
||||
nsINode* root = mRoot;
|
||||
if (mRoot && mRoot->IsElement()) {
|
||||
if ((rootFrame = mRoot->AsElement()->GetPrimaryFrame())) {
|
||||
nsRect rootRectRelativeToRootFrame;
|
||||
if (rootFrame->IsScrollFrame()) {
|
||||
// rootRectRelativeToRootFrame should be the content rect of rootFrame,
|
||||
@ -348,28 +362,32 @@ 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 {
|
||||
MOZ_ASSERT(!mRoot || mRoot->IsDocument());
|
||||
Document* rootDocument = mRoot->AsDocument();
|
||||
if (rootDocument) {
|
||||
if (PresShell* presShell = rootDocument->GetPresShell()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
root = rootFrame->GetContent()->AsElement();
|
||||
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
|
||||
rootRect = scrollFrame->GetScrollPortRect();
|
||||
}
|
||||
}
|
||||
root = rootFrame->GetContent()->AsElement();
|
||||
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
|
||||
rootRect = scrollFrame->GetScrollPortRect();
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,10 +434,7 @@ void DOMIntersectionObserver::Update(Document* aDocument,
|
||||
|
||||
// 2.3. Let targetRect be a DOMRectReadOnly obtained by running the
|
||||
// getBoundingClientRect() algorithm on target.
|
||||
targetRect = nsLayoutUtils::GetAllInFlowRectsUnion(
|
||||
targetFrame,
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(targetFrame),
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
targetRect = targetFrame->GetBoundingClientRect();
|
||||
|
||||
// 2.4. Let intersectionRect be the result of running the compute the
|
||||
// intersection algorithm on target.
|
||||
@ -458,7 +473,9 @@ void DOMIntersectionObserver::Update(Document* aDocument,
|
||||
// length of observer.thresholds if intersectionRatio is greater than or
|
||||
// equal to the last entry in observer.thresholds.
|
||||
int32_t thresholdIndex = -1;
|
||||
// FIXME(emilio): Why the isIntersecting check?
|
||||
|
||||
// If not intersecting, we can just shortcut, as we know that the thresholds
|
||||
// are always between 0 and 1.
|
||||
if (isIntersecting) {
|
||||
thresholdIndex = mThresholds.IndexOfFirstElementGt(intersectionRatio);
|
||||
if (thresholdIndex == 0) {
|
||||
@ -468,19 +485,22 @@ void DOMIntersectionObserver::Update(Document* aDocument,
|
||||
// neither Chrome nor the WPT tests expect this behavior, so treat these
|
||||
// two cases as one.
|
||||
//
|
||||
// FIXME(emilio): Looks like a good candidate for a spec issue.
|
||||
// See https://github.com/w3c/IntersectionObserver/issues/432 about
|
||||
// this.
|
||||
thresholdIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Steps 2.10 - 2.15.
|
||||
if (target->UpdateIntersectionObservation(this, thresholdIndex)) {
|
||||
QueueIntersectionObserverEntry(target, time,
|
||||
origin == BrowsingContextOrigin::Different
|
||||
? Nothing()
|
||||
: Some(rootBounds),
|
||||
targetRect, intersectionRect,
|
||||
intersectionRatio);
|
||||
// See https://github.com/w3c/IntersectionObserver/issues/432 about
|
||||
// why we use thresholdIndex > 0 rather than isIntersecting for the
|
||||
// entry's isIntersecting value.
|
||||
QueueIntersectionObserverEntry(
|
||||
target, time,
|
||||
origin == BrowsingContextOrigin::Different ? Some(rootBounds)
|
||||
: Nothing(),
|
||||
targetRect, intersectionRect, thresholdIndex > 0, intersectionRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -488,7 +508,7 @@ void DOMIntersectionObserver::Update(Document* aDocument,
|
||||
void DOMIntersectionObserver::QueueIntersectionObserverEntry(
|
||||
Element* aTarget, DOMHighResTimeStamp time, const Maybe<nsRect>& aRootRect,
|
||||
const nsRect& aTargetRect, const Maybe<nsRect>& aIntersectionRect,
|
||||
double aIntersectionRatio) {
|
||||
bool aIsIntersecting, double aIntersectionRatio) {
|
||||
RefPtr<DOMRect> rootBounds;
|
||||
if (aRootRect.isSome()) {
|
||||
rootBounds = new DOMRect(this);
|
||||
@ -502,7 +522,7 @@ void DOMIntersectionObserver::QueueIntersectionObserverEntry(
|
||||
}
|
||||
RefPtr<DOMIntersectionObserverEntry> entry = new DOMIntersectionObserverEntry(
|
||||
this, time, rootBounds.forget(), boundingClientRect.forget(),
|
||||
intersectionRect.forget(), aIntersectionRect.isSome(), aTarget,
|
||||
intersectionRect.forget(), aIsIntersecting, aTarget,
|
||||
aIntersectionRatio);
|
||||
mQueuedEntries.AppendElement(entry.forget());
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ class DOMIntersectionObserverEntry final : public nsISupports,
|
||||
double aIntersectionRatio)
|
||||
: mOwner(aOwner),
|
||||
mTime(aTime),
|
||||
mRootBounds(aRootBounds),
|
||||
mBoundingClientRect(aBoundingClientRect),
|
||||
mIntersectionRect(aIntersectionRect),
|
||||
mRootBounds(std::move(aRootBounds)),
|
||||
mBoundingClientRect(std::move(aBoundingClientRect)),
|
||||
mIntersectionRect(std::move(aIntersectionRect)),
|
||||
mIsIntersecting(aIsIntersecting),
|
||||
mTarget(aTarget),
|
||||
mIntersectionRatio(aIntersectionRatio) {}
|
||||
@ -104,7 +104,7 @@ class DOMIntersectionObserver final : public nsISupports,
|
||||
|
||||
nsISupports* GetParentObject() const { return mOwner; }
|
||||
|
||||
Element* GetRoot() const { return mRoot; }
|
||||
nsINode* GetRoot() const { return mRoot; }
|
||||
|
||||
void GetRootMargin(nsACString&);
|
||||
bool SetRootMargin(const nsACString&);
|
||||
@ -128,12 +128,13 @@ class DOMIntersectionObserver final : public nsISupports,
|
||||
const Maybe<nsRect>& aRootRect,
|
||||
const nsRect& aTargetRect,
|
||||
const Maybe<nsRect>& aIntersectionRect,
|
||||
bool aIsIntersecting,
|
||||
double aIntersectionRatio);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mOwner;
|
||||
RefPtr<Document> mDocument;
|
||||
RefPtr<dom::IntersectionCallback> mCallback;
|
||||
RefPtr<Element> mRoot;
|
||||
RefPtr<nsINode> mRoot;
|
||||
StyleRect<LengthPercentage> mRootMargin;
|
||||
nsTArray<double> mThresholds;
|
||||
|
||||
|
@ -1075,10 +1075,7 @@ already_AddRefed<DOMRect> Element::GetBoundingClientRect() {
|
||||
return rect.forget();
|
||||
}
|
||||
|
||||
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(
|
||||
frame, nsLayoutUtils::GetContainingBlockForClientRect(frame),
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
rect->SetLayoutRect(r);
|
||||
rect->SetLayoutRect(frame->GetBoundingClientRect());
|
||||
return rect.forget();
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ interface IntersectionObserver {
|
||||
optional IntersectionObserverInit options = {});
|
||||
|
||||
[Constant]
|
||||
readonly attribute Element? root;
|
||||
readonly attribute Node? root;
|
||||
[Constant]
|
||||
readonly attribute UTF8String rootMargin;
|
||||
[Constant,Cached]
|
||||
@ -56,7 +56,7 @@ dictionary IntersectionObserverEntryInit {
|
||||
};
|
||||
|
||||
dictionary IntersectionObserverInit {
|
||||
Element? root = null;
|
||||
(Element or Document)? root = null;
|
||||
UTF8String rootMargin = "0px";
|
||||
(double or sequence<double>) threshold = 0;
|
||||
};
|
||||
|
@ -4735,6 +4735,8 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
|
||||
// appropriate nsDisplayAsyncZoom display items. This code handles the general
|
||||
// case with nested async zooms (even though that never actually happens),
|
||||
// because it fell out of the implementation for free.
|
||||
//
|
||||
// TODO: Do we need to do the same for ancestor transforms?
|
||||
for (nsPresContext* ctx = GetPresContext(); ctx;
|
||||
ctx = ctx->GetParentPresContext()) {
|
||||
PresShell* shell = ctx->PresShell();
|
||||
@ -4775,7 +4777,7 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
|
||||
// determine the offset of the reference frame for the display list
|
||||
// to the root frame. This will allow the coordinates used when painting
|
||||
// to all be offset from the same point
|
||||
info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame);
|
||||
info->mRootOffset = ancestorFrame->GetBoundingClientRect().TopLeft();
|
||||
rangeRect.MoveBy(info->mRootOffset);
|
||||
aSurfaceRect.UnionRect(aSurfaceRect, rangeRect);
|
||||
|
||||
|
@ -7432,6 +7432,12 @@ nsRect nsIFrame::GetNormalRect() const {
|
||||
return GetRect();
|
||||
}
|
||||
|
||||
nsRect nsIFrame::GetBoundingClientRect() {
|
||||
return nsLayoutUtils::GetAllInFlowRectsUnion(
|
||||
this, nsLayoutUtils::GetContainingBlockForClientRect(this),
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
}
|
||||
|
||||
nsPoint nsIFrame::GetPositionIgnoringScrolling() const {
|
||||
return GetParent() ? GetParent()->GetPositionOfChildIgnoringScrolling(this)
|
||||
: GetPosition();
|
||||
|
@ -1271,6 +1271,11 @@ class nsIFrame : public nsQueryFrame {
|
||||
*/
|
||||
nsRect GetNormalRect() const;
|
||||
|
||||
/**
|
||||
* Returns frame's rect as required by the GetBoundingClientRect() DOM API.
|
||||
*/
|
||||
nsRect GetBoundingClientRect();
|
||||
|
||||
/**
|
||||
* Return frame's position without relative positioning.
|
||||
* If aHasProperty is provided, returns whether the normal position
|
||||
|
@ -1640,6 +1640,11 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: dom.IntersectionObserverExplicitDocumentRoot.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: dom.ipc.cancel_content_js_when_navigating
|
||||
type: bool
|
||||
value: true
|
||||
|
@ -1 +1 @@
|
||||
prefs: [dom.IntersectionObserver.enabled:true]
|
||||
prefs: [dom.IntersectionObserver.enabled:true, dom.IntersectionObserverExplicitDocumentRoot.enabled:true]
|
||||
|
@ -1,4 +0,0 @@
|
||||
[initial-observation-with-threshold.html]
|
||||
[First rAF]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<title>A height: 100% descendant should trigger a relayout when stretching.</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#definite-sizes" />
|
||||
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1043071" />
|
||||
<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
|
||||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div style="display: flex; width: 100px;">
|
||||
<div style="display: flex; flex-direction: column; flex: 1; min-height: 100px;">
|
||||
<div style="flex: 1; background: red;">
|
||||
<div style="height: 100%; background-color: green;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="./resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
iframe {
|
||||
height: 250px;
|
||||
width: 150px;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
<iframe id="target-iframe" src="resources/iframe-no-root-subframe.html"></iframe>
|
||||
|
||||
<script>
|
||||
var iframe = document.getElementById("target-iframe");
|
||||
var target;
|
||||
var root;
|
||||
var entries = [];
|
||||
|
||||
iframe.onload = function() {
|
||||
runTestCycle(function() {
|
||||
assert_true(!!iframe, "iframe exists");
|
||||
|
||||
target = iframe.contentDocument.getElementById("target");
|
||||
assert_true(!!target, "Target element exists.");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, { root: iframe.contentDocument });
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.");
|
||||
}, "Observer with explicit root which is the document.");
|
||||
};
|
||||
|
||||
function step0() {
|
||||
let vw = iframe.contentDocument.documentElement.clientWidth;
|
||||
let vh = iframe.contentDocument.documentElement.clientHeight;
|
||||
// The target element is partially clipped by the iframe's root scroller, so
|
||||
// height of the intersection rect is (250 - 208) == 42.
|
||||
checkLastEntry(entries, 0, [8, 108, 208, 308, 8, 108, 208, 250, 0, vw, 0, vh, true]);
|
||||
}
|
||||
</script>
|
@ -43,7 +43,8 @@ function step3() {
|
||||
assert_equals(entries.length, 2);
|
||||
assert_true(entries[1].intersectionRatio >= 0.5 &&
|
||||
entries[1].intersectionRatio < 1);
|
||||
assert_equals(entries[1].isIntersecting, true);
|
||||
// See https://github.com/w3c/IntersectionObserver/issues/432
|
||||
assert_equals(entries[1].isIntersecting, false);
|
||||
scroller.scrollTop = 100;
|
||||
}
|
||||
|
||||
|
@ -676,9 +676,8 @@ nsresult nsBaseDragService::DrawDrag(nsINode* aDOMNode,
|
||||
// otherwise, there was no region so just set the rectangle to
|
||||
// the size of the primary frame of the content.
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(dragNode);
|
||||
nsIFrame* frame = content->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
presLayoutRect = frame->GetRect();
|
||||
if (nsIFrame* frame = content->GetPrimaryFrame()) {
|
||||
presLayoutRect = frame->GetBoundingClientRect();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user