From c9d920e9c630fd8b99b863e034742fd3b38e12d3 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 02:15:50 +0100 Subject: Revise lifetime management of IntersectionObservers. Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index e39abf1a6..cb624fb17 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -43,16 +43,18 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER + tmp->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries) - tmp->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries) @@ -185,10 +187,11 @@ DOMIntersectionObserver::Connect() if (mConnected) { return; } + mConnected = true; - - nsIDocument* document = mOwner->GetExtantDoc(); - document->AddIntersectionObserver(this); + if(mDocument) { + mDocument->AddIntersectionObserver(this); + } } void @@ -202,11 +205,8 @@ DOMIntersectionObserver::Disconnect() target->UnregisterIntersectionObserver(this); } mObservationTargets.Clear(); - if (mOwner) { - nsIDocument* document = mOwner->GetExtantDoc(); - if (document) { - document->RemoveIntersectionObserver(this); - } + if (mDocument) { + mDocument->RemoveIntersectionObserver(this); } mConnected = false; } -- cgit v1.2.3 From 107a68cb1d12aa6ed74e4ca414e5f05e4a92c963 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 06:30:39 +0100 Subject: Intersection ratio should be 1.0 for zero-area intersections. Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index cb624fb17..0834bc05c 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -411,7 +411,13 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time double targetArea = targetRect.width * targetRect.height; double intersectionArea = !intersectionRect ? 0 : intersectionRect->width * intersectionRect->height; - double intersectionRatio = targetArea > 0.0 ? intersectionArea / targetArea : 0.0; + + double intersectionRatio; + if (targetArea > 0.0) { + intersectionRatio = intersectionArea / targetArea; + } else { + intersectionRatio = intersectionRect.isSome() ? 1.0 : 0.0; + } size_t threshold = -1; if (intersectionRatio > 0.0) { -- cgit v1.2.3 From 0626e1cef06081bf93ee45eab47f6520816c967f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 07:33:31 +0100 Subject: Use targetFrame->GetRectRelativeToSelf() as the initial intersection rect. Tag #249. --- dom/base/DOMIntersectionObserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 0834bc05c..f0be34ec0 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -344,7 +344,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time nsLayoutUtils::GetContainingBlockForClientRect(targetFrame), nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS ); - intersectionRect = Some(targetFrame->GetVisualOverflowRect()); + intersectionRect = Some(targetFrame->GetRectRelativeToSelf()); nsIFrame* containerFrame = nsLayoutUtils::GetCrossDocParentFrame(targetFrame); while (containerFrame && containerFrame != rootFrame) { -- cgit v1.2.3 From 6cfd7509c781c11a99edb4332bc7b0142eb57faf Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 14:10:14 +0100 Subject: Map intersectionRect to the coordinate space of the target document. Spec says: "Map intersectionRect to the coordinate space of the viewport of the Document containing the target." Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index f0be34ec0..5798335b4 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -319,6 +319,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time nsIFrame* targetFrame = target->GetPrimaryFrame(); nsRect targetRect; Maybe intersectionRect; + bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc(); if (rootFrame && targetFrame) { // If mRoot is set we are testing intersection with a container element @@ -327,7 +328,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time // Skip further processing of this target if it is not in the same // Document as the intersection root, e.g. if root is an element of // the main document and target an element from an embedded iframe. - if (target->GetComposedDoc() != root->GetComposedDoc()) { + if (!isSameDoc) { continue; } // Skip further processing of this target if is not a descendant of the @@ -399,12 +400,12 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time intersectionRectRelativeToRoot, rootIntersectionRect ); - if (intersectionRect.isSome()) { - intersectionRect = Some(nsLayoutUtils::TransformFrameRectToAncestor( - nsLayoutUtils::GetContainingBlockForClientRect(rootFrame), - intersectionRect.value(), - targetFrame->PresContext()->PresShell()->GetRootScrollFrame() - )); + if (intersectionRect.isSome() && !isSameDoc) { + nsRect rect = intersectionRect.value(); + nsPresContext* presContext = targetFrame->PresContext(); + nsLayoutUtils::TransformRect(rootFrame, + presContext->PresShell()->GetRootScrollFrame(), rect); + intersectionRect = Some(rect); } } -- cgit v1.2.3 From fa97cddb3910ce8c35992d3ad2ec0fda060e3041 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 14:34:42 +0100 Subject: Use content area as the intersection rectangle ... ... for custom root with overflow clip. Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 5798335b4..f5e59c2b9 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -269,17 +269,21 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time root = mRoot; rootFrame = root->GetPrimaryFrame(); if (rootFrame) { + nsRect rootRectRelativeToRootFrame; if (rootFrame->GetType() == nsGkAtoms::scrollFrame) { + // rootRectRelativeToRootFrame should be the content rect of rootFrame, not including the scrollbars. nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame); - rootRect = nsLayoutUtils::TransformFrameRectToAncestor( - rootFrame, - rootFrame->GetContentRectRelativeToSelf(), - scrollFrame->GetScrolledFrame()); + rootRectRelativeToRootFrame = scrollFrame->GetScrollPortRect(); } else { - rootRect = nsLayoutUtils::GetAllInFlowRectsUnion(rootFrame, - nsLayoutUtils::GetContainingBlockForClientRect(rootFrame), - nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + // rootRectRelativeToRootFrame should be the border rect of rootFrame. + rootRectRelativeToRootFrame = rootFrame->GetRectRelativeToSelf(); } + nsIFrame* containingBlock = + nsLayoutUtils::GetContainingBlockForClientRect(rootFrame); + rootRect = + nsLayoutUtils::TransformFrameRectToAncestor(rootFrame, + rootRectRelativeToRootFrame, + containingBlock); } } else { nsCOMPtr presShell = aDocument->GetShell(); -- cgit v1.2.3 From 85d43d68bb32e484167bdeb0b6d78c60d44444d2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 14:35:26 +0100 Subject: Fix singed/unsigned type confusion for intersection threshold. Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index f5e59c2b9..650ec83cd 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -424,15 +424,15 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time intersectionRatio = intersectionRect.isSome() ? 1.0 : 0.0; } - size_t threshold = -1; + int32_t threshold = -1; if (intersectionRatio > 0.0) { if (intersectionRatio >= 1.0) { intersectionRatio = 1.0; - threshold = mThresholds.Length(); + threshold = (int32_t)mThresholds.Length(); } else { for (size_t k = 0; k < mThresholds.Length(); ++k) { if (mThresholds[k] <= intersectionRatio) { - threshold = k + 1; + threshold = (int32_t)k + 1; } else { break; } -- cgit v1.2.3 From 7771a8716d4bc135adadf95cf9ddf976f4294fba Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 22 Dec 2018 14:59:46 +0100 Subject: [intersection-observer] Calculate areas using int64_t. Tag #249 --- dom/base/DOMIntersectionObserver.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 650ec83cd..2f3a341c5 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -413,13 +413,15 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time } } - double targetArea = targetRect.width * targetRect.height; - double intersectionArea = !intersectionRect ? - 0 : intersectionRect->width * intersectionRect->height; + int64_t targetArea = + (int64_t) targetRect.Width() * (int64_t) targetRect.Height(); + int64_t intersectionArea = !intersectionRect ? 0 : + (int64_t) intersectionRect->Width() * + (int64_t) intersectionRect->Height(); double intersectionRatio; if (targetArea > 0.0) { - intersectionRatio = intersectionArea / targetArea; + intersectionRatio = (double) intersectionArea / (double) targetArea; } else { intersectionRatio = intersectionRect.isSome() ? 1.0 : 0.0; } -- cgit v1.2.3 From 3cf7e874fecf940ffeec00bafd3cf96d5c1b2a46 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 24 Dec 2018 01:58:16 +0100 Subject: Fix crashiness of IntersectionObservers. Mozilla hashtables -still- suck. --- dom/base/DOMIntersectionObserver.cpp | 39 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 2f3a341c5..e7b3cd0da 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -155,30 +155,29 @@ DOMIntersectionObserver::Observe(Element& aTarget) return; } aTarget.RegisterIntersectionObserver(this); - mObservationTargets.PutEntry(&aTarget); + mObservationTargets.AppendElement(&aTarget); Connect(); } void DOMIntersectionObserver::Unobserve(Element& aTarget) { - if (UnlinkTarget(aTarget)) { - aTarget.UnregisterIntersectionObserver(this); + if (mObservationTargets.Length() == 1) { + Disconnect(); + return; } + + mObservationTargets.RemoveElement(&aTarget); + aTarget.UnregisterIntersectionObserver(this); } -bool +void DOMIntersectionObserver::UnlinkTarget(Element& aTarget) { - if (!mObservationTargets.Contains(&aTarget)) { - return false; - } - if (mObservationTargets.Count() == 1) { - Disconnect(); - return false; - } - mObservationTargets.RemoveEntry(&aTarget); - return true; + mObservationTargets.RemoveElement(&aTarget); + if (mObservationTargets.Length() == 0) { + Disconnect(); + } } void @@ -200,15 +199,17 @@ DOMIntersectionObserver::Disconnect() if (!mConnected) { return; } - for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) { - Element* target = iter.Get()->GetKey(); + + mConnected = false; + + for (size_t i = 0; i < mObservationTargets.Length(); ++i) { + Element* target = mObservationTargets.ElementAt(i); target->UnregisterIntersectionObserver(this); } mObservationTargets.Clear(); if (mDocument) { mDocument->RemoveIntersectionObserver(this); } - mConnected = false; } void @@ -318,8 +319,8 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time rootMargin.Side(side) = nsLayoutUtils::ComputeCBDependentValue(basis, coord); } - for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) { - Element* target = iter.Get()->GetKey(); + for (size_t i = 0; i < mObservationTargets.Length(); ++i) { + Element* target = mObservationTargets.ElementAt(i); nsIFrame* targetFrame = target->GetPrimaryFrame(); nsRect targetRect; Maybe intersectionRect; @@ -493,7 +494,7 @@ DOMIntersectionObserver::Notify() } mozilla::dom::Sequence> entries; if (entries.SetCapacity(mQueuedEntries.Length(), mozilla::fallible)) { - for (uint32_t i = 0; i < mQueuedEntries.Length(); ++i) { + for (size_t i = 0; i < mQueuedEntries.Length(); ++i) { RefPtr next = mQueuedEntries[i]; *entries.AppendElement(mozilla::fallible) = next; } -- cgit v1.2.3 From f6ef8d8ca7ed96d699c28914fc590b0604520fd0 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 17 Jan 2019 19:02:50 +0100 Subject: Add isIntersecting property to IntersectionObserverEntry. Per updated spec. This resolves the issue raised in #249. --- dom/base/DOMIntersectionObserver.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index e7b3cd0da..0264a105e 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -482,6 +482,7 @@ DOMIntersectionObserver::QueueIntersectionObserverEntry(Element* aTarget, rootBounds.forget(), boundingClientRect.forget(), intersectionRect.forget(), + aIntersectionRect.isSome(), aTarget, aIntersectionRatio); mQueuedEntries.AppendElement(entry.forget()); } -- cgit v1.2.3 From ef8a5dca4f49f859c5b5a7fa9e079b2b7b9bf8fa Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 18 Jan 2019 19:09:30 +0100 Subject: Rewrite IntersectionObserver list handling to be more robust. Tag #935. --- dom/base/DOMIntersectionObserver.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 0264a105e..e671b7da9 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -162,6 +162,11 @@ DOMIntersectionObserver::Observe(Element& aTarget) void DOMIntersectionObserver::Unobserve(Element& aTarget) { + if (!mObservationTargets.Contains(&aTarget)) { + // You're not on the list, buddy! + return; + } + if (mObservationTargets.Length() == 1) { Disconnect(); return; @@ -188,7 +193,7 @@ DOMIntersectionObserver::Connect() } mConnected = true; - if(mDocument) { + if (mDocument) { mDocument->AddIntersectionObserver(this); } } @@ -293,12 +298,25 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time if (rootFrame) { nsPresContext* presContext = rootFrame->PresContext(); while (!presContext->IsRootContentDocument()) { - presContext = rootFrame->PresContext()->GetParentPresContext(); - rootFrame = presContext->PresShell()->GetRootScrollFrame(); + // Walk up the tree + 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(); + // 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(); + } } } } -- cgit v1.2.3 From 1f9ab3a6e6e3f1e79b482c0540c98859bbc71350 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 18 Jan 2019 22:43:29 +0100 Subject: Remove NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS --- dom/base/DOMIntersectionObserver.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'dom/base/DOMIntersectionObserver.cpp') diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index e671b7da9..389b93071 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -52,7 +52,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) -- cgit v1.2.3