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/ExceptionCode.h" | 10 #include "core/dom/ExceptionCode.h" |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 #endif | 165 #endif |
166 | 166 |
167 LayoutObject* IntersectionObserver::rootLayoutObject() const | 167 LayoutObject* IntersectionObserver::rootLayoutObject() const |
168 { | 168 { |
169 Node* node = rootNode(); | 169 Node* node = rootNode(); |
170 if (node->isDocumentNode()) | 170 if (node->isDocumentNode()) |
171 return toDocument(node)->layoutView(); | 171 return toDocument(node)->layoutView(); |
172 return toElement(node)->layoutObject(); | 172 return toElement(node)->layoutObject(); |
173 } | 173 } |
174 | 174 |
175 bool IntersectionObserver::isDescendantOfRoot(const Element* target) const | |
176 { | |
177 // Is m_root an ancestor, through the DOM and frame trees, of target? | |
178 Node* node = rootNode(); | |
179 if (!node || !target || target == node) | |
180 return false; | |
181 if (!target->inDocument() || !node->inDocument()) | |
182 return false; | |
183 | |
184 Document* rootDocument = &node->document(); | |
185 Document* targetDocument = &target->document(); | |
186 while (targetDocument != rootDocument) { | |
187 target = targetDocument->ownerElement(); | |
188 if (!target) | |
189 return false; | |
190 targetDocument = &target->document(); | |
191 } | |
192 if (node->isDocumentNode()) { | |
193 ASSERT(targetDocument == node); | |
194 return true; | |
195 } | |
196 return target->isDescendantOf(node); | |
197 } | |
198 | |
199 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) | 175 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) |
200 { | 176 { |
201 if (!m_root) { | 177 if (!m_root) { |
202 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); | 178 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); |
203 return; | 179 return; |
204 } | 180 } |
205 if (!target) { | 181 if (!target) { |
206 exceptionState.throwTypeError("Observation target must be an element."); | 182 exceptionState.throwTypeError("Observation target must be an element."); |
207 return; | 183 return; |
208 } | 184 } |
209 if (m_root.get() == target) { | 185 if (m_root.get() == target) { |
210 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); | 186 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); |
211 return; | 187 return; |
212 } | 188 } |
213 if (!isDescendantOfRoot(target)) { | |
214 exceptionState.throwDOMException(HierarchyRequestError, "Observed elemen
t must be a descendant of the observer's root element."); | |
215 return; | |
216 } | |
217 | 189 |
218 // TODO(szager): Add a pointer to the spec that describes this policy. | 190 // TODO(szager): Add a pointer to the spec that describes this policy. |
219 bool shouldReportRootBounds = target->document().frame()->securityContext()-
>securityOrigin()->canAccess(rootNode()->document().frame()->securityContext()->
securityOrigin()); | 191 bool shouldReportRootBounds = target->document().frame()->securityContext()-
>securityOrigin()->canAccess(rootNode()->document().frame()->securityContext()->
securityOrigin()); |
220 if (!shouldReportRootBounds && hasPercentMargin()) { | 192 if (!shouldReportRootBounds && hasPercentMargin()) { |
221 exceptionState.throwDOMException(HierarchyRequestError, "Cannot observe
a cross-origin target because the observer has a root margin value specified as
a percent."); | 193 exceptionState.throwDOMException(HierarchyRequestError, "Cannot observe
a cross-origin target because the observer has a root margin value specified as
a percent."); |
222 return; | 194 return; |
223 } | 195 } |
224 | 196 |
225 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 197 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
226 return; | 198 return; |
227 | 199 |
228 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); | 200 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); |
229 target->ensureIntersectionObserverData().addObservation(*observation); | 201 target->ensureIntersectionObserverData().addObservation(*observation); |
230 m_observations.add(observation); | 202 m_observations.add(observation); |
231 } | 203 } |
232 | 204 |
233 void IntersectionObserver::unobserve(Element* target, ExceptionState&) | 205 void IntersectionObserver::unobserve(Element* target, ExceptionState&) |
234 { | 206 { |
235 if (!target || !target->intersectionObserverData()) | 207 if (!target || !target->intersectionObserverData()) |
236 return; | 208 return; |
237 // TODO(szager): unobserve callback | 209 // TODO(szager): unobserve callback |
238 if (IntersectionObservation* observation = target->intersectionObserverData(
)->getObservationFor(*this)) | 210 if (IntersectionObservation* observation = target->intersectionObserverData(
)->getObservationFor(*this)) |
239 observation->disconnect(); | 211 observation->disconnect(); |
240 } | 212 } |
241 | 213 |
242 void IntersectionObserver::computeIntersectionObservations() | 214 void IntersectionObserver::computeIntersectionObservations() |
243 { | 215 { |
244 if (!m_root) | 216 if (!m_root || !m_root->inDocument()) |
245 return; | 217 return; |
246 Document* callbackDocument = toDocument(m_callback->executionContext()); | 218 Document* callbackDocument = toDocument(m_callback->executionContext()); |
247 if (!callbackDocument) | 219 if (!callbackDocument) |
248 return; | 220 return; |
249 LocalDOMWindow* callbackDOMWindow = callbackDocument->domWindow(); | 221 LocalDOMWindow* callbackDOMWindow = callbackDocument->domWindow(); |
250 if (!callbackDOMWindow) | 222 if (!callbackDOMWindow) |
251 return; | 223 return; |
252 DOMHighResTimeStamp timestamp = DOMWindowPerformance::performance(*callbackD
OMWindow)->now(); | 224 DOMHighResTimeStamp timestamp = DOMWindowPerformance::performance(*callbackD
OMWindow)->now(); |
253 for (auto& observation : m_observations) | 225 for (auto& observation : m_observations) |
254 observation->computeIntersectionObservations(timestamp); | 226 observation->computeIntersectionObservations(timestamp); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 { | 323 { |
352 | 324 |
353 if (m_entries.isEmpty()) | 325 if (m_entries.isEmpty()) |
354 return; | 326 return; |
355 | 327 |
356 HeapVector<Member<IntersectionObserverEntry>> entries; | 328 HeapVector<Member<IntersectionObserverEntry>> entries; |
357 entries.swap(m_entries); | 329 entries.swap(m_entries); |
358 m_callback->handleEvent(entries, *this); | 330 m_callback->handleEvent(entries, *this); |
359 } | 331 } |
360 | 332 |
361 void IntersectionObserver::setActive(bool active) | |
362 { | |
363 for (auto& observation : m_observations) | |
364 observation->setActive(m_root && active && isDescendantOfRoot(observatio
n->target())); | |
365 } | |
366 | |
367 bool IntersectionObserver::hasPercentMargin() const | 333 bool IntersectionObserver::hasPercentMargin() const |
368 { | 334 { |
369 return (m_topMargin.type() == Percent | 335 return (m_topMargin.type() == Percent |
370 || m_rightMargin.type() == Percent | 336 || m_rightMargin.type() == Percent |
371 || m_bottomMargin.type() == Percent | 337 || m_bottomMargin.type() == Percent |
372 || m_leftMargin.type() == Percent); | 338 || m_leftMargin.type() == Percent); |
373 } | 339 } |
374 | 340 |
375 DEFINE_TRACE(IntersectionObserver) | 341 DEFINE_TRACE(IntersectionObserver) |
376 { | 342 { |
377 #if ENABLE(OILPAN) | 343 #if ENABLE(OILPAN) |
378 visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObs
erver::clearWeakMembers>(this); | 344 visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObs
erver::clearWeakMembers>(this); |
379 #endif | 345 #endif |
380 visitor->trace(m_callback); | 346 visitor->trace(m_callback); |
381 visitor->trace(m_observations); | 347 visitor->trace(m_observations); |
382 visitor->trace(m_entries); | 348 visitor->trace(m_entries); |
383 } | 349 } |
384 | 350 |
385 } // namespace blink | 351 } // namespace blink |
OLD | NEW |