| Index: third_party/WebKit/LayoutTests/intersection-observer/README
|
| diff --git a/third_party/WebKit/LayoutTests/intersection-observer/README b/third_party/WebKit/LayoutTests/intersection-observer/README
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bc78b418df739bfcb6131da4f96037084554eb17
|
| --- /dev/null
|
| +++ b/third_party/WebKit/LayoutTests/intersection-observer/README
|
| @@ -0,0 +1,78 @@
|
| +All of the IntersectionObserver tests feature the following idiom:
|
| +
|
| +<script>
|
| +var observer = new IntersectionObserver(...)
|
| +function test_function() {
|
| + var entries = observer.takeRecords();
|
| + // Verify entries
|
| +}
|
| +onload = function() {
|
| + observer.observe(target);
|
| + requestAnimationFrame(() => { requestAnimationFrame(test_function) });
|
| +}
|
| +
|
| +Subsequent steps in the test use a single RAF to give the observer a chance to
|
| +generate notifications, but the double RAF is required in the onload handler.
|
| +Here's the chain of events:
|
| +
|
| +- onload
|
| + - observer.observe()
|
| + - First RAF handler is registered
|
| +- BeginFrame
|
| + - RAF handlers run
|
| + - Second RAF handler is registered
|
| + - UpdateAllLifecyclePhases
|
| + - IntersectionObserver generates notifications
|
| +- BeginFrame
|
| + - RAF handlers run
|
| + - Second RAF handler verifies observer notifications.
|
| +
|
| +#-------------------------------------------------------------------------------
|
| +
|
| +All of the IntersectionObserver tests are currently listed in LeakExpecations.
|
| +
|
| +To avoid leaking DOM objects, the tests must ensure that all posted tasks have
|
| +run before exiting. IntersectionObserverController requests an idle callback
|
| +through the document's ScriptedIdleTaskController with a timeout of 100ms. That
|
| +callback must be allowed to run before the test finishes to avoid a leak.
|
| +
|
| +ScriptedIdleTaskController posts two tasks to the WebScheduler: one to run at
|
| +the next idle time, and another to run when the timeout expires.
|
| +crbug.com/595155 explains that when one of those tasks runs, it does not release
|
| +its reference to the ScriptedIdleTaskController, which is needlessly kept alive
|
| +until the both tasks have fired. If a test exits before both tasks have fired,
|
| +it will have a DOM leak.
|
| +
|
| +crbug.com/595152 explains that when running without the threaded compositor --
|
| +as the layout tests do -- idle tasks are never serviced. They will still run
|
| +when their timeout expires, but the idle task posted by
|
| +ScriptedIdleTaskController will never run.
|
| +
|
| +Fixing the first bug means that requestIdleCallback will not leak as long as it
|
| +actually runs before exit. The second bug means that when running without the
|
| +threaded compositor, requestIdleCallback will only ever run when its timeout
|
| +expires.
|
| +
|
| +The upshot of all of this is that the only way to ensure that
|
| +IntersectionObserver tests don't leak is to ensure that their idle tasks all run
|
| +before the tests exit, and those idle tasks will only run when their 100ms
|
| +timeout expires.
|
| +
|
| +Note that all of this still holds when observer.takeRecords() is called before
|
| +the idle task runs. In that case, the idle task is not cancelled (because the
|
| +idle task needs to service all observers tracked by a given
|
| +IntersectionObserverController); when the idle task runs, it's simply a no-op.
|
| +There is no way in javascript to detect that such a no-op has occurred, but
|
| +using requestIdleCallback with a timeout of 100 should be guaranteed to run
|
| +after the IntersectionObserverController's idle task has run, as long as
|
| +ScriptedIdleTaskController honors first-in-first-out semantics.
|
| +
|
| +At the time of writing, there is a patch out to add testRunner.runIdleTasks():
|
| +
|
| +https://codereview.chromium.org/1806133002/
|
| +
|
| +With that patch, the tests can be removed from LeakExpectations as long as they
|
| +end with:
|
| +
|
| +if (window.testRunner)
|
| + testRunner.runIdleTasks(finishJSTest);
|
|
|