| 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 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 } | 179 } |
| 180 if (rootNode->isDocumentNode()) { | 180 if (rootNode->isDocumentNode()) { |
| 181 ASSERT(targetDocument == rootNode); | 181 ASSERT(targetDocument == rootNode); |
| 182 return true; | 182 return true; |
| 183 } | 183 } |
| 184 return target->isDescendantOf(rootNode); | 184 return target->isDescendantOf(rootNode); |
| 185 } | 185 } |
| 186 | 186 |
| 187 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) | 187 void IntersectionObserver::observe(Element* target, ExceptionState& exceptionSta
te) |
| 188 { | 188 { |
| 189 checkRootAndDetachIfNeeded(); |
| 189 if (!m_root) { | 190 if (!m_root) { |
| 190 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); | 191 exceptionState.throwDOMException(HierarchyRequestError, "Invalid observe
r: root element or containing document has been deleted."); |
| 191 return; | 192 return; |
| 192 } | 193 } |
| 193 if (!target) { | 194 if (!target) { |
| 194 exceptionState.throwTypeError("Observation target must be an element."); | 195 exceptionState.throwTypeError("Observation target must be an element."); |
| 195 return; | 196 return; |
| 196 } | 197 } |
| 197 if (m_root.get() == target) { | 198 if (m_root.get() == target) { |
| 198 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); | 199 exceptionState.throwDOMException(HierarchyRequestError, "Cannot use the
same element for root and target."); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 213 if (target->ensureIntersectionObserverData().getObservationFor(*this)) | 214 if (target->ensureIntersectionObserverData().getObservationFor(*this)) |
| 214 return; | 215 return; |
| 215 | 216 |
| 216 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); | 217 IntersectionObservation* observation = new IntersectionObservation(*this, *t
arget, shouldReportRootBounds); |
| 217 target->ensureIntersectionObserverData().addObservation(*observation); | 218 target->ensureIntersectionObserverData().addObservation(*observation); |
| 218 m_observations.add(observation); | 219 m_observations.add(observation); |
| 219 } | 220 } |
| 220 | 221 |
| 221 void IntersectionObserver::unobserve(Element* target, ExceptionState&) | 222 void IntersectionObserver::unobserve(Element* target, ExceptionState&) |
| 222 { | 223 { |
| 224 checkRootAndDetachIfNeeded(); |
| 223 if (!target || !target->intersectionObserverData()) | 225 if (!target || !target->intersectionObserverData()) |
| 224 return; | 226 return; |
| 225 // TODO(szager): unobserve callback | 227 // TODO(szager): unobserve callback |
| 226 if (IntersectionObservation* observation = target->intersectionObserverData(
)->getObservationFor(*this)) | 228 if (IntersectionObservation* observation = target->intersectionObserverData(
)->getObservationFor(*this)) |
| 227 observation->disconnect(); | 229 observation->disconnect(); |
| 228 } | 230 } |
| 229 | 231 |
| 230 void IntersectionObserver::computeIntersectionObservations(double timestamp) | 232 void IntersectionObserver::computeIntersectionObservations(double timestamp) |
| 231 { | 233 { |
| 234 checkRootAndDetachIfNeeded(); |
| 232 if (!m_root) | 235 if (!m_root) |
| 233 return; | 236 return; |
| 234 for (auto& observation : m_observations) | 237 for (auto& observation : m_observations) |
| 235 observation->computeIntersectionObservations(timestamp); | 238 observation->computeIntersectionObservations(timestamp); |
| 236 } | 239 } |
| 237 | 240 |
| 238 void IntersectionObserver::disconnect() | 241 void IntersectionObserver::disconnect() |
| 239 { | 242 { |
| 240 HeapVector<Member<IntersectionObservation>> observationsToDisconnect; | 243 HeapVector<Member<IntersectionObservation>> observationsToDisconnect; |
| 241 copyToVector(m_observations, observationsToDisconnect); | 244 copyToVector(m_observations, observationsToDisconnect); |
| 242 for (auto& observation : observationsToDisconnect) | 245 for (auto& observation : observationsToDisconnect) |
| 243 observation->disconnect(); | 246 observation->disconnect(); |
| 244 ASSERT(m_observations.isEmpty()); | 247 ASSERT(m_observations.isEmpty()); |
| 245 } | 248 } |
| 246 | 249 |
| 247 void IntersectionObserver::removeObservation(IntersectionObservation& observatio
n) | 250 void IntersectionObserver::removeObservation(IntersectionObservation& observatio
n) |
| 248 { | 251 { |
| 249 m_observations.remove(&observation); | 252 m_observations.remove(&observation); |
| 250 } | 253 } |
| 251 | 254 |
| 252 HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(
) | 255 HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(
) |
| 253 { | 256 { |
| 257 checkRootAndDetachIfNeeded(); |
| 254 HeapVector<Member<IntersectionObserverEntry>> entries; | 258 HeapVector<Member<IntersectionObserverEntry>> entries; |
| 255 entries.swap(m_entries); | 259 entries.swap(m_entries); |
| 256 return entries; | 260 return entries; |
| 257 } | 261 } |
| 258 | 262 |
| 259 void IntersectionObserver::enqueueIntersectionObserverEntry(IntersectionObserver
Entry& entry) | 263 void IntersectionObserver::enqueueIntersectionObserverEntry(IntersectionObserver
Entry& entry) |
| 260 { | 264 { |
| 261 m_entries.append(&entry); | 265 m_entries.append(&entry); |
| 262 toDocument(m_callback->executionContext())->ensureIntersectionObserverContro
ller().scheduleIntersectionObserverForDelivery(*this); | 266 toDocument(m_callback->executionContext())->ensureIntersectionObserverContro
ller().scheduleIntersectionObserverForDelivery(*this); |
| 263 } | 267 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 288 unsigned IntersectionObserver::firstThresholdGreaterThan(float ratio) const | 292 unsigned IntersectionObserver::firstThresholdGreaterThan(float ratio) const |
| 289 { | 293 { |
| 290 unsigned result = 0; | 294 unsigned result = 0; |
| 291 while (result < m_thresholds.size() && m_thresholds[result] < ratio) | 295 while (result < m_thresholds.size() && m_thresholds[result] < ratio) |
| 292 ++result; | 296 ++result; |
| 293 return result; | 297 return result; |
| 294 } | 298 } |
| 295 | 299 |
| 296 void IntersectionObserver::deliver() | 300 void IntersectionObserver::deliver() |
| 297 { | 301 { |
| 302 checkRootAndDetachIfNeeded(); |
| 303 |
| 298 if (m_entries.isEmpty()) | 304 if (m_entries.isEmpty()) |
| 299 return; | 305 return; |
| 300 | 306 |
| 301 HeapVector<Member<IntersectionObserverEntry>> entries; | 307 HeapVector<Member<IntersectionObserverEntry>> entries; |
| 302 entries.swap(m_entries); | 308 entries.swap(m_entries); |
| 303 m_callback->handleEvent(entries, *this); | 309 m_callback->handleEvent(entries, *this); |
| 304 } | 310 } |
| 305 | 311 |
| 306 void IntersectionObserver::setActive(bool active) | 312 void IntersectionObserver::setActive(bool active) |
| 307 { | 313 { |
| 314 checkRootAndDetachIfNeeded(); |
| 308 for (auto& observation : m_observations) | 315 for (auto& observation : m_observations) |
| 309 observation->setActive(m_root && active && isDescendantOfRoot(observatio
n->target())); | 316 observation->setActive(m_root && active && isDescendantOfRoot(observatio
n->target())); |
| 310 } | 317 } |
| 311 | 318 |
| 312 bool IntersectionObserver::hasPercentMargin() const | 319 bool IntersectionObserver::hasPercentMargin() const |
| 313 { | 320 { |
| 314 return (m_topMargin.type() == Percent | 321 return (m_topMargin.type() == Percent |
| 315 || m_rightMargin.type() == Percent | 322 || m_rightMargin.type() == Percent |
| 316 || m_bottomMargin.type() == Percent | 323 || m_bottomMargin.type() == Percent |
| 317 || m_leftMargin.type() == Percent); | 324 || m_leftMargin.type() == Percent); |
| 318 } | 325 } |
| 319 | 326 |
| 320 void IntersectionObserver::rootDisappearedCallback(Visitor* visitor, void* self) | 327 void IntersectionObserver::checkRootAndDetachIfNeeded() |
| 321 { | 328 { |
| 322 IntersectionObserver* observer = static_cast<IntersectionObserver*>(self); | 329 #if ENABLE(OILPAN) |
| 323 observer->disconnect(); | 330 // TODO(szager): Pre-oilpan, ElementIntersectionObserverData::dispose() will
take |
| 331 // care of this cleanup. When oilpan ships, there will be a potential leak
of the |
| 332 // callback's execution context when the root goes away. For a detailed exp
lanation: |
| 333 // |
| 334 // https://goo.gl/PC2Baj |
| 335 // |
| 336 // When that happens, this method should catch most potential leaks, but a c
omplete |
| 337 // solution will still be needed, along the lines described in the above lin
k. |
| 338 if (m_root) |
| 339 return; |
| 340 disconnect(); |
| 341 #endif |
| 324 } | 342 } |
| 325 | 343 |
| 326 DEFINE_TRACE(IntersectionObserver) | 344 DEFINE_TRACE(IntersectionObserver) |
| 327 { | 345 { |
| 328 #if ENABLE(OILPAN) | |
| 329 visitor->registerWeakMembers(this, m_root.get(), IntersectionObserver::rootD
isappearedCallback); | |
| 330 #endif | |
| 331 visitor->trace(m_callback); | 346 visitor->trace(m_callback); |
| 332 visitor->trace(m_root); | 347 visitor->trace(m_root); |
| 333 visitor->trace(m_observations); | 348 visitor->trace(m_observations); |
| 334 visitor->trace(m_entries); | 349 visitor->trace(m_entries); |
| 335 } | 350 } |
| 336 | 351 |
| 337 } // namespace blink | 352 } // namespace blink |
| OLD | NEW |