Commit ab28ef1a authored by Stefan Zager's avatar Stefan Zager Committed by Commit Bot

[IntersectionObserver] Allow Document argument to constructor

This implements a behavioral change as described in:

https://github.com/w3c/IntersectionObserver/issues/372

If the 'root' argument to the IntersectionObserver constructor is a
Document, then the observer will clip to the Document's root
scroller. For the top Document, this is the same behavior as the
implicit root. For an iframe Document, this is new behavior which is
unobtainable by other means.

BUG=1015183

Change-Id: I234bfce28ab954bb15b8d157bc22ee2d2469d5e4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2003750Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Commit-Queue: Stefan Zager <szager@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734268}
parent 116bd95e
...@@ -40,6 +40,8 @@ bindings_core_generated_union_type_files = [ ...@@ -40,6 +40,8 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/double_or_string.h", "$bindings_core_v8_output_dir/double_or_string.h",
"$bindings_core_v8_output_dir/double_or_string_or_string_sequence.cc", "$bindings_core_v8_output_dir/double_or_string_or_string_sequence.cc",
"$bindings_core_v8_output_dir/double_or_string_or_string_sequence.h", "$bindings_core_v8_output_dir/double_or_string_or_string_sequence.h",
"$bindings_core_v8_output_dir/element_or_document.cc",
"$bindings_core_v8_output_dir/element_or_document.h",
"$bindings_core_v8_output_dir/event_listener_options_or_boolean.cc", "$bindings_core_v8_output_dir/event_listener_options_or_boolean.cc",
"$bindings_core_v8_output_dir/event_listener_options_or_boolean.h", "$bindings_core_v8_output_dir/event_listener_options_or_boolean.h",
"$bindings_core_v8_output_dir/file_or_usv_string.cc", "$bindings_core_v8_output_dir/file_or_usv_string.cc",
......
...@@ -226,6 +226,7 @@ ...@@ -226,6 +226,7 @@
#include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h" #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
#include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_entry.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_entry.h"
#include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h" #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
...@@ -6839,6 +6840,20 @@ Document::EnsureIntersectionObserverController() { ...@@ -6839,6 +6840,20 @@ Document::EnsureIntersectionObserverController() {
return *intersection_observer_controller_; return *intersection_observer_controller_;
} }
ElementIntersectionObserverData*
Document::DocumentExplicitRootIntersectionObserverData() const {
return document_explicit_root_intersection_observer_data_.Get();
}
ElementIntersectionObserverData&
Document::EnsureDocumentExplicitRootIntersectionObserverData() {
if (!document_explicit_root_intersection_observer_data_) {
document_explicit_root_intersection_observer_data_ =
MakeGarbageCollected<ElementIntersectionObserverData>();
}
return *document_explicit_root_intersection_observer_data_;
}
ResizeObserverController& Document::EnsureResizeObserverController() { ResizeObserverController& Document::EnsureResizeObserverController() {
if (!resize_observer_controller_) { if (!resize_observer_controller_) {
resize_observer_controller_ = resize_observer_controller_ =
...@@ -7824,6 +7839,7 @@ void Document::Trace(Visitor* visitor) { ...@@ -7824,6 +7839,7 @@ void Document::Trace(Visitor* visitor) {
visitor->Trace(elem_sheet_); visitor->Trace(elem_sheet_);
visitor->Trace(node_iterators_); visitor->Trace(node_iterators_);
visitor->Trace(ranges_); visitor->Trace(ranges_);
visitor->Trace(document_explicit_root_intersection_observer_data_);
visitor->Trace(style_engine_); visitor->Trace(style_engine_);
visitor->Trace(form_controller_); visitor->Trace(form_controller_);
visitor->Trace(visited_link_state_); visitor->Trace(visited_link_state_);
......
...@@ -98,6 +98,7 @@ class CanvasFontCache; ...@@ -98,6 +98,7 @@ class CanvasFontCache;
class ChromeClient; class ChromeClient;
class Comment; class Comment;
class ComputedAccessibleNode; class ComputedAccessibleNode;
class ElementIntersectionObserverData;
class WindowAgent; class WindowAgent;
class WindowAgentFactory; class WindowAgentFactory;
class ComputedStyle; class ComputedStyle;
...@@ -954,6 +955,14 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -954,6 +955,14 @@ class CORE_EXPORT Document : public ContainerNode,
IntersectionObserverController* GetIntersectionObserverController(); IntersectionObserverController* GetIntersectionObserverController();
IntersectionObserverController& EnsureIntersectionObserverController(); IntersectionObserverController& EnsureIntersectionObserverController();
// This is used to track IntersectionObservers for which this document is the
// explicit root. The IntersectionObserverController tracks *all* observers
// associated with this document; usually that's what you want.
ElementIntersectionObserverData*
DocumentExplicitRootIntersectionObserverData() const;
ElementIntersectionObserverData&
EnsureDocumentExplicitRootIntersectionObserverData();
ResizeObserverController* GetResizeObserverController() const { ResizeObserverController* GetResizeObserverController() const {
return resize_observer_controller_; return resize_observer_controller_;
} }
...@@ -1886,6 +1895,9 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -1886,6 +1895,9 @@ class CORE_EXPORT Document : public ContainerNode,
MutationObserverOptions mutation_observer_types_; MutationObserverOptions mutation_observer_types_;
Member<ElementIntersectionObserverData>
document_explicit_root_intersection_observer_data_;
Member<StyleEngine> style_engine_; Member<StyleEngine> style_engine_;
Member<StyleSheetList> style_sheet_list_; Member<StyleSheetList> style_sheet_list_;
......
...@@ -188,29 +188,29 @@ IntersectionGeometry::RootGeometry::RootGeometry(const LayoutObject* root, ...@@ -188,29 +188,29 @@ IntersectionGeometry::RootGeometry::RootGeometry(const LayoutObject* root,
root_to_document_transform = transform_state.AccumulatedTransform(); root_to_document_transform = transform_state.AccumulatedTransform();
} }
// If root_element is non-null, it is treated as the explicit root of an // If root_node is non-null, it is treated as the explicit root of an
// IntersectionObserver; if it is valid, its LayoutObject is returned. // IntersectionObserver; if it is valid, its LayoutObject is returned.
// //
// If root_element is null, returns the object to be used as the implicit root // If root_node is null, returns the object to be used as the implicit root
// for a given target. // for a given target.
// //
// https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-root // https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-root
const LayoutObject* IntersectionGeometry::GetRootLayoutObjectForTarget( const LayoutObject* IntersectionGeometry::GetRootLayoutObjectForTarget(
const Element* root_element, const Node* root_node,
LayoutObject* target, LayoutObject* target,
bool check_containing_block_chain) { bool check_containing_block_chain) {
if (!root_element) if (!root_node)
return target ? LocalRootView(*target) : nullptr; return target ? LocalRootView(*target) : nullptr;
if (!root_element->isConnected()) if (!root_node->isConnected())
return nullptr; return nullptr;
LayoutObject* root = nullptr; LayoutObject* root = nullptr;
if (RuntimeEnabledFeatures:: if (RuntimeEnabledFeatures::
IntersectionObserverDocumentScrollingElementRootEnabled() && IntersectionObserverDocumentScrollingElementRootEnabled() &&
root_element == root_element->GetDocument().scrollingElement()) { root_node->IsDocumentNode()) {
root = root_element->GetDocument().GetLayoutView(); root = To<Document>(root_node)->GetLayoutView();
} else { } else {
root = root_element->GetLayoutObject(); root = root_node->GetLayoutObject();
if (target && check_containing_block_chain && if (target && check_containing_block_chain &&
!IsContainingBlockChainDescendant(target, root)) { !IsContainingBlockChainDescendant(target, root)) {
root = nullptr; root = nullptr;
...@@ -219,7 +219,7 @@ const LayoutObject* IntersectionGeometry::GetRootLayoutObjectForTarget( ...@@ -219,7 +219,7 @@ const LayoutObject* IntersectionGeometry::GetRootLayoutObjectForTarget(
return root; return root;
} }
IntersectionGeometry::IntersectionGeometry(const Element* root_element, IntersectionGeometry::IntersectionGeometry(const Node* root_node,
const Element& target_element, const Element& target_element,
const Vector<Length>& root_margin, const Vector<Length>& root_margin,
const Vector<float>& thresholds, const Vector<float>& thresholds,
...@@ -230,13 +230,13 @@ IntersectionGeometry::IntersectionGeometry(const Element* root_element, ...@@ -230,13 +230,13 @@ IntersectionGeometry::IntersectionGeometry(const Element* root_element,
threshold_index_(0) { threshold_index_(0) {
if (cached_rects) if (cached_rects)
cached_rects->valid = false; cached_rects->valid = false;
if (!root_element) if (!root_node)
flags_ |= kRootIsImplicit; flags_ |= kRootIsImplicit;
LayoutObject* target = GetTargetLayoutObject(target_element); LayoutObject* target = GetTargetLayoutObject(target_element);
if (!target) if (!target)
return; return;
const LayoutObject* root = GetRootLayoutObjectForTarget( const LayoutObject* root =
root_element, target, !ShouldUseCachedRects()); GetRootLayoutObjectForTarget(root_node, target, !ShouldUseCachedRects());
if (!root) if (!root)
return; return;
RootGeometry root_geometry(root, root_margin); RootGeometry root_geometry(root, root_margin);
...@@ -244,7 +244,7 @@ IntersectionGeometry::IntersectionGeometry(const Element* root_element, ...@@ -244,7 +244,7 @@ IntersectionGeometry::IntersectionGeometry(const Element* root_element,
} }
IntersectionGeometry::IntersectionGeometry(const RootGeometry& root_geometry, IntersectionGeometry::IntersectionGeometry(const RootGeometry& root_geometry,
const Element& explicit_root, const Node& explicit_root,
const Element& target_element, const Element& target_element,
const Vector<float>& thresholds, const Vector<float>& thresholds,
unsigned flags, unsigned flags,
......
...@@ -17,8 +17,9 @@ namespace blink { ...@@ -17,8 +17,9 @@ namespace blink {
class Element; class Element;
class LayoutObject; class LayoutObject;
class Node;
// Computes the intersection between an ancestor (root) element and a // Computes the intersection between an ancestor (root) node and a
// descendant (target) element, with overflow and CSS clipping applied. // descendant (target) element, with overflow and CSS clipping applied.
// Optionally also checks whether the target is occluded or has visual // Optionally also checks whether the target is occluded or has visual
// effects applied. // effects applied.
...@@ -67,11 +68,11 @@ class CORE_EXPORT IntersectionGeometry { ...@@ -67,11 +68,11 @@ class CORE_EXPORT IntersectionGeometry {
}; };
static const LayoutObject* GetRootLayoutObjectForTarget( static const LayoutObject* GetRootLayoutObjectForTarget(
const Element* root_element, const Node* root_node,
LayoutObject* target, LayoutObject* target,
bool check_containing_block_chain); bool check_containing_block_chain);
IntersectionGeometry(const Element* root, IntersectionGeometry(const Node* root,
const Element& target, const Element& target,
const Vector<Length>& root_margin, const Vector<Length>& root_margin,
const Vector<float>& thresholds, const Vector<float>& thresholds,
...@@ -79,7 +80,7 @@ class CORE_EXPORT IntersectionGeometry { ...@@ -79,7 +80,7 @@ class CORE_EXPORT IntersectionGeometry {
CachedRects* cached_rects = nullptr); CachedRects* cached_rects = nullptr);
IntersectionGeometry(const RootGeometry& root_geometry, IntersectionGeometry(const RootGeometry& root_geometry,
const Element& explicit_root, const Node& explicit_root,
const Element& target, const Element& target,
const Vector<float>& thresholds, const Vector<float>& thresholds,
unsigned flags, unsigned flags,
......
...@@ -160,7 +160,12 @@ IntersectionObserver* IntersectionObserver::Create( ...@@ -160,7 +160,12 @@ IntersectionObserver* IntersectionObserver::Create(
const IntersectionObserverInit* observer_init, const IntersectionObserverInit* observer_init,
IntersectionObserverDelegate& delegate, IntersectionObserverDelegate& delegate,
ExceptionState& exception_state) { ExceptionState& exception_state) {
Element* root = observer_init->root(); Node* root = nullptr;
if (observer_init->root().IsElement()) {
root = observer_init->root().GetAsElement();
} else if (observer_init->root().IsDocument()) {
root = observer_init->root().GetAsDocument();
}
DOMHighResTimeStamp delay = 0; DOMHighResTimeStamp delay = 0;
bool track_visibility = false; bool track_visibility = false;
...@@ -231,7 +236,7 @@ IntersectionObserver* IntersectionObserver::Create( ...@@ -231,7 +236,7 @@ IntersectionObserver* IntersectionObserver::Create(
IntersectionObserver::IntersectionObserver( IntersectionObserver::IntersectionObserver(
IntersectionObserverDelegate& delegate, IntersectionObserverDelegate& delegate,
Element* root, Node* root,
const Vector<Length>& root_margin, const Vector<Length>& root_margin,
const Vector<float>& thresholds, const Vector<float>& thresholds,
ThresholdInterpretation semantics, ThresholdInterpretation semantics,
...@@ -277,7 +282,14 @@ IntersectionObserver::IntersectionObserver( ...@@ -277,7 +282,14 @@ IntersectionObserver::IntersectionObserver(
break; break;
} }
if (root) { if (root) {
root->EnsureIntersectionObserverData().AddObserver(*this); if (root->IsDocumentNode()) {
To<Document>(root)
->EnsureDocumentExplicitRootIntersectionObserverData()
.AddObserver(*this);
} else {
DCHECK(root->IsElementNode());
To<Element>(root)->EnsureIntersectionObserverData().AddObserver(*this);
}
root->GetDocument() root->GetDocument()
.EnsureIntersectionObserverController() .EnsureIntersectionObserverController()
.AddTrackedObserver(*this, track_visibility); .AddTrackedObserver(*this, track_visibility);
......
...@@ -24,6 +24,7 @@ class ExceptionState; ...@@ -24,6 +24,7 @@ class ExceptionState;
class IntersectionObserverDelegate; class IntersectionObserverDelegate;
class IntersectionObserverEntry; class IntersectionObserverEntry;
class IntersectionObserverInit; class IntersectionObserverInit;
class Node;
class ScriptState; class ScriptState;
class V8IntersectionObserverCallback; class V8IntersectionObserverCallback;
...@@ -98,7 +99,7 @@ class CORE_EXPORT IntersectionObserver final ...@@ -98,7 +99,7 @@ class CORE_EXPORT IntersectionObserver final
static void ResumeSuspendedObservers(); static void ResumeSuspendedObservers();
explicit IntersectionObserver(IntersectionObserverDelegate&, explicit IntersectionObserver(IntersectionObserverDelegate&,
Element*, Node*,
const Vector<Length>& root_margin, const Vector<Length>& root_margin,
const Vector<float>& thresholds, const Vector<float>& thresholds,
ThresholdInterpretation semantics, ThresholdInterpretation semantics,
...@@ -114,14 +115,14 @@ class CORE_EXPORT IntersectionObserver final ...@@ -114,14 +115,14 @@ class CORE_EXPORT IntersectionObserver final
ExceptionState& = ASSERT_NO_EXCEPTION); ExceptionState& = ASSERT_NO_EXCEPTION);
// API attributes. // API attributes.
Element* root() const { return root_.Get(); } Node* root() const { return root_.Get(); }
String rootMargin() const; String rootMargin() const;
const Vector<float>& thresholds() const { return thresholds_; } const Vector<float>& thresholds() const { return thresholds_; }
DOMHighResTimeStamp delay() const { return delay_; } DOMHighResTimeStamp delay() const { return delay_; }
bool trackVisibility() const { return track_visibility_; } bool trackVisibility() const { return track_visibility_; }
bool trackFractionOfRoot() const { return track_fraction_of_root_; } bool trackFractionOfRoot() const { return track_fraction_of_root_; }
// An observer can either track intersections with an explicit root Element, // An observer can either track intersections with an explicit root Node,
// or with the the top-level frame's viewport (the "implicit root"). When // or with the the top-level frame's viewport (the "implicit root"). When
// tracking the implicit root, root_ will be null, but because root_ is a // tracking the implicit root, root_ will be null, but because root_ is a
// weak pointer, we cannot surmise that this observer tracks the implicit // weak pointer, we cannot surmise that this observer tracks the implicit
...@@ -147,7 +148,7 @@ class CORE_EXPORT IntersectionObserver final ...@@ -147,7 +148,7 @@ class CORE_EXPORT IntersectionObserver final
DeliveryBehavior GetDeliveryBehavior() const; DeliveryBehavior GetDeliveryBehavior() const;
void Deliver(); void Deliver();
// Returns false if this observer has an explicit root element which has been // Returns false if this observer has an explicit root node which has been
// deleted; true otherwise. // deleted; true otherwise.
bool RootIsValid() const; bool RootIsValid() const;
bool CanUseCachedRects() const { return can_use_cached_rects_; } bool CanUseCachedRects() const { return can_use_cached_rects_; }
...@@ -166,7 +167,7 @@ class CORE_EXPORT IntersectionObserver final ...@@ -166,7 +167,7 @@ class CORE_EXPORT IntersectionObserver final
void ProcessCustomWeakness(const WeakCallbackInfo&); void ProcessCustomWeakness(const WeakCallbackInfo&);
const Member<IntersectionObserverDelegate> delegate_; const Member<IntersectionObserverDelegate> delegate_;
UntracedMember<Element> root_; UntracedMember<Node> root_;
HeapLinkedHashSet<WeakMember<IntersectionObservation>> observations_; HeapLinkedHashSet<WeakMember<IntersectionObservation>> observations_;
Vector<float> thresholds_; Vector<float> thresholds_;
DOMHighResTimeStamp delay_; DOMHighResTimeStamp delay_;
......
...@@ -10,8 +10,8 @@ callback IntersectionObserverCallback = void (sequence<IntersectionObserverEntry ...@@ -10,8 +10,8 @@ callback IntersectionObserverCallback = void (sequence<IntersectionObserverEntry
Exposed=Window, Exposed=Window,
ActiveScriptWrappable ActiveScriptWrappable
] interface IntersectionObserver { ] interface IntersectionObserver {
[CallWith=ScriptState, RaisesException, MeasureAs=IntersectionObserver_Constructor] constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options = {}); [CallWith=ScriptState, RaisesException, MeasureAs=IntersectionObserver_Constructor] constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options);
readonly attribute Element? root; readonly attribute Node? root;
readonly attribute DOMString rootMargin; readonly attribute DOMString rootMargin;
// https://github.com/WICG/IntersectionObserver/issues/114 // https://github.com/WICG/IntersectionObserver/issues/114
readonly attribute FrozenArray<double> thresholds; readonly attribute FrozenArray<double> thresholds;
......
...@@ -54,6 +54,7 @@ class IntersectionObserverController ...@@ -54,6 +54,7 @@ class IntersectionObserverController
const char* NameInHeapSnapshot() const override { const char* NameInHeapSnapshot() const override {
return "IntersectionObserverController"; return "IntersectionObserverController";
} }
unsigned GetTrackedObserverCountForTesting() const { unsigned GetTrackedObserverCountForTesting() const {
return explicit_root_observers_.size(); return explicit_root_observers_.size();
} }
...@@ -72,7 +73,7 @@ class IntersectionObserverController ...@@ -72,7 +73,7 @@ class IntersectionObserverController
// IntersectionObservers for which this is the execution context of the // IntersectionObservers for which this is the execution context of the
// callback, and with unsent notifications. // callback, and with unsent notifications.
HeapHashSet<Member<IntersectionObserver>> pending_intersection_observers_; HeapHashSet<Member<IntersectionObserver>> pending_intersection_observers_;
// This is 'true' if any tracked element is the target of an observer for // This is 'true' if any tracked node is the target of an observer for
// which observer->trackVisibility() is true. // which observer->trackVisibility() is true.
bool needs_occlusion_tracking_; bool needs_occlusion_tracking_;
}; };
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// https://wicg.github.io/IntersectionObserver/#intersection-observer-init // https://wicg.github.io/IntersectionObserver/#intersection-observer-init
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;
[RuntimeEnabled=IntersectionObserverV2] DOMHighResTimeStamp delay = 0; [RuntimeEnabled=IntersectionObserverV2] DOMHighResTimeStamp delay = 0;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h" #include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h"
#include "third_party/blink/renderer/core/intersection_observer/intersection_observer_delegate.h" #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_delegate.h"
...@@ -132,7 +133,7 @@ TEST_F(IntersectionObserverTest, NotificationSentWhenRootRemoved) { ...@@ -132,7 +133,7 @@ TEST_F(IntersectionObserverTest, NotificationSentWhenRootRemoved) {
Element* root = GetDocument().getElementById("root"); Element* root = GetDocument().getElementById("root");
ASSERT_TRUE(root); ASSERT_TRUE(root);
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create(); IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
observer_init->setRoot(root); observer_init->setRoot(ElementOrDocument::FromElement(root));
DummyExceptionStateForTesting exception_state; DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate = TestIntersectionObserverDelegate* observer_delegate =
MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument()); MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
...@@ -159,27 +160,32 @@ TEST_F(IntersectionObserverTest, NotificationSentWhenRootRemoved) { ...@@ -159,27 +160,32 @@ TEST_F(IntersectionObserverTest, NotificationSentWhenRootRemoved) {
EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting()); EXPECT_FALSE(observer_delegate->LastEntry()->isIntersecting());
} }
TEST_F(IntersectionObserverTest, ScrollingElementRootClips) { TEST_F(IntersectionObserverTest, DocumentRootClips) {
ScopedIntersectionObserverDocumentScrollingElementRootForTest scope(true); ScopedIntersectionObserverDocumentScrollingElementRootForTest scope(true);
WebView().MainFrameWidget()->Resize(WebSize(800, 600)); WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/", "text/html"); SimRequest main_resource("https://example.com/", "text/html");
SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/"); LoadURL("https://example.com/");
main_resource.Complete(R"HTML( main_resource.Complete(R"HTML(
<iframe src="iframe.html" style="width:200px; height:100px"></iframe>
)HTML");
iframe_resource.Complete(R"HTML(
<div id='target'>Hello, world!</div> <div id='target'>Hello, world!</div>
<div id='spacer' style='height:2000px'></div> <div id='spacer' style='height:2000px'></div>
)HTML"); )HTML");
Element* root = GetDocument().scrollingElement(); Document* iframe_document = To<WebLocalFrameImpl>(MainFrame().FirstChild())
ASSERT_TRUE(root); ->GetFrame()
->GetDocument();
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create(); IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
observer_init->setRoot(root); observer_init->setRoot(ElementOrDocument::FromDocument(iframe_document));
DummyExceptionStateForTesting exception_state; DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate = TestIntersectionObserverDelegate* observer_delegate =
MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument()); MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
IntersectionObserver* observer = IntersectionObserver::Create( IntersectionObserver* observer = IntersectionObserver::Create(
observer_init, *observer_delegate, exception_state); observer_init, *observer_delegate, exception_state);
ASSERT_FALSE(exception_state.HadException()); ASSERT_FALSE(exception_state.HadException());
Element* target = GetDocument().getElementById("target"); Element* target = iframe_document->getElementById("target");
ASSERT_TRUE(target); ASSERT_TRUE(target);
observer->observe(target, exception_state); observer->observe(target, exception_state);
...@@ -190,8 +196,8 @@ TEST_F(IntersectionObserverTest, ScrollingElementRootClips) { ...@@ -190,8 +196,8 @@ TEST_F(IntersectionObserverTest, ScrollingElementRootClips) {
EXPECT_EQ(observer_delegate->EntryCount(), 1); EXPECT_EQ(observer_delegate->EntryCount(), 1);
EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting());
GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 1000), iframe_document->View()->LayoutViewport()->SetScrollOffset(
kProgrammaticScroll); ScrollOffset(0, 1000), kProgrammaticScroll);
Compositor().BeginFrame(); Compositor().BeginFrame();
test::RunPendingTasks(); test::RunPendingTasks();
EXPECT_EQ(observer_delegate->CallCount(), 2); EXPECT_EQ(observer_delegate->CallCount(), 2);
...@@ -530,7 +536,7 @@ TEST_F(IntersectionObserverTest, TrackedRootBookkeeping) { ...@@ -530,7 +536,7 @@ TEST_F(IntersectionObserverTest, TrackedRootBookkeeping) {
Persistent<Element> target = GetDocument().getElementById("target1"); Persistent<Element> target = GetDocument().getElementById("target1");
Persistent<IntersectionObserverInit> observer_init = Persistent<IntersectionObserverInit> observer_init =
IntersectionObserverInit::Create(); IntersectionObserverInit::Create();
observer_init->setRoot(root); observer_init->setRoot(ElementOrDocument::FromElement(root));
Persistent<TestIntersectionObserverDelegate> observer_delegate = Persistent<TestIntersectionObserverDelegate> observer_delegate =
MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument()); MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
Persistent<IntersectionObserver> observer = Persistent<IntersectionObserver> observer =
...@@ -679,7 +685,7 @@ TEST_F(IntersectionObserverTest, CachedRectsTest) { ...@@ -679,7 +685,7 @@ TEST_F(IntersectionObserverTest, CachedRectsTest) {
Element* target2 = GetDocument().getElementById("target2"); Element* target2 = GetDocument().getElementById("target2");
IntersectionObserverInit* observer_init = IntersectionObserverInit::Create(); IntersectionObserverInit* observer_init = IntersectionObserverInit::Create();
observer_init->setRoot(root); observer_init->setRoot(ElementOrDocument::FromElement(root));
DummyExceptionStateForTesting exception_state; DummyExceptionStateForTesting exception_state;
TestIntersectionObserverDelegate* observer_delegate = TestIntersectionObserverDelegate* observer_delegate =
MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument()); MakeGarbageCollected<TestIntersectionObserverDelegate>(GetDocument());
......
...@@ -28,18 +28,16 @@ iframe.onload = function() { ...@@ -28,18 +28,16 @@ iframe.onload = function() {
runTestCycle(function() { runTestCycle(function() {
assert_true(!!iframe, "iframe exists"); assert_true(!!iframe, "iframe exists");
root = iframe.contentDocument.scrollingElement;
assert_true(!!root, "Root element exists.");
target = iframe.contentDocument.getElementById("target"); target = iframe.contentDocument.getElementById("target");
assert_true(!!target, "Target element exists."); assert_true(!!target, "Target element exists.");
var observer = new IntersectionObserver(function(changes) { var observer = new IntersectionObserver(function(changes) {
entries = entries.concat(changes) entries = entries.concat(changes)
}, { root: root }); }, { root: iframe.contentDocument });
observer.observe(target); observer.observe(target);
entries = entries.concat(observer.takeRecords()); entries = entries.concat(observer.takeRecords());
assert_equals(entries.length, 0, "No initial notifications."); assert_equals(entries.length, 0, "No initial notifications.");
runTestCycle(step0, "First rAF."); runTestCycle(step0, "First rAF.");
}, "Observer with explicit root which is the document's scrolling element."); }, "Observer with explicit root which is the document.");
}; };
function step0() { function step0() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment