| 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 |