Chromium Code Reviews| 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), |
| 207 m_initialState(InitialState::kHidden) { | 220 m_initialState(InitialState::kHidden), |
| 221 m_intersectWithRemoteAncestors(intersectWithRemoteAncestors) { | |
| 208 switch (rootMargin.size()) { | 222 switch (rootMargin.size()) { |
| 209 case 0: | 223 case 0: |
| 210 break; | 224 break; |
| 211 case 1: | 225 case 1: |
| 212 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = | 226 m_topMargin = m_rightMargin = m_bottomMargin = m_leftMargin = |
| 213 rootMargin[0]; | 227 rootMargin[0]; |
| 214 break; | 228 break; |
| 215 case 2: | 229 case 2: |
| 216 m_topMargin = m_bottomMargin = rootMargin[0]; | 230 m_topMargin = m_bottomMargin = rootMargin[0]; |
| 217 m_rightMargin = m_leftMargin = rootMargin[1]; | 231 m_rightMargin = m_leftMargin = rootMargin[1]; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 243 m_root = nullptr; | 257 m_root = nullptr; |
| 244 } | 258 } |
| 245 | 259 |
| 246 LayoutObject* IntersectionObserver::rootLayoutObject() const { | 260 LayoutObject* IntersectionObserver::rootLayoutObject() const { |
| 247 Node* node = rootNode(); | 261 Node* node = rootNode(); |
| 248 if (node->isDocumentNode()) | 262 if (node->isDocumentNode()) |
| 249 return LayoutAPIShim::layoutObjectFrom(toDocument(node)->layoutViewItem()); | 263 return LayoutAPIShim::layoutObjectFrom(toDocument(node)->layoutViewItem()); |
| 250 return toElement(node)->layoutObject(); | 264 return toElement(node)->layoutObject(); |
| 251 } | 265 } |
| 252 | 266 |
| 267 LayoutObject* IntersectionObserver::rootLayoutObjectForIntersection() const { | |
| 268 if (m_intersectWithRemoteAncestors) | |
| 269 return nullptr; | |
| 270 return rootLayoutObject(); | |
| 271 } | |
| 272 | |
| 253 void IntersectionObserver::observe(Element* target, | 273 void IntersectionObserver::observe(Element* target, |
| 254 ExceptionState& exceptionState) { | 274 ExceptionState& exceptionState) { |
| 255 if (!m_root) { | 275 if (!m_root) { |
| 256 exceptionState.throwDOMException( | 276 exceptionState.throwDOMException( |
| 257 InvalidStateError, | 277 InvalidStateError, |
| 258 "observe() called on an IntersectionObserver with an invalid root."); | 278 "observe() called on an IntersectionObserver with an invalid root."); |
| 259 return; | 279 return; |
| 260 } | 280 } |
| 261 | 281 |
| 262 if (!target || m_root.get() == target) | 282 if (!target || m_root.get() == target) |
| 263 return; | 283 return; |
| 264 | 284 |
| 265 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 285 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
| 266 return; | 286 return; |
| 267 bool shouldReportRootBounds = false; | 287 bool shouldReportRootBounds = false; |
| 268 bool isDOMDescendant = false; | 288 bool isDOMDescendant = false; |
| 269 LocalFrame* targetFrame = target->document().frame(); | 289 LocalFrame* targetFrame = target->document().frame(); |
| 270 LocalFrame* rootFrame = m_root->document().frame(); | 290 LocalFrame* rootFrame = m_root->document().frame(); |
| 271 | 291 |
| 272 if (target->document() == rootNode()->document()) { | 292 if (target->document() == rootNode()->document()) { |
| 273 shouldReportRootBounds = true; | 293 if (!m_intersectWithRemoteAncestors) |
|
ojan
2016/11/23 22:55:54
Isn't this always true if target and root are in t
kenrb
2016/11/23 23:23:25
This is the special case problem I am thinking abo
| |
| 294 shouldReportRootBounds = true; | |
| 274 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); | 295 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); |
| 275 } else if (targetFrame && rootFrame) { | 296 } else if (targetFrame && rootFrame) { |
| 276 shouldReportRootBounds = | 297 shouldReportRootBounds = |
| 277 targetFrame->securityContext()->getSecurityOrigin()->canAccess( | 298 targetFrame->securityContext()->getSecurityOrigin()->canAccess( |
| 278 rootFrame->securityContext()->getSecurityOrigin()); | 299 rootFrame->securityContext()->getSecurityOrigin()); |
| 279 isDOMDescendant = (targetFrame->tree().top() == rootFrame); | 300 isDOMDescendant = (targetFrame->tree().top() == rootFrame); |
| 280 } | 301 } |
| 281 | 302 |
| 282 IntersectionObservation* observation = | 303 IntersectionObservation* observation = |
| 283 new IntersectionObservation(*this, *target, shouldReportRootBounds); | 304 new IntersectionObservation(*this, *target, shouldReportRootBounds); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 | 468 |
| 448 DEFINE_TRACE(IntersectionObserver) { | 469 DEFINE_TRACE(IntersectionObserver) { |
| 449 visitor->template registerWeakMembers< | 470 visitor->template registerWeakMembers< |
| 450 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); | 471 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); |
| 451 visitor->trace(m_callback); | 472 visitor->trace(m_callback); |
| 452 visitor->trace(m_observations); | 473 visitor->trace(m_observations); |
| 453 visitor->trace(m_entries); | 474 visitor->trace(m_entries); |
| 454 } | 475 } |
| 455 | 476 |
| 456 } // namespace blink | 477 } // namespace blink |
| OLD | NEW |