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 |