Index: third_party/WebKit/Source/core/dom/IntersectionObserver.cpp |
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp |
index bb69ebb03c1e0c746a8d602ef7b8391fd2812806..f1a91f4244aeb58430e49a396de9fefeae8025e5 100644 |
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp |
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp |
@@ -8,18 +8,18 @@ |
#include "core/css/parser/CSSParserTokenRange.h" |
#include "core/css/parser/CSSTokenizer.h" |
#include "core/dom/Element.h" |
+#include "core/dom/ElementIntersectionObserverData.h" |
#include "core/dom/ExceptionCode.h" |
#include "core/dom/ExecutionContext.h" |
#include "core/dom/IntersectionObserverCallback.h" |
#include "core/dom/IntersectionObserverController.h" |
#include "core/dom/IntersectionObserverEntry.h" |
#include "core/dom/IntersectionObserverInit.h" |
-#include "core/dom/NodeIntersectionObserverData.h" |
#include "core/frame/FrameView.h" |
#include "core/frame/LocalDOMWindow.h" |
#include "core/frame/LocalFrame.h" |
-#include "core/html/HTMLFrameOwnerElement.h" |
#include "core/inspector/ConsoleMessage.h" |
+#include "core/layout/LayoutView.h" |
#include "core/timing/DOMWindowPerformance.h" |
#include "core/timing/Performance.h" |
#include "platform/Timer.h" |
@@ -128,34 +128,13 @@ void parseThresholds(const DoubleOrDoubleSequence& thresholdParameter, |
std::sort(thresholds.begin(), thresholds.end()); |
} |
-// Returns the root Node of a given Document to use as the IntersectionObserver |
-// root when no root is given. |
-// TODO(szager): it doesn't support RemoteFrames, see https://crbug.com/615156 |
-Node* getRootNode(Document* document) { |
- Frame* mainFrame = document->frame()->tree().top(); |
- if (mainFrame && mainFrame->isLocalFrame()) |
- return toLocalFrame(mainFrame)->document(); |
- return nullptr; |
-} |
- |
} // anonymous namespace |
IntersectionObserver* IntersectionObserver::create( |
const IntersectionObserverInit& observerInit, |
IntersectionObserverCallback& callback, |
ExceptionState& exceptionState) { |
- Node* root = observerInit.root(); |
- if (!root) { |
- ExecutionContext* context = callback.getExecutionContext(); |
- DCHECK(context->isDocument()); |
- root = getRootNode(toDocument(context)); |
- } |
- if (!root) { |
- exceptionState.throwDOMException( |
- HierarchyRequestError, |
- "Unable to get root node in main frame to track."); |
- return nullptr; |
- } |
+ Element* root = observerInit.root(); |
Vector<Length> rootMargin; |
parseRootMargin(observerInit.rootMargin(), rootMargin, exceptionState); |
@@ -167,7 +146,7 @@ IntersectionObserver* IntersectionObserver::create( |
if (exceptionState.hadException()) |
return nullptr; |
- return new IntersectionObserver(callback, *root, rootMargin, thresholds); |
+ return new IntersectionObserver(callback, root, rootMargin, thresholds); |
} |
IntersectionObserver* IntersectionObserver::create( |
@@ -176,32 +155,25 @@ IntersectionObserver* IntersectionObserver::create( |
Document* document, |
std::unique_ptr<EventCallback> callback, |
ExceptionState& exceptionState) { |
- Node* root = getRootNode(document); |
- if (!root) { |
- exceptionState.throwDOMException( |
- HierarchyRequestError, |
- "Unable to get root node in main frame to track."); |
- return nullptr; |
- } |
- |
IntersectionObserverCallbackImpl* intersectionObserverCallback = |
new IntersectionObserverCallbackImpl(document, std::move(callback)); |
- return new IntersectionObserver(*intersectionObserverCallback, *root, |
+ return new IntersectionObserver(*intersectionObserverCallback, nullptr, |
rootMargin, thresholds); |
} |
IntersectionObserver::IntersectionObserver( |
IntersectionObserverCallback& callback, |
- Node& root, |
+ Element* root, |
const Vector<Length>& rootMargin, |
const Vector<float>& thresholds) |
: m_callback(&callback), |
- m_root(&root), |
+ m_root(root), |
m_thresholds(thresholds), |
m_topMargin(Fixed), |
m_rightMargin(Fixed), |
m_bottomMargin(Fixed), |
m_leftMargin(Fixed), |
+ m_rootIsImplicit(root ? 0 : 1), |
m_initialState(InitialState::kHidden) { |
switch (rootMargin.size()) { |
case 0: |
@@ -229,45 +201,78 @@ IntersectionObserver::IntersectionObserver( |
NOTREACHED(); |
break; |
} |
- root.document().ensureIntersectionObserverController().addTrackedObserver( |
+ if (root) |
+ root->ensureIntersectionObserverData().addObserver(*this); |
+ trackingDocument().ensureIntersectionObserverController().addTrackedObserver( |
*this); |
} |
void IntersectionObserver::clearWeakMembers(Visitor* visitor) { |
- if (ThreadHeap::isHeapObjectAlive(m_root)) |
+ if (ThreadHeap::isHeapObjectAlive(root())) |
return; |
IgnorableExceptionState exceptionState; |
disconnect(exceptionState); |
m_root = nullptr; |
} |
+bool IntersectionObserver::rootIsValid() const { |
+ return rootIsImplicit() || root(); |
+} |
+ |
+Document& IntersectionObserver::trackingDocument() const { |
+ Document* document = nullptr; |
+ if (rootIsImplicit()) { |
+ DCHECK(m_callback->getExecutionContext()); |
+ document = toDocument(m_callback->getExecutionContext()); |
+ } else { |
+ DCHECK(root()); |
+ document = &root()->document(); |
+ } |
+ DCHECK(document); |
+ DCHECK(document->frame()); |
+ return *document->frame()->localFrameRoot()->document(); |
+} |
+ |
+LayoutObject* IntersectionObserver::rootLayoutObject() const { |
+ if (rootIsImplicit()) |
+ return trackingDocument().layoutView(); |
+ return root() ? root()->layoutObject() : nullptr; |
+} |
+ |
void IntersectionObserver::observe(Element* target, |
ExceptionState& exceptionState) { |
- if (!m_root) { |
+ if (!rootIsValid()) { |
exceptionState.throwDOMException( |
InvalidStateError, |
"observe() called on an IntersectionObserver with an invalid root."); |
return; |
} |
- if (!target || m_root.get() == target) |
+ if (!target || root() == target) |
+ return; |
+ |
+ LocalFrame* targetFrame = target->document().frame(); |
+ if (!targetFrame) |
return; |
if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
return; |
- bool shouldReportRootBounds = false; |
- bool isDOMDescendant = false; |
- LocalFrame* targetFrame = target->document().frame(); |
- LocalFrame* rootFrame = m_root->document().frame(); |
- if (target->document() == rootNode()->document()) { |
+ bool isDOMDescendant = true; |
+ bool shouldReportRootBounds = false; |
+ if (rootIsImplicit()) { |
+ Frame* rootFrame = targetFrame->tree().top(); |
+ DCHECK(rootFrame); |
+ if (rootFrame == targetFrame) { |
+ shouldReportRootBounds = true; |
+ } else { |
+ shouldReportRootBounds = |
+ targetFrame->securityContext()->getSecurityOrigin()->canAccess( |
+ rootFrame->securityContext()->getSecurityOrigin()); |
+ } |
+ } else { |
shouldReportRootBounds = true; |
- isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); |
- } else if (targetFrame && rootFrame) { |
- shouldReportRootBounds = |
- targetFrame->securityContext()->getSecurityOrigin()->canAccess( |
- rootFrame->securityContext()->getSecurityOrigin()); |
- isDOMDescendant = (targetFrame->tree().top() == rootFrame); |
+ isDOMDescendant = root()->isShadowIncludingInclusiveAncestorOf(target); |
} |
IntersectionObservation* observation = |
@@ -276,11 +281,10 @@ void IntersectionObserver::observe(Element* target, |
m_observations.add(observation); |
if (!isDOMDescendant) { |
- m_root->document().addConsoleMessage( |
+ root()->document().addConsoleMessage( |
ConsoleMessage::create(JSMessageSource, WarningMessageLevel, |
"IntersectionObserver.observe(target): target " |
"element is not a descendant of root.")); |
- return; |
} |
if (m_initialState == InitialState::kAuto) { |
@@ -288,15 +292,13 @@ void IntersectionObserver::observe(Element* target, |
observation->setLastThresholdIndex(std::numeric_limits<unsigned>::max()); |
} |
- if (!rootFrame) |
- return; |
- if (FrameView* rootFrameView = rootFrame->view()) |
- rootFrameView->scheduleAnimation(); |
+ if (FrameView* frameView = targetFrame->view()) |
+ frameView->scheduleAnimation(); |
} |
void IntersectionObserver::unobserve(Element* target, |
ExceptionState& exceptionState) { |
- if (!m_root) { |
+ if (!rootIsValid()) { |
exceptionState.throwDOMException( |
InvalidStateError, |
"unobserve() called on an IntersectionObserver with an invalid root."); |
@@ -305,13 +307,15 @@ void IntersectionObserver::unobserve(Element* target, |
if (!target || !target->intersectionObserverData()) |
return; |
- // TODO(szager): unobserve callback |
+ |
if (IntersectionObservation* observation = |
target->intersectionObserverData()->getObservationFor(*this)) |
observation->disconnect(); |
} |
void IntersectionObserver::computeIntersectionObservations() { |
+ if (!rootIsValid()) |
+ return; |
Document* callbackDocument = toDocument(m_callback->getExecutionContext()); |
if (!callbackDocument) |
return; |
@@ -325,7 +329,7 @@ void IntersectionObserver::computeIntersectionObservations() { |
} |
void IntersectionObserver::disconnect(ExceptionState& exceptionState) { |
- if (!m_root) { |
+ if (!rootIsValid()) { |
exceptionState.throwDOMException( |
InvalidStateError, |
"disconnect() called on an IntersectionObserver with an invalid root."); |
@@ -351,24 +355,18 @@ HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords( |
ExceptionState& exceptionState) { |
HeapVector<Member<IntersectionObserverEntry>> entries; |
- if (!m_root) |
+ if (!rootIsValid()) { |
exceptionState.throwDOMException(InvalidStateError, |
"takeRecords() called on an " |
"IntersectionObserver with an invalid " |
"root."); |
- else |
+ } else { |
entries.swap(m_entries); |
+ } |
return entries; |
} |
-Element* IntersectionObserver::root() const { |
- Node* node = rootNode(); |
- if (node && !node->isDocumentNode()) |
- return toElement(node); |
- return nullptr; |
-} |
- |
static void appendLength(StringBuilder& stringBuilder, const Length& length) { |
stringBuilder.appendNumber(length.intValue()); |
if (length.type() == Percent) |