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 |