| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/dom/IntersectionObserver.h" | 5 #include "core/dom/IntersectionObserver.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
| 8 #include "core/css/parser/CSSParserTokenRange.h" | 8 #include "core/css/parser/CSSParserTokenRange.h" |
| 9 #include "core/css/parser/CSSTokenizer.h" | 9 #include "core/css/parser/CSSTokenizer.h" |
| 10 #include "core/dom/Element.h" | 10 #include "core/dom/Element.h" |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 "Threshold values must be numbers between 0 and 1"); | 125 "Threshold values must be numbers between 0 and 1"); |
| 126 break; | 126 break; |
| 127 } | 127 } |
| 128 } | 128 } |
| 129 | 129 |
| 130 std::sort(thresholds.begin(), thresholds.end()); | 130 std::sort(thresholds.begin(), thresholds.end()); |
| 131 } | 131 } |
| 132 | 132 |
| 133 // Returns the root Node of a given Document to use as the IntersectionObserver | 133 // Returns the root Node of a given Document to use as the IntersectionObserver |
| 134 // root when no root is given. | 134 // root when no root is given. |
| 135 // TODO(szager): it doesn't support RemoteFrames, see https://crbug.com/615156 | |
| 136 Node* getRootNode(Document* document) { | 135 Node* getRootNode(Document* document) { |
| 137 Frame* mainFrame = document->frame()->tree().top(); | 136 LocalFrame* rootFrame = document->frame()->localFrameRoot(); |
| 138 if (mainFrame && mainFrame->isLocalFrame()) | 137 if (rootFrame) |
| 139 return toLocalFrame(mainFrame)->document(); | 138 return rootFrame->document(); |
| 140 return nullptr; | 139 return nullptr; |
| 141 } | 140 } |
| 142 | 141 |
| 143 } // anonymous namespace | 142 } // anonymous namespace |
| 144 | 143 |
| 145 IntersectionObserver* IntersectionObserver::create( | 144 IntersectionObserver* IntersectionObserver::create( |
| 146 const IntersectionObserverInit& observerInit, | 145 const IntersectionObserverInit& observerInit, |
| 147 IntersectionObserverCallback& callback, | 146 IntersectionObserverCallback& callback, |
| 148 ExceptionState& exceptionState) { | 147 ExceptionState& exceptionState) { |
| 148 bool intersectWithRemoteAncestors = false; |
| 149 Node* root = observerInit.root(); | 149 Node* root = observerInit.root(); |
| 150 if (!root) { | 150 if (!root) { |
| 151 ExecutionContext* context = callback.getExecutionContext(); | 151 ExecutionContext* context = callback.getExecutionContext(); |
| 152 DCHECK(context->isDocument()); | 152 DCHECK(context->isDocument()); |
| 153 root = getRootNode(toDocument(context)); | 153 root = getRootNode(toDocument(context)); |
| 154 if (root && (toDocument(context)->frame()->tree().top()->isRemoteFrame() || |
| 155 root != |
| 156 toLocalFrame(toDocument(context)->frame()->tree().top()) |
| 157 ->document())) |
| 158 intersectWithRemoteAncestors = true; |
| 154 } | 159 } |
| 155 if (!root) { | 160 if (!root) { |
| 156 exceptionState.throwDOMException( | 161 exceptionState.throwDOMException( |
| 157 HierarchyRequestError, | 162 HierarchyRequestError, |
| 158 "Unable to get root node in main frame to track."); | 163 "Unable to get root node in main frame to track."); |
| 159 return nullptr; | 164 return nullptr; |
| 160 } | 165 } |
| 161 | 166 |
| 162 Vector<Length> rootMargin; | 167 Vector<Length> rootMargin; |
| 163 parseRootMargin(observerInit.rootMargin(), rootMargin, exceptionState); | 168 parseRootMargin(observerInit.rootMargin(), rootMargin, exceptionState); |
| 164 if (exceptionState.hadException()) | 169 if (exceptionState.hadException()) |
| 165 return nullptr; | 170 return nullptr; |
| 166 | 171 |
| 167 Vector<float> thresholds; | 172 Vector<float> thresholds; |
| 168 parseThresholds(observerInit.threshold(), thresholds, exceptionState); | 173 parseThresholds(observerInit.threshold(), thresholds, exceptionState); |
| 169 if (exceptionState.hadException()) | 174 if (exceptionState.hadException()) |
| 170 return nullptr; | 175 return nullptr; |
| 171 | 176 |
| 172 return new IntersectionObserver(callback, *root, rootMargin, thresholds); | 177 return new IntersectionObserver(callback, *root, rootMargin, thresholds, |
| 178 intersectWithRemoteAncestors); |
| 173 } | 179 } |
| 174 | 180 |
| 175 IntersectionObserver* IntersectionObserver::create( | 181 IntersectionObserver* IntersectionObserver::create( |
| 176 const Vector<Length>& rootMargin, | 182 const Vector<Length>& rootMargin, |
| 177 const Vector<float>& thresholds, | 183 const Vector<float>& thresholds, |
| 178 Document* document, | 184 Document* document, |
| 179 std::unique_ptr<EventCallback> callback, | 185 std::unique_ptr<EventCallback> callback, |
| 180 ExceptionState& exceptionState) { | 186 ExceptionState& exceptionState) { |
| 181 Node* root = getRootNode(document); | 187 Node* root = getRootNode(document); |
| 188 bool intersectWithRemoteAncestors = false; |
| 189 if (root && |
| 190 (document->frame()->tree().top()->isRemoteFrame() || |
| 191 root != toLocalFrame(document->frame()->tree().top())->document())) |
| 192 intersectWithRemoteAncestors = true; |
| 182 if (!root) { | 193 if (!root) { |
| 183 exceptionState.throwDOMException( | 194 exceptionState.throwDOMException( |
| 184 HierarchyRequestError, | 195 HierarchyRequestError, |
| 185 "Unable to get root node in main frame to track."); | 196 "Unable to get root node in main frame to track."); |
| 186 return nullptr; | 197 return nullptr; |
| 187 } | 198 } |
| 188 | 199 |
| 189 IntersectionObserverCallbackImpl* intersectionObserverCallback = | 200 IntersectionObserverCallbackImpl* intersectionObserverCallback = |
| 190 new IntersectionObserverCallbackImpl(document, std::move(callback)); | 201 new IntersectionObserverCallbackImpl(document, std::move(callback)); |
| 191 return new IntersectionObserver(*intersectionObserverCallback, *root, | 202 return new IntersectionObserver(*intersectionObserverCallback, *root, |
| 192 rootMargin, thresholds); | 203 rootMargin, thresholds, |
| 204 intersectWithRemoteAncestors); |
| 193 } | 205 } |
| 194 | 206 |
| 195 IntersectionObserver::IntersectionObserver( | 207 IntersectionObserver::IntersectionObserver( |
| 196 IntersectionObserverCallback& callback, | 208 IntersectionObserverCallback& callback, |
| 197 Node& root, | 209 Node& root, |
| 198 const Vector<Length>& rootMargin, | 210 const Vector<Length>& rootMargin, |
| 199 const Vector<float>& thresholds) | 211 const Vector<float>& thresholds, |
| 212 bool intersectWithRemoteAncestors) |
| 200 : m_callback(&callback), | 213 : m_callback(&callback), |
| 201 m_root(&root), | 214 m_root(&root), |
| 202 m_thresholds(thresholds), | 215 m_thresholds(thresholds), |
| 203 m_topMargin(Fixed), | 216 m_topMargin(Fixed), |
| 204 m_rightMargin(Fixed), | 217 m_rightMargin(Fixed), |
| 205 m_bottomMargin(Fixed), | 218 m_bottomMargin(Fixed), |
| 206 m_leftMargin(Fixed) { | 219 m_leftMargin(Fixed), |
| 220 m_intersectWithRemoteAncestors(intersectWithRemoteAncestors) { |
| 207 switch (rootMargin.size()) { | 221 switch (rootMargin.size()) { |
| 208 case 0: | 222 case 0: |
| 209 break; | 223 break; |
| 210 case 1: | 224 case 1: |
| 211 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = | 225 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = |
| 212 rootMargin[0]; | 226 rootMargin[0]; |
| 213 break; | 227 break; |
| 214 case 2: | 228 case 2: |
| 215 m_topMargin = m_bottomMargin = rootMargin[0]; | 229 m_topMargin = m_bottomMargin = rootMargin[0]; |
| 216 m_rightMargin = m_leftMargin = rootMargin[1]; | 230 m_rightMargin = m_leftMargin = rootMargin[1]; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 return; | 276 return; |
| 263 | 277 |
| 264 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 278 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
| 265 return; | 279 return; |
| 266 bool shouldReportRootBounds = false; | 280 bool shouldReportRootBounds = false; |
| 267 bool isDOMDescendant = false; | 281 bool isDOMDescendant = false; |
| 268 LocalFrame* targetFrame = target->document().frame(); | 282 LocalFrame* targetFrame = target->document().frame(); |
| 269 LocalFrame* rootFrame = m_root->document().frame(); | 283 LocalFrame* rootFrame = m_root->document().frame(); |
| 270 | 284 |
| 271 if (target->document() == rootNode()->document()) { | 285 if (target->document() == rootNode()->document()) { |
| 272 shouldReportRootBounds = true; | 286 if (!m_intersectWithRemoteAncestors) |
| 287 shouldReportRootBounds = true; |
| 273 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); | 288 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); |
| 274 } else if (targetFrame && rootFrame) { | 289 } else if (targetFrame && rootFrame) { |
| 275 shouldReportRootBounds = | 290 shouldReportRootBounds = |
| 276 targetFrame->securityContext()->getSecurityOrigin()->canAccess( | 291 targetFrame->securityContext()->getSecurityOrigin()->canAccess( |
| 277 rootFrame->securityContext()->getSecurityOrigin()); | 292 rootFrame->securityContext()->getSecurityOrigin()); |
| 278 isDOMDescendant = (targetFrame->tree().top() == rootFrame); | 293 isDOMDescendant = (targetFrame->tree().top() == rootFrame); |
| 279 } | 294 } |
| 280 | 295 |
| 281 IntersectionObservation* observation = | 296 IntersectionObservation* observation = |
| 282 new IntersectionObservation(*this, *target, shouldReportRootBounds); | 297 new IntersectionObservation(*this, *target, shouldReportRootBounds); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 | 442 |
| 428 void IntersectionObserver::deliver() { | 443 void IntersectionObserver::deliver() { |
| 429 if (m_entries.isEmpty()) | 444 if (m_entries.isEmpty()) |
| 430 return; | 445 return; |
| 431 | 446 |
| 432 HeapVector<Member<IntersectionObserverEntry>> entries; | 447 HeapVector<Member<IntersectionObserverEntry>> entries; |
| 433 entries.swap(m_entries); | 448 entries.swap(m_entries); |
| 434 m_callback->handleEvent(entries, *this); | 449 m_callback->handleEvent(entries, *this); |
| 435 } | 450 } |
| 436 | 451 |
| 452 void IntersectionObserver::intersectWithRemoteAncestorsIfNeeded( |
| 453 LayoutRect& rect) { |
| 454 if (m_intersectWithRemoteAncestors) { |
| 455 Document* root = toDocument(rootNode()); |
| 456 if (root->view()) { |
| 457 LayoutRect viewportIntersectionRect( |
| 458 root->view()->remoteViewportIntersection()); |
| 459 rect.intersect(viewportIntersectionRect); |
| 460 } |
| 461 } |
| 462 } |
| 463 |
| 437 DEFINE_TRACE(IntersectionObserver) { | 464 DEFINE_TRACE(IntersectionObserver) { |
| 438 visitor->template registerWeakMembers< | 465 visitor->template registerWeakMembers< |
| 439 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); | 466 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); |
| 440 visitor->trace(m_callback); | 467 visitor->trace(m_callback); |
| 441 visitor->trace(m_observations); | 468 visitor->trace(m_observations); |
| 442 visitor->trace(m_entries); | 469 visitor->trace(m_entries); |
| 443 } | 470 } |
| 444 | 471 |
| 445 } // namespace blink | 472 } // namespace blink |
| OLD | NEW |