[Webkit-unassigned] [Bug 196729] New: IntersectionObserver delivers incorrect records and fires at the wrong time

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Tue Apr 9 03:40:55 PDT 2019


https://bugs.webkit.org/show_bug.cgi?id=196729

            Bug ID: 196729
           Summary: IntersectionObserver delivers incorrect records and
                    fires at the wrong time
           Product: WebKit
           Version: WebKit Nightly Build
          Hardware: Unspecified
                OS: Unspecified
            Status: NEW
          Severity: Normal
          Priority: P2
         Component: DOM
          Assignee: webkit-unassigned at lists.webkit.org
          Reporter: esprehn at chromium.org

The implementation of scheduling done here https://bugs.webkit.org/show_bug.cgi?id=189007 does not follow the spec which requires that the observations be computed after the next layout. Instead they seem to be on a one shot timer that's not connected to the rendering system. This means they report about elements not in the document, and also that there's both ordering bugs compared to other browsers as well as race conditions where sometimes the wrong records are delivered.

ex.
// Does not notify in Chrome or Firefox, notifies with a zero sized rect in Safari.

o = new IntersectionObserver((records) => console.log(records))
d = document.createElement('div')
o.observe(d)


ex.
// Delivers intersection records once with the right width and height in Chrome and Firefox. Delivers zero sized rects in Safari and then the correct ones later.

o = new IntersectionObserver((records) => console.log(records))
d = document.createElement('div')
o.observe(d)
requestAnimationFrame(() => { document.body.append(d); d.textContent = 'Hello World' })


ex.
// Delivers a record with zero height and *never* delivers the correct rects.

document.body.style.fontSize = 32;
o = new IntersectionObserver((records) => {
  // prints [0], but should print a number greater than 32.
  console.log(records.map(r => r.boundingClientRect.height));
})
d = document.createElement('div')
o.observe(d)
setTimeout(() => {
  let x = document.createElement('div')
  x.textContent = 'Hello World'
  d.appendChild(x);
});
document.body.append(d);


The code also skips computing intersections if there's a pending style recalc or layout:
https://github.com/WebKit/webkit/blob/9029c43e695bf886fffb15eec951f0605e34509b/Source/WebCore/dom/Document.cpp#L7540
and then restarts the timer if no layout is required in Document::resolveStyle
https://github.com/WebKit/webkit/blob/9029c43e695bf886fffb15eec951f0605e34509b/Source/WebCore/dom/Document.cpp#L1918
but if layout was required nothing seems to restart the timer. I think this works today because updateLayoutAndStyleIfNeededRecursive will always run all the steps twice so the timer gets restarted on the second pass. If that loop wasn't there I don't think IntersectionObserver would work.

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20190409/be852adc/attachment.html>


More information about the webkit-unassigned mailing list