After <https://trac.webkit.org/r206247> (the fix for bug 162359), it is possible for the client to not get notified of a paint milestone until the next layer flush, which may or may not occur. This is because WebCore fires painting milestones on a timer, and by the time it does so, the flush for the paint that triggered it may have already happened.
<rdar://problem/29074344>
Perhaps the timer is not the reason. TiledCoreAnimationDrawingArea::flushLayers is called long before RenderLayerCompositor::didPaintBacking.
If some data in the commit will change, we should schedule a commit.
(In reply to comment #2) > Perhaps the timer is not the reason. > TiledCoreAnimationDrawingArea::flushLayers is called long before > RenderLayerCompositor::didPaintBacking. TiledCoreAnimationDrawingArea::flushLayers installs a commit handler, and that runs after didPaintBacking. So we need to fire the pending milestones from there.
Actually, I am seeing this with the root layer, which doesn’t even rely on RenderLayerCompositor::didPaintBacking, because RenderLayerBacking::paintIntoLayer calls FrameView::didPaintContents() directly which calls firePaintRelatedMilestonesIfNeeded() without a timer delay. I am trying to understand in what cases that is not followed by a flush, so that I cam make a reliable test case for the fix that moves firing the pending milestones into the commit handler. I am also trying to understand what’s the right thing to do for OS X 10.10, which doesn’t use the commit handler code path.
Created attachment 293734 [details] Have WebKit, not WebCore, defer sending the milestones until after the commit I wasn’t able to add an API test for this. I test with internal builds of macOS Mail, which were affected by the bug.
Comment on attachment 293734 [details] Have WebKit, not WebCore, defer sending the milestones until after the commit View in context: https://bugs.webkit.org/attachment.cgi?id=293734&action=review > Source/WebCore/ChangeLog:11 > + To give WebKit a chance to deliver the painting milestones to its client after the commit, > + we must tell it about them before or during the commit. To that end, we should not defer > + the call to firePaintRelatedMilestonesIfNeeded until after the commit. Was it deferred for a good reason, like coalescing? > Source/WebCore/rendering/RenderLayerCompositor.cpp:572 > + frameView.firePaintRelatedMilestonesIfNeeded(); Does one really "fire" a milestone, or just reach or pass it? > Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:428 > + if (TiledCoreAnimationDrawingArea* drawingArea = static_cast<TiledCoreAnimationDrawingArea*>(retainedPage->drawingArea())) { auto foo = downcast<TiledCoreAnimationDrawingArea>() ? When is drawingArea != this? Very confusing to fetch it here again. > Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:431 > + if (drawingArea->m_pendingNewlyReachedLayoutMilestones) > + retainedPage->send(Messages::WebPageProxy::DidReachLayoutMilestone(drawingArea->m_pendingNewlyReachedLayoutMilestones)); > + drawingArea->m_pendingNewlyReachedLayoutMilestones = 0; I would like to see this moved to a self-contained function. > Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:439 > + if (drawingArea->m_pendingNewlyReachedLayoutMilestones) > + retainedPage->send(Messages::WebPageProxy::DidReachLayoutMilestone(drawingArea->m_pendingNewlyReachedLayoutMilestones)); > + drawingArea->m_pendingNewlyReachedLayoutMilestones = 0; ...which you could also call here.
Comment on attachment 293734 [details] Have WebKit, not WebCore, defer sending the milestones until after the commit View in context: https://bugs.webkit.org/attachment.cgi?id=293734&action=review >> Source/WebCore/ChangeLog:11 >> + the call to firePaintRelatedMilestonesIfNeeded until after the commit. > > Was it deferred for a good reason, like coalescing? It was deferred in order to make sure that WebKit client gets notified only after the commit (see bug 115753). That bug was probably reintroduced when <https://trac.webkit.org/r166015> (the fix for bug 130541) made RenderLayerBacking::paintIntoLayer() call FrameView::didPaintContents(), which fires the paint-related milestones synchronously. That is, until <https://trac.webkit.org/r206247> introduced a completely different way for the milestones to be deferred, which happened to defer them too much in some cases. >> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:428 >> + if (TiledCoreAnimationDrawingArea* drawingArea = static_cast<TiledCoreAnimationDrawingArea*>(retainedPage->drawingArea())) { > > auto foo = downcast<TiledCoreAnimationDrawingArea>() ? > > When is drawingArea != this? Very confusing to fetch it here again. drawingArea is null if in the mean while WebPage::close has been called. >> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:439 >> + drawingArea->m_pendingNewlyReachedLayoutMilestones = 0; > > ...which you could also call here. I waffled on this. It will be a similar number of lines of code, and once 10.10 support is gone, it will be even more silly for it to be a function.
Created attachment 293747 [details] Have WebKit, not WebCore, defer sending the milestones until after the commit Made a helper function
Fixed in <https://trac.webkit.org/r208328>.