| 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" |
| 11 #include "core/dom/ExceptionCode.h" | 11 #include "core/dom/ExceptionCode.h" |
| 12 #include "core/dom/ExecutionContext.h" | 12 #include "core/dom/ExecutionContext.h" |
| 13 #include "core/dom/IntersectionObserverCallback.h" | 13 #include "core/dom/IntersectionObserverCallback.h" |
| 14 #include "core/dom/IntersectionObserverController.h" | 14 #include "core/dom/IntersectionObserverController.h" |
| 15 #include "core/dom/IntersectionObserverEntry.h" | 15 #include "core/dom/IntersectionObserverEntry.h" |
| 16 #include "core/dom/IntersectionObserverInit.h" | 16 #include "core/dom/IntersectionObserverInit.h" |
| 17 #include "core/dom/NodeIntersectionObserverData.h" | 17 #include "core/dom/NodeIntersectionObserverData.h" |
| 18 #include "core/frame/FrameView.h" | 18 #include "core/frame/FrameView.h" |
| 19 #include "core/frame/LocalDOMWindow.h" | 19 #include "core/frame/LocalDOMWindow.h" |
| 20 #include "core/frame/LocalFrame.h" | 20 #include "core/frame/LocalFrame.h" |
| 21 #include "core/html/HTMLFrameOwnerElement.h" | 21 #include "core/html/HTMLFrameOwnerElement.h" |
| 22 #include "core/inspector/ConsoleMessage.h" | 22 #include "core/inspector/ConsoleMessage.h" |
| 23 #include "core/layout/api/LayoutAPIShim.h" | |
| 24 #include "core/layout/api/LayoutViewItem.h" | |
| 25 #include "core/timing/DOMWindowPerformance.h" | 23 #include "core/timing/DOMWindowPerformance.h" |
| 26 #include "core/timing/Performance.h" | 24 #include "core/timing/Performance.h" |
| 27 #include "platform/Timer.h" | 25 #include "platform/Timer.h" |
| 28 #include <algorithm> | 26 #include <algorithm> |
| 29 | 27 |
| 30 namespace blink { | 28 namespace blink { |
| 31 | 29 |
| 32 namespace { | 30 namespace { |
| 33 | 31 |
| 34 // Internal implementation of IntersectionObserverCallback when using | 32 // Internal implementation of IntersectionObserverCallback when using |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 234 } |
| 237 | 235 |
| 238 void IntersectionObserver::clearWeakMembers(Visitor* visitor) { | 236 void IntersectionObserver::clearWeakMembers(Visitor* visitor) { |
| 239 if (ThreadHeap::isHeapObjectAlive(m_root)) | 237 if (ThreadHeap::isHeapObjectAlive(m_root)) |
| 240 return; | 238 return; |
| 241 IgnorableExceptionState exceptionState; | 239 IgnorableExceptionState exceptionState; |
| 242 disconnect(exceptionState); | 240 disconnect(exceptionState); |
| 243 m_root = nullptr; | 241 m_root = nullptr; |
| 244 } | 242 } |
| 245 | 243 |
| 246 LayoutObject* IntersectionObserver::rootLayoutObject() const { | |
| 247 Node* node = rootNode(); | |
| 248 if (node->isDocumentNode()) | |
| 249 return LayoutAPIShim::layoutObjectFrom(toDocument(node)->layoutViewItem()); | |
| 250 return toElement(node)->layoutObject(); | |
| 251 } | |
| 252 | |
| 253 void IntersectionObserver::observe(Element* target, | 244 void IntersectionObserver::observe(Element* target, |
| 254 ExceptionState& exceptionState) { | 245 ExceptionState& exceptionState) { |
| 255 if (!m_root) { | 246 if (!m_root) { |
| 256 exceptionState.throwDOMException( | 247 exceptionState.throwDOMException( |
| 257 InvalidStateError, | 248 InvalidStateError, |
| 258 "observe() called on an IntersectionObserver with an invalid root."); | 249 "observe() called on an IntersectionObserver with an invalid root."); |
| 259 return; | 250 return; |
| 260 } | 251 } |
| 261 | 252 |
| 262 if (!target || m_root.get() == target) | 253 if (!target || m_root.get() == target) |
| 263 return; | 254 return; |
| 264 | 255 |
| 265 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 256 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
| 266 return; | 257 return; |
| 267 bool shouldReportRootBounds = false; | 258 bool shouldReportRootBounds = false; |
| 268 bool isDOMDescendant = false; | 259 bool isDOMDescendant = false; |
| 269 LocalFrame* targetFrame = target->document().frame(); | 260 LocalFrame* targetFrame = target->document().frame(); |
| 270 LocalFrame* rootFrame = m_root->document().frame(); | 261 LocalFrame* rootFrame = m_root->document().frame(); |
| 271 | 262 |
| 272 if (target->document() == rootNode()->document()) { | 263 if (target->document() == rootNode()->document()) { |
| 273 shouldReportRootBounds = true; | 264 shouldReportRootBounds = true; |
| 274 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); | 265 isDOMDescendant = rootNode()->isShadowIncludingInclusiveAncestorOf(target); |
| 275 } else if (targetFrame && rootFrame) { | 266 } else if (targetFrame && rootFrame) { |
| 276 shouldReportRootBounds = | 267 shouldReportRootBounds = |
| 277 targetFrame->securityContext()->getSecurityOrigin()->canAccess( | 268 targetFrame->securityContext()->getSecurityOrigin()->canAccess( |
| 278 rootFrame->securityContext()->getSecurityOrigin()); | 269 rootFrame->securityContext()->getSecurityOrigin()); |
| 279 isDOMDescendant = (targetFrame->tree().top() == rootFrame); | 270 isDOMDescendant = (targetFrame->tree().top() == rootFrame); |
| 280 } | 271 } |
| 281 | 272 |
| 282 IntersectionObservation* observation = | 273 IntersectionObservation* observation = new IntersectionObservation( |
| 283 new IntersectionObservation(*this, *target, shouldReportRootBounds); | 274 *this, *target, |
| 275 shouldReportRootBounds |
| 276 ? IntersectionGeometry::ReportRootBounds::kShouldReportRootBounds |
| 277 : IntersectionGeometry::ReportRootBounds::kShouldNotReportRootBounds); |
| 284 target->ensureIntersectionObserverData().addObservation(*observation); | 278 target->ensureIntersectionObserverData().addObservation(*observation); |
| 285 m_observations.add(observation); | 279 m_observations.add(observation); |
| 286 | 280 |
| 287 if (!isDOMDescendant) { | 281 if (!isDOMDescendant) { |
| 288 m_root->document().addConsoleMessage( | 282 m_root->document().addConsoleMessage( |
| 289 ConsoleMessage::create(JSMessageSource, WarningMessageLevel, | 283 ConsoleMessage::create(JSMessageSource, WarningMessageLevel, |
| 290 "IntersectionObserver.observe(target): target " | 284 "IntersectionObserver.observe(target): target " |
| 291 "element is not a descendant of root.")); | 285 "element is not a descendant of root.")); |
| 292 return; | 286 return; |
| 293 } | 287 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 } | 393 } |
| 400 | 394 |
| 401 void IntersectionObserver::enqueueIntersectionObserverEntry( | 395 void IntersectionObserver::enqueueIntersectionObserverEntry( |
| 402 IntersectionObserverEntry& entry) { | 396 IntersectionObserverEntry& entry) { |
| 403 m_entries.append(&entry); | 397 m_entries.append(&entry); |
| 404 toDocument(m_callback->getExecutionContext()) | 398 toDocument(m_callback->getExecutionContext()) |
| 405 ->ensureIntersectionObserverController() | 399 ->ensureIntersectionObserverController() |
| 406 .scheduleIntersectionObserverForDelivery(*this); | 400 .scheduleIntersectionObserverForDelivery(*this); |
| 407 } | 401 } |
| 408 | 402 |
| 409 static LayoutUnit computeMargin(const Length& length, | |
| 410 LayoutUnit referenceLength) { | |
| 411 if (length.type() == Percent) | |
| 412 return LayoutUnit( | |
| 413 static_cast<int>(referenceLength.toFloat() * length.percent() / 100.0)); | |
| 414 DCHECK_EQ(length.type(), Fixed); | |
| 415 return LayoutUnit(length.intValue()); | |
| 416 } | |
| 417 | |
| 418 void IntersectionObserver::applyRootMargin(LayoutRect& rect) const { | |
| 419 // TODO(szager): Make sure the spec is clear that left/right margins are | |
| 420 // resolved against width and not height. | |
| 421 LayoutUnit topMargin = computeMargin(m_topMargin, rect.height()); | |
| 422 LayoutUnit rightMargin = computeMargin(m_rightMargin, rect.width()); | |
| 423 LayoutUnit bottomMargin = computeMargin(m_bottomMargin, rect.height()); | |
| 424 LayoutUnit leftMargin = computeMargin(m_leftMargin, rect.width()); | |
| 425 | |
| 426 rect.setX(rect.x() - leftMargin); | |
| 427 rect.setWidth(rect.width() + leftMargin + rightMargin); | |
| 428 rect.setY(rect.y() - topMargin); | |
| 429 rect.setHeight(rect.height() + topMargin + bottomMargin); | |
| 430 } | |
| 431 | |
| 432 unsigned IntersectionObserver::firstThresholdGreaterThan(float ratio) const { | 403 unsigned IntersectionObserver::firstThresholdGreaterThan(float ratio) const { |
| 433 unsigned result = 0; | 404 unsigned result = 0; |
| 434 while (result < m_thresholds.size() && m_thresholds[result] <= ratio) | 405 while (result < m_thresholds.size() && m_thresholds[result] <= ratio) |
| 435 ++result; | 406 ++result; |
| 436 return result; | 407 return result; |
| 437 } | 408 } |
| 438 | 409 |
| 439 void IntersectionObserver::deliver() { | 410 void IntersectionObserver::deliver() { |
| 440 if (m_entries.isEmpty()) | 411 if (m_entries.isEmpty()) |
| 441 return; | 412 return; |
| 442 | 413 |
| 443 HeapVector<Member<IntersectionObserverEntry>> entries; | 414 HeapVector<Member<IntersectionObserverEntry>> entries; |
| 444 entries.swap(m_entries); | 415 entries.swap(m_entries); |
| 445 m_callback->handleEvent(entries, *this); | 416 m_callback->handleEvent(entries, *this); |
| 446 } | 417 } |
| 447 | 418 |
| 448 DEFINE_TRACE(IntersectionObserver) { | 419 DEFINE_TRACE(IntersectionObserver) { |
| 449 visitor->template registerWeakMembers< | 420 visitor->template registerWeakMembers< |
| 450 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); | 421 IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); |
| 451 visitor->trace(m_callback); | 422 visitor->trace(m_callback); |
| 452 visitor->trace(m_observations); | 423 visitor->trace(m_observations); |
| 453 visitor->trace(m_entries); | 424 visitor->trace(m_entries); |
| 454 } | 425 } |
| 455 | 426 |
| 456 } // namespace blink | 427 } // namespace blink |
| OLD | NEW |