requestAnimationFrame should execute before the next frame
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Mar 2019 00:52:57 +0000 (00:52 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Mar 2019 00:52:57 +0000 (00:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177484

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2019-03-07
Reviewed by Simon Fraser.

Source/WebCore:

This change fixes two issues with animation timing:

1. Calling the requestAnimationFrame callbacks would have happened when
   the DisplayLink fires. This may have happened even if the frame is
   missed and no display is committed.

2. Style changes and layout triggered by script could trigger painting
   at more than 60fps. CoreAnimation commits could happen at more than
   60fps, although WindowServer will throttle those, and only some will
   be shown on the screen.

This change introduces a new paint scheduling model where painting is
driven by a "RenderingUpdateScheduler", which only triggers paints once
per 16.7ms frame.

Code that previously scheduled a compositing layer flush now schedules a
"RenderingUpdate", and that update is driven by a DisplayRefreshMonitor
callback. When the render happens, we service requestAnimationFrame callbacks,
Web Animations and intersection observations per the "Update the rendering"
step of the HTML Event Loop specification
<https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering>.

In the future, more rendering steps will be added to this code.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* accessibility/mac/AXObjectCacheMac.mm:
Fix layout tests by adding null check.

* animation/DocumentAnimationScheduler.cpp: Removed.
* animation/DocumentAnimationScheduler.h: Removed.
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::DocumentTimeline):
(WebCore::DocumentTimeline::updateThrottlingState):
(WebCore::DocumentTimeline::resumeAnimations):
(WebCore::DocumentTimeline::liveCurrentTime const):
(WebCore::DocumentTimeline::currentTime):
(WebCore::DocumentTimeline::animationTimingDidChange):
(WebCore::DocumentTimeline::scheduleAnimationResolution):
(WebCore::DocumentTimeline::unscheduleAnimationResolution):
(WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::scheduleNextTick):
(WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement):
Simplify this function by handling the case of no-animations separately.

(WebCore::DocumentTimeline::resolveAnimationsForElement):
Simplify the loop and delete hasPendingAcceleratedAnimations because it
is initialized to true and is not changed inside the loop.

(WebCore::DocumentTimeline::scheduleAnimationResolutionIfNeeded): Deleted.
(WebCore::DocumentTimeline::animationResolutionTimerFired): Deleted.
* animation/DocumentTimeline.h:
* dom/Document.cpp:
(WebCore::Document::resolveStyle):
There is no need to force update in resolveStyle(). notifyFlushRequired()
will be called eventually which will scheduleRenderingUpdate().

(WebCore::Document::prepareForDestruction):
(WebCore::Document::updateAnimationsAndSendEvents):
(WebCore::Document::serviceRequestAnimationFrameCallbacks):
(WebCore::Document::windowScreenDidChange):
(WebCore::Document::updateIntersectionObservations):
(WebCore::Document::scheduleForcedIntersectionObservationUpdate): Deleted.
(WebCore::Document::animationScheduler): Deleted.
* dom/Document.h:
(WebCore::Document::numberOfIntersectionObservers const):
* dom/ScriptedAnimationController.cpp:
(WebCore::ScriptedAnimationController::serviceRequestAnimationFrameCallbacks):
(WebCore::ScriptedAnimationController::scheduleAnimation):
(WebCore::ScriptedAnimationController::animationTimerFired):
(WebCore::ScriptedAnimationController::serviceScriptedAnimations): Deleted.
(WebCore::ScriptedAnimationController::documentAnimationSchedulerDidFire): Deleted.
* dom/ScriptedAnimationController.h:
* page/FrameView.cpp:
(WebCore::FrameView::viewportContentsChanged):
* page/IntersectionObserver.cpp:
(WebCore::IntersectionObserver::observe):
* page/Page.cpp:
(WebCore::Page::Page):
(WebCore::Page::layoutIfNeeded):
(WebCore::Page::renderingUpdate):
(WebCore::Page::renderingUpdateScheduler):
(WebCore::Page::willDisplayPage): Deleted.
(WebCore::Page::addDocumentNeedingIntersectionObservationUpdate): Deleted.
(WebCore::Page::updateIntersectionObservations): Deleted.
(WebCore::Page::scheduleForcedIntersectionObservationUpdate): Deleted.
* page/Page.h:
* page/PageOverlayController.cpp:
(WebCore::PageOverlayController::didChangeViewExposedRect):
(WebCore::PageOverlayController::notifyFlushRequired):
* page/ResourceUsageData.h:
Include header files that become missing because of adding
RenderingUpdateScheduler.cpp.

* page/RenderingUpdateScheduler.cpp: Added.
(WebCore::RenderingUpdateScheduler::RenderingUpdateScheduler):
(WebCore::RenderingUpdateScheduler::scheduleRenderingUpdate):
(WebCore::RenderingUpdateScheduler::startTimer):
(WebCore::RenderingUpdateScheduler::clearTimer):
(WebCore::RenderingUpdateScheduler::windowScreenDidChange):
(WebCore::RenderingUpdateScheduler::createDisplayRefreshMonitor const):
(WebCore::RenderingUpdateScheduler::displayRefreshFired):
* page/RenderingUpdateScheduler.h: Added.
(WebCore::RenderingUpdateScheduler::create):
* page/ios/ContentChangeObserver.h:
Include header files that become missing because of adding
RenderingUpdateScheduler.cpp.

* page/mac/ServicesOverlayController.mm:
(WebCore::ServicesOverlayController::Highlight::notifyFlushRequired):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::scheduleLayerFlushNow):

Source/WebKit:

Replace the calls to Page::layoutIfNeeded() and willDisplayPage() by
a single call to Page::renderingUpdate(). This new function implements
"Update the rendering" step of the HTML Event Loop specification
<https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering>.

* WebProcess/WebPage/AcceleratedDrawingArea.cpp:
(WebKit::AcceleratedDrawingArea::updateBackingStoreState):
* WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
(WebKit::LayerTreeHost::layerFlushTimerFired):
* WebProcess/WebPage/DrawingAreaImpl.cpp:
(WebKit::DrawingAreaImpl::display):
* WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::flushLayers):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::layoutIfNeeded):
(WebKit::WebPage::renderingUpdate):
(WebKit::WebPage::willDisplayPage): Deleted.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::TiledCoreAnimationDrawingArea::flushLayers):

Source/WebKitLegacy/mac:

* WebView/WebView.mm:
(-[WebView _viewWillDrawInternal]):
Call Page::renderingUpdate() which implements  "Update the rendering"
step of the HTML Event Loop specification.

Source/WebKitLegacy/win:

* WebView.cpp:
(WebView::updateBackingStore):
(WebView::flushPendingGraphicsLayerChangesSoon):
(WebView::flushPendingGraphicsLayerChanges):
Call Page::renderingUpdate() which implements  "Update the rendering"
step of the HTML Event Loop specification.

Source/WTF:

Add trace points for the page RenderingUpdate.

* wtf/SystemTracing.h:

Tools:

Add trace points for the page RenderingUpdate.

* Tracing/SystemTracePoints.plist:

LayoutTests:

* TestExpectations:
There is a slight difference between the actual DRT and the expected DRT
due to animation timing change. But these two tests are not animating
correctly if they are opened in Safari with web animation turned on.

* animations/animation-multiple-callbacks-timestamp.html:
Fix variable names used by an error message.
* animations/no-style-recalc-during-accelerated-animation-expected.txt:
* animations/no-style-recalc-during-accelerated-animation.html:
One extra styleReclc was incurred due to the document styleRecalcTimer.
I think this timer is not needed anymore. I will look at removing it in
a separate patch.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242624 268f45cc-cd09-0410-ab3c-d52691b4dbfc

41 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/animations/animation-multiple-callbacks-timestamp.html
LayoutTests/animations/no-style-recalc-during-accelerated-animation-expected.txt
LayoutTests/animations/no-style-recalc-during-accelerated-animation.html
Source/WTF/ChangeLog
Source/WTF/wtf/SystemTracing.h
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/accessibility/mac/AXObjectCacheMac.mm
Source/WebCore/animation/DocumentAnimationScheduler.cpp [deleted file]
Source/WebCore/animation/DocumentTimeline.cpp
Source/WebCore/animation/DocumentTimeline.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ScriptedAnimationController.cpp
Source/WebCore/dom/ScriptedAnimationController.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/IntersectionObserver.cpp
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/page/PageOverlayController.cpp
Source/WebCore/page/RenderingUpdateScheduler.cpp [new file with mode: 0644]
Source/WebCore/page/RenderingUpdateScheduler.h [moved from Source/WebCore/animation/DocumentAnimationScheduler.h with 58% similarity]
Source/WebCore/page/ios/ContentChangeObserver.h
Source/WebCore/page/mac/ServicesOverlayController.mm
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp
Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebView.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebView.cpp
Tools/ChangeLog
Tools/Tracing/SystemTracePoints.plist

index d3fb796..cab2b51 100644 (file)
@@ -1,3 +1,23 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        * TestExpectations:
+        There is a slight difference between the actual DRT and the expected DRT
+        due to animation timing change. But these two tests are not animating
+        correctly if they are opened in Safari with web animation turned on. 
+
+        * animations/animation-multiple-callbacks-timestamp.html:
+        Fix variable names used by an error message.
+        * animations/no-style-recalc-during-accelerated-animation-expected.txt:
+        * animations/no-style-recalc-during-accelerated-animation.html:
+        One extra styleReclc was incurred due to the document styleRecalcTimer.
+        I think this timer is not needed anymore. I will look at removing it in
+        a separate patch.
+
 2019-03-07  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Add a setting to be able to turn content change observation on/off
index d25fd1b..6506afa 100644 (file)
@@ -3038,6 +3038,8 @@ webkit.org/b/187773 http/tests/webAPIStatistics [ Skip ]
 
 # This is fallout from turning Web Animations on.
 webkit.org/b/190032 animations/animation-playstate-paused-style-resolution.html [ Failure ]
+webkit.org/b/190032 animations/missing-values-first-keyframe.html [ Failure ]
+webkit.org/b/190032 animations/missing-values-last-keyframe.html [ Failure ]
 webkit.org/b/190032 compositing/backing/backing-store-attachment-fill-forwards-animation.html [ Failure ]
 webkit.org/b/190032 compositing/backing/transform-transition-from-outside-view.html [ Failure ]
 webkit.org/b/190032 compositing/layer-creation/mismatched-rotated-transform-transition-overlap.html [ Failure ]
index 5ddd9bf..750e2c7 100644 (file)
@@ -35,7 +35,7 @@
         {
             const WarmupFrames = 5;
             if (++currentFrame > WarmupFrames && timestamp != timestamp1) {
-                testFailed("timestamp1 = " + timestamp1 + ", timestamp2 = " + timestamp2  + ", window.performance.now() = " + window.performance.now());
+                testFailed("timestamp = " + timestamp + ", timestamp1 = " + timestamp1  + ", window.performance.now() = " + window.performance.now());
                 failed = true;
             }
         }
index cfa01f7..05f0aef 100644 (file)
             box.addEventListener("animationiteration", () => result.innerText = "Got iteration event.\n");
             box.addEventListener("animationend", () => {
                 const numRecalcs = internals.styleRecalcCount();
-                if (numRecalcs > 2)
-                    result.innerText += "FAIL: saw " + numRecalcs + " style recalcs during the animation, should only see two."
+                if (numRecalcs > 3)
+                    result.innerText += "FAIL: saw " + numRecalcs + " style recalcs during the animation, should only see three."
                 else 
-                    result.innerText += "PASS: saw two or fewer style recalcs during the animation."
+                    result.innerText += "PASS: saw three or fewer style recalcs during the animation."
 
                 if (window.testRunner)
                     testRunner.notifyDone();
index 0d9c9a4..305b232 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        Add trace points for the page RenderingUpdate.
+
+        * wtf/SystemTracing.h:
+
 2019-03-06  Ross Kirsling  <ross.kirsling@sony.com>
 
         [Win] Remove -DUCHAR_TYPE=wchar_t stopgap and learn to live with char16_t.
index ac9fda0..bcce0f9 100644 (file)
@@ -77,6 +77,11 @@ enum TracePointCode {
     ComputeEventRegionsStart,
     ComputeEventRegionsEnd,
 
+    ScheduleRenderingUpdate,
+    TriggerRenderingUpdate,
+    RenderingUpdateStart,
+    RenderingUpdateEnd,
+
     WebKitRange = 10000,
     WebHTMLViewPaintStart,
     WebHTMLViewPaintEnd,
index 3337e91..afacb99 100644 (file)
@@ -1,3 +1,124 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        This change fixes two issues with animation timing:
+
+        1. Calling the requestAnimationFrame callbacks would have happened when
+           the DisplayLink fires. This may have happened even if the frame is
+           missed and no display is committed.
+
+        2. Style changes and layout triggered by script could trigger painting
+           at more than 60fps. CoreAnimation commits could happen at more than
+           60fps, although WindowServer will throttle those, and only some will
+           be shown on the screen.
+
+        This change introduces a new paint scheduling model where painting is
+        driven by a "RenderingUpdateScheduler", which only triggers paints once
+        per 16.7ms frame.
+
+        Code that previously scheduled a compositing layer flush now schedules a
+        "RenderingUpdate", and that update is driven by a DisplayRefreshMonitor
+        callback. When the render happens, we service requestAnimationFrame callbacks,
+        Web Animations and intersection observations per the "Update the rendering"
+        step of the HTML Event Loop specification
+        <https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering>.
+
+        In the future, more rendering steps will be added to this code.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * accessibility/mac/AXObjectCacheMac.mm:
+        Fix layout tests by adding null check.
+
+        * animation/DocumentAnimationScheduler.cpp: Removed.
+        * animation/DocumentAnimationScheduler.h: Removed.
+        * animation/DocumentTimeline.cpp:
+        (WebCore::DocumentTimeline::DocumentTimeline):
+        (WebCore::DocumentTimeline::updateThrottlingState):
+        (WebCore::DocumentTimeline::resumeAnimations):
+        (WebCore::DocumentTimeline::liveCurrentTime const):
+        (WebCore::DocumentTimeline::currentTime):
+        (WebCore::DocumentTimeline::animationTimingDidChange):
+        (WebCore::DocumentTimeline::scheduleAnimationResolution):
+        (WebCore::DocumentTimeline::unscheduleAnimationResolution):
+        (WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
+        (WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents):
+        (WebCore::DocumentTimeline::scheduleNextTick):
+        (WebCore::DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement):
+        Simplify this function by handling the case of no-animations separately.
+
+        (WebCore::DocumentTimeline::resolveAnimationsForElement):
+        Simplify the loop and delete hasPendingAcceleratedAnimations because it
+        is initialized to true and is not changed inside the loop.
+
+        (WebCore::DocumentTimeline::scheduleAnimationResolutionIfNeeded): Deleted.
+        (WebCore::DocumentTimeline::animationResolutionTimerFired): Deleted.
+        * animation/DocumentTimeline.h:
+        * dom/Document.cpp:
+        (WebCore::Document::resolveStyle):
+        There is no need to force update in resolveStyle(). notifyFlushRequired()
+        will be called eventually which will scheduleRenderingUpdate().
+
+        (WebCore::Document::prepareForDestruction):
+        (WebCore::Document::updateAnimationsAndSendEvents):
+        (WebCore::Document::serviceRequestAnimationFrameCallbacks):
+        (WebCore::Document::windowScreenDidChange):
+        (WebCore::Document::updateIntersectionObservations):
+        (WebCore::Document::scheduleForcedIntersectionObservationUpdate): Deleted.
+        (WebCore::Document::animationScheduler): Deleted.
+        * dom/Document.h:
+        (WebCore::Document::numberOfIntersectionObservers const):
+        * dom/ScriptedAnimationController.cpp:
+        (WebCore::ScriptedAnimationController::serviceRequestAnimationFrameCallbacks):
+        (WebCore::ScriptedAnimationController::scheduleAnimation):
+        (WebCore::ScriptedAnimationController::animationTimerFired):
+        (WebCore::ScriptedAnimationController::serviceScriptedAnimations): Deleted.
+        (WebCore::ScriptedAnimationController::documentAnimationSchedulerDidFire): Deleted.
+        * dom/ScriptedAnimationController.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::viewportContentsChanged):
+        * page/IntersectionObserver.cpp:
+        (WebCore::IntersectionObserver::observe):
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+        (WebCore::Page::layoutIfNeeded):
+        (WebCore::Page::renderingUpdate):
+        (WebCore::Page::renderingUpdateScheduler):
+        (WebCore::Page::willDisplayPage): Deleted.
+        (WebCore::Page::addDocumentNeedingIntersectionObservationUpdate): Deleted.
+        (WebCore::Page::updateIntersectionObservations): Deleted.
+        (WebCore::Page::scheduleForcedIntersectionObservationUpdate): Deleted.
+        * page/Page.h:
+        * page/PageOverlayController.cpp:
+        (WebCore::PageOverlayController::didChangeViewExposedRect):
+        (WebCore::PageOverlayController::notifyFlushRequired):
+        * page/ResourceUsageData.h:
+        Include header files that become missing because of adding 
+        RenderingUpdateScheduler.cpp.
+
+        * page/RenderingUpdateScheduler.cpp: Added.
+        (WebCore::RenderingUpdateScheduler::RenderingUpdateScheduler):
+        (WebCore::RenderingUpdateScheduler::scheduleRenderingUpdate):
+        (WebCore::RenderingUpdateScheduler::startTimer):
+        (WebCore::RenderingUpdateScheduler::clearTimer):
+        (WebCore::RenderingUpdateScheduler::windowScreenDidChange):
+        (WebCore::RenderingUpdateScheduler::createDisplayRefreshMonitor const):
+        (WebCore::RenderingUpdateScheduler::displayRefreshFired):
+        * page/RenderingUpdateScheduler.h: Added.
+        (WebCore::RenderingUpdateScheduler::create):
+        * page/ios/ContentChangeObserver.h:
+        Include header files that become missing because of adding 
+        RenderingUpdateScheduler.cpp.
+
+        * page/mac/ServicesOverlayController.mm:
+        (WebCore::ServicesOverlayController::Highlight::notifyFlushRequired):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
+
 2019-03-07  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Add a setting to be able to turn content change observation on/off
index 41f6356..6711fe3 100644 (file)
@@ -420,7 +420,6 @@ animation/AnimationTimeline.cpp
 animation/CSSAnimation.cpp
 animation/CSSTransition.cpp
 animation/DeclarativeAnimation.cpp
-animation/DocumentAnimationScheduler.cpp
 animation/DocumentTimeline.cpp
 animation/KeyframeEffect.cpp
 animation/WebAnimation.cpp
@@ -1539,6 +1538,7 @@ page/ProcessWarming.cpp
 page/Quirks.cpp
 page/RemoteDOMWindow.cpp
 page/RemoteFrame.cpp
+page/RenderingUpdateScheduler.cpp
 page/ResourceUsageOverlay.cpp
 page/ResourceUsageThread.cpp
 page/RuntimeEnabledFeatures.cpp
index 149e27b..48422a7 100644 (file)
                5550CB421E955E3C00111AA0 /* ImageTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 5550CB411E955E3C00111AA0 /* ImageTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                555130011E7CCCCB00A69E38 /* DecodingOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 555130001E7CCCCA00A69E38 /* DecodingOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
                555B87ED1CAAF0AB00349425 /* ImageDecoderCG.h in Headers */ = {isa = PBXBuildFile; fileRef = 555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */; };
+               556C7C4B22123997009B06CA /* RenderingUpdateScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 556C7C4722123942009B06CA /* RenderingUpdateScheduler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5576A5651D88A70800CCC04C /* ImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 5576A5631D88A70800CCC04C /* ImageFrame.h */; settings = {ATTRIBUTES = (Private, ); }; };
                55A336F91D821E3C0022C4C7 /* ImageBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 55A336F81D821E3C0022C4C7 /* ImageBackingStore.h */; settings = {ATTRIBUTES = (Private, ); }; };
                55AF14E61EAAC59B0026EEAA /* UTIRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 55AF14E41EAAC59B0026EEAA /* UTIRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7156BCA121CA350F00534397 /* BasicEffectTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 7156BC9F21CA350600534397 /* BasicEffectTiming.h */; };
                715AD7202050513200D592DC /* DeclarativeAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 715AD71D2050512400D592DC /* DeclarativeAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                715AD7212050513F00D592DC /* CSSTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 7123C186204739BA00789392 /* CSSTransition.h */; };
-               716E55B020DBABF100F0CF29 /* DocumentAnimationScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 716E55AD20DBABDC00F0CF29 /* DocumentAnimationScheduler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                71729F7B20F3BA4900801CE6 /* DocumentTimelineOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 71729F7A20F3BA3A00801CE6 /* DocumentTimelineOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
                71729F7E20F3BB4700801CE6 /* JSDocumentTimelineOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 71729F7C20F3BAB900801CE6 /* JSDocumentTimelineOptions.h */; };
                71A1B6081DEE5AD70073BCFB /* modern-media-controls-localized-strings.js in Resources */ = {isa = PBXBuildFile; fileRef = 71A1B6061DEE5A820073BCFB /* modern-media-controls-localized-strings.js */; };
                555130001E7CCCCA00A69E38 /* DecodingOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecodingOptions.h; sourceTree = "<group>"; };
                555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecoderCG.cpp; sourceTree = "<group>"; };
                555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDecoderCG.h; sourceTree = "<group>"; };
+               556C7C4722123942009B06CA /* RenderingUpdateScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderingUpdateScheduler.h; sourceTree = "<group>"; };
+               556C7C4922123943009B06CA /* RenderingUpdateScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderingUpdateScheduler.cpp; sourceTree = "<group>"; };
                5576A5621D88A70800CCC04C /* ImageFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrame.cpp; sourceTree = "<group>"; };
                5576A5631D88A70800CCC04C /* ImageFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrame.h; sourceTree = "<group>"; };
                5597FCCB2076C06800D35BB0 /* GlyphDisplayListCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlyphDisplayListCache.h; sourceTree = "<group>"; };
                716C8DF21E48B269005BD0DA /* volume-up-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "volume-up-support.js"; sourceTree = "<group>"; };
                716C8DF31E48B284005BD0DA /* volume-down-button.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "volume-down-button.js"; sourceTree = "<group>"; };
                716C8DF41E48B284005BD0DA /* volume-up-button.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "volume-up-button.js"; sourceTree = "<group>"; };
-               716E55AD20DBABDC00F0CF29 /* DocumentAnimationScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentAnimationScheduler.h; sourceTree = "<group>"; };
-               716E55AF20DBABDD00F0CF29 /* DocumentAnimationScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentAnimationScheduler.cpp; sourceTree = "<group>"; };
                716FA0D81DB26591007323CC /* airplay-button.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "airplay-button.css"; sourceTree = "<group>"; };
                716FA0D91DB26591007323CC /* airplay-button.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "airplay-button.js"; sourceTree = "<group>"; };
                716FA0DA1DB26591007323CC /* airplay-placard.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "airplay-placard.js"; sourceTree = "<group>"; };
                                46BCBBC3208500A700710638 /* RemoteDOMWindow.idl */,
                                46B9518C207D632900A7D2DD /* RemoteFrame.cpp */,
                                46B95192207D632E00A7D2DD /* RemoteFrame.h */,
+                               556C7C4922123943009B06CA /* RenderingUpdateScheduler.cpp */,
+                               556C7C4722123942009B06CA /* RenderingUpdateScheduler.h */,
                                A5071E821C56D079009951BE /* ResourceUsageData.h */,
                                ADBAD6EC1BCDD95000381325 /* ResourceUsageOverlay.cpp */,
                                ADBAD6ED1BCDD95000381325 /* ResourceUsageOverlay.h */,
                                7123C185204739B900789392 /* CSSTransition.idl */,
                                715AD71F2050512400D592DC /* DeclarativeAnimation.cpp */,
                                715AD71D2050512400D592DC /* DeclarativeAnimation.h */,
-                               716E55AF20DBABDD00F0CF29 /* DocumentAnimationScheduler.cpp */,
-                               716E55AD20DBABDC00F0CF29 /* DocumentAnimationScheduler.h */,
                                71025EC41F99F096004A250C /* DocumentTimeline.cpp */,
                                71025EC51F99F096004A250C /* DocumentTimeline.h */,
                                71025ECA1F99F096004A250C /* DocumentTimeline.idl */,
                                B2F34FE60E82F81400F627CD /* DNS.h in Headers */,
                                7EE6846F12D26E3800E73215 /* DNSResolveQueueCFNet.h in Headers */,
                                A8185F4009765766005826D9 /* Document.h in Headers */,
-                               716E55B020DBABF100F0CF29 /* DocumentAnimationScheduler.h in Headers */,
                                A3BB59F41457A40D00AC56FE /* DocumentEventQueue.h in Headers */,
                                A8185F3D09765766005826D9 /* DocumentFragment.h in Headers */,
                                46E1666E1FCC86A200C9710B /* DocumentIdentifier.h in Headers */,
                                BCEA4876097D93020094C9E4 /* RenderImage.h in Headers */,
                                08F2F00A1213E61700DCEC48 /* RenderImageResource.h in Headers */,
                                08641D4812142F7D008DE9F6 /* RenderImageResourceStyleImage.h in Headers */,
+                               556C7C4B22123997009B06CA /* RenderingUpdateScheduler.h in Headers */,
                                BCEA4878097D93020094C9E4 /* RenderInline.h in Headers */,
                                B595FF471824CEE300FF51CD /* RenderIterator.h in Headers */,
                                BCEA487A097D93020094C9E4 /* RenderLayer.h in Headers */,
index 1bb5898..bc684d1 100644 (file)
@@ -539,8 +539,14 @@ void AXObjectCache::platformHandleFocusedUIElementChanged(Node*, Node*)
 {
     NSAccessibilityHandleFocusChanged();
     // AXFocusChanged is a test specific notification name and not something a real AT will be listening for
-    if (UNLIKELY(axShouldRepostNotificationsForTests))
-        [rootWebArea()->wrapper() accessibilityPostedNotification:@"AXFocusChanged" userInfo:nil];
+    if (UNLIKELY(!axShouldRepostNotificationsForTests))
+        return;
+
+    auto* rootWebArea = this->rootWebArea();
+    if (!rootWebArea)
+        return;
+
+    [rootWebArea->wrapper() accessibilityPostedNotification:@"AXFocusChanged" userInfo:nil];
 }
 
 void AXObjectCache::handleScrolledToAnchor(const Node*)
diff --git a/Source/WebCore/animation/DocumentAnimationScheduler.cpp b/Source/WebCore/animation/DocumentAnimationScheduler.cpp
deleted file mode 100644 (file)
index ada330a..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "DocumentAnimationScheduler.h"
-
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-
-#include "Chrome.h"
-#include "ChromeClient.h"
-#include "DOMWindow.h"
-#include "DisplayRefreshMonitor.h"
-#include "DisplayRefreshMonitorManager.h"
-#include "Document.h"
-#include "DocumentTimeline.h"
-#include "Page.h"
-#include "ScriptedAnimationController.h"
-
-namespace WebCore {
-
-Ref<DocumentAnimationScheduler> DocumentAnimationScheduler::create(Document& document, PlatformDisplayID displayID)
-{
-    return adoptRef(*new DocumentAnimationScheduler(document, displayID));
-}
-
-DocumentAnimationScheduler::DocumentAnimationScheduler(Document& document, PlatformDisplayID displayID)
-    : m_document(&document)
-{
-    windowScreenDidChange(displayID);
-}
-
-DocumentAnimationScheduler::~DocumentAnimationScheduler() = default;
-
-void DocumentAnimationScheduler::detachFromDocument()
-{
-    m_document = nullptr;
-}
-
-bool DocumentAnimationScheduler::scheduleWebAnimationsResolution()
-{
-    m_scheduledWebAnimationsResolution = true;
-    return DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this);
-}
-
-void DocumentAnimationScheduler::unscheduleWebAnimationsResolution()
-{
-    m_scheduledWebAnimationsResolution = false;
-
-    if (!m_scheduledScriptedAnimationResolution)
-        DisplayRefreshMonitorManager::sharedManager().unregisterClient(*this);
-}
-
-bool DocumentAnimationScheduler::scheduleScriptedAnimationResolution()
-{
-    m_scheduledScriptedAnimationResolution = true;
-    return DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this);
-}
-
-void DocumentAnimationScheduler::displayRefreshFired()
-{
-    if (!m_document || !m_document->domWindow())
-        return;
-
-    // This object could be deleted after scripts in the the requestAnimationFrame callbacks are executed.
-    auto protectedThis = makeRef(*this);
-
-    m_isFiring = true;
-    m_lastTimestamp = Seconds(m_document->domWindow()->nowTimestamp());
-
-    if (m_scheduledWebAnimationsResolution) {
-        m_scheduledWebAnimationsResolution = false;
-        m_document->timeline().documentAnimationSchedulerDidFire();
-    }
-
-    if (m_scheduledScriptedAnimationResolution) {
-        m_scheduledScriptedAnimationResolution = false;
-        if (auto* scriptedAnimationController = m_document->scriptedAnimationController())
-            scriptedAnimationController->documentAnimationSchedulerDidFire();
-    }
-
-    m_isFiring = false;
-}
-
-void DocumentAnimationScheduler::windowScreenDidChange(PlatformDisplayID displayID)
-{
-    DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this);
-}
-
-RefPtr<DisplayRefreshMonitor> DocumentAnimationScheduler::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
-{
-    if (!m_document || !m_document->page())
-        return nullptr;
-
-    if (auto monitor = m_document->page()->chrome().client().createDisplayRefreshMonitor(displayID))
-        return monitor;
-
-    return DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(displayID);
-}
-
-} // namespace WebCore
-
-#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
index 3018cbb..aba49f4 100644 (file)
@@ -33,7 +33,6 @@
 #include "DOMWindow.h"
 #include "DeclarativeAnimation.h"
 #include "Document.h"
-#include "DocumentAnimationScheduler.h"
 #include "GraphicsLayer.h"
 #include "KeyframeEffect.h"
 #include "Microtasks.h"
@@ -61,10 +60,7 @@ Ref<DocumentTimeline> DocumentTimeline::create(Document& document, DocumentTimel
 
 DocumentTimeline::DocumentTimeline(Document& document, Seconds originTime)
     : AnimationTimeline()
-#if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    , m_animationResolutionTimer(*this, &DocumentTimeline::animationResolutionTimerFired)
-#endif
-    , m_tickScheduleTimer(*this, &DocumentTimeline::scheduleAnimationResolutionIfNeeded)
+    , m_tickScheduleTimer(*this, &DocumentTimeline::scheduleAnimationResolution)
     , m_document(&document)
     , m_originTime(originTime)
 {
@@ -194,7 +190,7 @@ Vector<RefPtr<WebAnimation>> DocumentTimeline::getAnimations() const
 
 void DocumentTimeline::updateThrottlingState()
 {
-    scheduleAnimationResolutionIfNeeded();
+    scheduleAnimationResolution();
 }
 
 Seconds DocumentTimeline::animationInterval() const
@@ -210,7 +206,7 @@ void DocumentTimeline::suspendAnimations()
         return;
 
     if (!m_cachedCurrentTime)
-        m_cachedCurrentTime = liveCurrentTime();
+        m_cachedCurrentTime = Seconds(liveCurrentTime());
 
     for (const auto& animation : m_animations)
         animation->setSuspended(true);
@@ -234,7 +230,7 @@ void DocumentTimeline::resumeAnimations()
     for (const auto& animation : m_animations)
         animation->setSuspended(false);
 
-    scheduleAnimationResolutionIfNeeded();
+    scheduleAnimationResolution();
 }
 
 bool DocumentTimeline::animationsAreSuspended()
@@ -252,13 +248,9 @@ unsigned DocumentTimeline::numberOfActiveAnimationsForTesting() const
     return count;
 }
 
-Seconds DocumentTimeline::liveCurrentTime() const
+DOMHighResTimeStamp DocumentTimeline::liveCurrentTime() const
 {
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    return m_document->animationScheduler().lastTimestamp();
-#else
-    return Seconds(m_document->domWindow()->nowTimestamp());
-#endif
+    return m_document->domWindow()->nowTimestamp();
 }
 
 Optional<Seconds> DocumentTimeline::currentTime()
@@ -274,36 +266,15 @@ Optional<Seconds> DocumentTimeline::currentTime()
         }
     }
 
-    auto currentTime = liveCurrentTime();
-
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    // If we're in the middle of firing a frame, either due to a requestAnimationFrame callback
-    // or scheduling an animation update, we want to ensure we use the same time we're using as
-    // the timestamp for requestAnimationFrame() callbacks.
-    if (m_document->animationScheduler().isFiring())
-        cacheCurrentTime(currentTime);
-#endif
-
-    if (!m_cachedCurrentTime) {
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-        // If we're not in the middle of firing a frame, let's make our best guess at what the currentTime should
-        // be since the last time a frame fired by increment of our update interval. This way code using something
-        // like setTimeout() or handling events will get a time that's only updating at around 60fps, or less if
-        // we're throttled.
-        auto lastAnimationSchedulerTimestamp = currentTime;
-        auto delta = Seconds(m_document->domWindow()->nowTimestamp()) - lastAnimationSchedulerTimestamp;
-        int frames = std::floor(delta.seconds() / animationInterval().seconds());
-        cacheCurrentTime(lastAnimationSchedulerTimestamp + Seconds(frames * animationInterval().seconds()));
-#else
-        cacheCurrentTime(currentTime);
-#endif
-    }
+    if (!m_cachedCurrentTime)
+        cacheCurrentTime(liveCurrentTime());
+    
     return m_cachedCurrentTime.value() - m_originTime;
 }
 
-void DocumentTimeline::cacheCurrentTime(Seconds newCurrentTime)
+void DocumentTimeline::cacheCurrentTime(DOMHighResTimeStamp newCurrentTime)
 {
-    m_cachedCurrentTime = newCurrentTime;
+    m_cachedCurrentTime = Seconds(newCurrentTime);
     // We want to be sure to keep this time cached until we've both finished running JS and finished updating
     // animations, so we schedule the invalidation task and register a whenIdle callback on the VM, which will
     // fire syncronously if no JS is running.
@@ -326,16 +297,10 @@ void DocumentTimeline::maybeClearCachedCurrentTime()
         m_cachedCurrentTime = WTF::nullopt;
 }
 
-void DocumentTimeline::scheduleAnimationResolutionIfNeeded()
-{
-    if (!m_isUpdatingAnimations && !m_isSuspended && !m_animations.isEmpty())
-        scheduleAnimationResolution();
-}
-
 void DocumentTimeline::animationTimingDidChange(WebAnimation& animation)
 {
     AnimationTimeline::animationTimingDidChange(animation);
-    scheduleAnimationResolutionIfNeeded();
+    scheduleAnimationResolution();
 }
 
 void DocumentTimeline::removeAnimation(WebAnimation& animation)
@@ -348,44 +313,44 @@ void DocumentTimeline::removeAnimation(WebAnimation& animation)
 
 void DocumentTimeline::scheduleAnimationResolution()
 {
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    m_document->animationScheduler().scheduleWebAnimationsResolution();
-#else
-    // FIXME: We need to use the same logic as ScriptedAnimationController here,
-    // which will be addressed by the refactor tracked by webkit.org/b/179293.
-    m_animationResolutionTimer.startOneShot(animationInterval());
-#endif
+    if (m_isSuspended || m_animations.isEmpty() || m_animationResolutionScheduled)
+        return;
+
+    if (!m_document || !m_document->page())
+        return;
+    
+    m_document->page()->renderingUpdateScheduler().scheduleRenderingUpdate();
+    m_animationResolutionScheduled = true;
 }
 
 void DocumentTimeline::unscheduleAnimationResolution()
 {
     m_tickScheduleTimer.stop();
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    m_document->animationScheduler().unscheduleWebAnimationsResolution();
-#else
-    // FIXME: We need to use the same logic as ScriptedAnimationController here,
-    // which will be addressed by the refactor tracked by webkit.org/b/179293.
-    m_animationResolutionTimer.stop();
-#endif
-}
-
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-void DocumentTimeline::documentAnimationSchedulerDidFire()
-#else
-void DocumentTimeline::animationResolutionTimerFired()
-#endif
-{
-    updateAnimationsAndSendEvents();
+    m_animationResolutionScheduled = false;
+}
+
+void DocumentTimeline::updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp)
+{
+    // We need to freeze the current time even if no animation is running.
+    // document.timeline.currentTime may be called from a rAF callback and
+    // it has to match the rAF timestamp.
+    if (!m_isSuspended)
+        cacheCurrentTime(timestamp);
+
+    if (m_isSuspended || m_animations.isEmpty() || !m_animationResolutionScheduled)
+        return;
+
+    internalUpdateAnimationsAndSendEvents();
     applyPendingAcceleratedAnimations();
+
+    m_animationResolutionScheduled = false;
     scheduleNextTick();
 }
 
-void DocumentTimeline::updateAnimationsAndSendEvents()
+void DocumentTimeline::internalUpdateAnimationsAndSendEvents()
 {
     m_numberOfAnimationTimelineInvalidationsForTesting++;
 
-    m_isUpdatingAnimations = true;
-
     // https://drafts.csswg.org/web-animations/#update-animations-and-send-events
 
     // 1. Update the current time of all timelines associated with doc passing now as the timestamp.
@@ -448,8 +413,6 @@ void DocumentTimeline::updateAnimationsAndSendEvents()
     // removed from the list of completed transitions otherwise.
     for (auto& completedTransition : completedTransitions)
         transitionDidComplete(completedTransition);
-
-    m_isUpdatingAnimations = false;
 }
 
 void DocumentTimeline::transitionDidComplete(RefPtr<CSSTransition> transition)
@@ -473,7 +436,7 @@ void DocumentTimeline::scheduleNextTick()
 
     for (const auto& animation : m_animations) {
         if (!animation->isRunningAccelerated()) {
-            scheduleAnimationResolutionIfNeeded();
+            scheduleAnimationResolution();
             return;
         }
     }
@@ -483,7 +446,7 @@ void DocumentTimeline::scheduleNextTick()
     for (const auto& animation : m_animations) {
         auto animationTimeToNextRequiredTick = animation->timeToNextTick();
         if (animationTimeToNextRequiredTick < animationInterval()) {
-            scheduleAnimationResolutionIfNeeded();
+            scheduleAnimationResolution();
             return;
         }
         scheduleDelay = std::min(scheduleDelay, animationTimeToNextRequiredTick);
@@ -593,18 +556,20 @@ void DocumentTimeline::animationAcceleratedRunningStateDidChange(WebAnimation& a
 void DocumentTimeline::updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element& element)
 {
     auto animations = animationsForElement(element);
-    bool runningAnimationsForElementAreAllAccelerated = !animations.isEmpty();
+
+    if (animations.isEmpty()) {
+        m_elementsWithRunningAcceleratedAnimations.remove(&element);
+        return;
+    }
+
     for (const auto& animation : animations) {
         if (!animation->isRunningAccelerated()) {
-            runningAnimationsForElementAreAllAccelerated = false;
-            break;
+            m_elementsWithRunningAcceleratedAnimations.remove(&element);
+            return;
         }
     }
 
-    if (runningAnimationsForElementAreAllAccelerated)
-        m_elementsWithRunningAcceleratedAnimations.add(&element);
-    else
-        m_elementsWithRunningAcceleratedAnimations.remove(&element);
+    m_elementsWithRunningAcceleratedAnimations.add(&element);
 }
 
 void DocumentTimeline::applyPendingAcceleratedAnimations()
@@ -625,30 +590,28 @@ void DocumentTimeline::applyPendingAcceleratedAnimations()
 
 bool DocumentTimeline::resolveAnimationsForElement(Element& element, RenderStyle& targetStyle)
 {
-    bool hasNonAcceleratedAnimations = false;
-    bool hasPendingAcceleratedAnimations = true;
+    bool hasNonAcceleratedAnimationProperty = false;
+
     for (const auto& animation : animationsForElement(element)) {
         animation->resolve(targetStyle);
-        if (!hasNonAcceleratedAnimations) {
-            if (auto* effect = animation->effect()) {
-                if (is<KeyframeEffect>(effect)) {
-                    auto* keyframeEffect = downcast<KeyframeEffect>(effect);
-                    for (auto cssPropertyId : keyframeEffect->animatedProperties()) {
-                        if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) {
-                            hasNonAcceleratedAnimations = true;
-                            continue;
-                        }
-                        if (!hasPendingAcceleratedAnimations)
-                            hasPendingAcceleratedAnimations = keyframeEffect->hasPendingAcceleratedAction();
-                    }
-                }
+
+        if (hasNonAcceleratedAnimationProperty)
+            continue;
+
+        auto* effect = animation->effect();
+        if (!effect || !is<KeyframeEffect>(effect))
+            continue;
+
+        auto* keyframeEffect = downcast<KeyframeEffect>(effect);
+        for (auto cssPropertyId : keyframeEffect->animatedProperties()) {
+            if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(cssPropertyId)) {
+                hasNonAcceleratedAnimationProperty = true;
+                break;
             }
         }
     }
 
-    // If there are no non-accelerated animations and we've encountered at least one pending
-    // accelerated animation, we should recomposite this element's layer for animation purposes.
-    return !hasNonAcceleratedAnimations && hasPendingAcceleratedAnimations;
+    return !hasNonAcceleratedAnimationProperty;
 }
 
 bool DocumentTimeline::runningAnimationsForElementAreAllAccelerated(Element& element) const
index 7cc81c9..49a1110 100644 (file)
@@ -71,10 +71,8 @@ public:
     void detachFromDocument();
 
     void enqueueAnimationPlaybackEvent(AnimationPlaybackEvent&);
-
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    void documentAnimationSchedulerDidFire();
-#endif
+    
+    void updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp);
 
     void updateThrottlingState();
     WEBCORE_EXPORT Seconds animationInterval() const;
@@ -88,26 +86,19 @@ public:
 private:
     DocumentTimeline(Document&, Seconds);
 
-    Seconds liveCurrentTime() const;
-    void cacheCurrentTime(Seconds);
-    void scheduleAnimationResolutionIfNeeded();
+    DOMHighResTimeStamp liveCurrentTime() const;
+    void cacheCurrentTime(DOMHighResTimeStamp);
+    void maybeClearCachedCurrentTime();
     void scheduleInvalidationTaskIfNeeded();
     void performInvalidationTask();
-    void animationScheduleTimerFired();
     void scheduleAnimationResolution();
     void unscheduleAnimationResolution();
-    void updateAnimationsAndSendEvents();
+    void internalUpdateAnimationsAndSendEvents();
     void performEventDispatchTask();
-    void maybeClearCachedCurrentTime();
     void updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element&);
     void transitionDidComplete(RefPtr<CSSTransition>);
     void scheduleNextTick();
 
-#if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    void animationResolutionTimerFired();
-    Timer m_animationResolutionTimer;
-#endif
-
     Timer m_tickScheduleTimer;
     GenericTaskQueue<Timer> m_currentTimeClearingTaskQueue;
     HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange;
@@ -119,7 +110,7 @@ private:
     unsigned m_numberOfAnimationTimelineInvalidationsForTesting { 0 };
     bool m_isSuspended { false };
     bool m_waitingOnVMIdle { false };
-    bool m_isUpdatingAnimations { false };
+    bool m_animationResolutionScheduled { false };
 };
 
 } // namespace WebCore
index 1429278..e184c1f 100644 (file)
@@ -57,7 +57,6 @@
 #include "DOMWindow.h"
 #include "DateComponents.h"
 #include "DebugPageOverlays.h"
-#include "DocumentAnimationScheduler.h"
 #include "DocumentLoader.h"
 #include "DocumentMarkerController.h"
 #include "DocumentSharedObjectPool.h"
@@ -1957,11 +1956,8 @@ void Document::resolveStyle(ResolveStyleType type)
             frameView.layoutContext().scheduleLayout();
 
         // Usually this is handled by post-layout.
-        if (!frameView.needsLayout()) {
+        if (!frameView.needsLayout())
             frameView.frame().selection().scheduleAppearanceUpdateAfterStyleChange();
-            if (m_needsForcedIntersectionObservationUpdate)
-                page()->scheduleForcedIntersectionObservationUpdate(*this);
-        }
 
         // As a result of the style recalculation, the currently hovered element might have been
         // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event
@@ -2558,13 +2554,6 @@ void Document::prepareForDestruction()
         m_timeline = nullptr;
     }
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    if (m_animationScheduler) {
-        m_animationScheduler->detachFromDocument();
-        m_animationScheduler = nullptr;
-    }
-#endif
-
 #if ENABLE(CSS_PAINTING_API)
     for (auto& scope : m_paintWorkletGlobalScopes.values())
         scope->prepareForDestruction();
@@ -6261,13 +6250,20 @@ void Document::resumeScriptedAnimationControllerCallbacks()
         m_scriptedAnimationController->resume();
 }
 
-void Document::windowScreenDidChange(PlatformDisplayID displayID)
+void Document::updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp)
 {
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    if (m_animationScheduler)
-        m_animationScheduler->windowScreenDidChange(displayID);
-#endif
+    if (m_timeline)
+        m_timeline->updateAnimationsAndSendEvents(timestamp);
+}
+
+void Document::serviceRequestAnimationFrameCallbacks(DOMHighResTimeStamp timestamp)
+{
+    if (m_scriptedAnimationController)
+        m_scriptedAnimationController->serviceRequestAnimationFrameCallbacks(timestamp);
+}
 
+void Document::windowScreenDidChange(PlatformDisplayID displayID)
+{
     if (RenderView* view = renderView()) {
         if (view->usesCompositing())
             view->compositor().windowScreenDidChange(displayID);
@@ -7929,8 +7925,6 @@ void Document::updateIntersectionObservations()
     if (needsLayout || hasPendingStyleRecalc())
         return;
 
-    m_needsForcedIntersectionObservationUpdate = false;
-
     for (const auto& observer : m_intersectionObservers) {
         bool needNotify = false;
         DOMHighResTimeStamp timestamp;
@@ -8007,17 +8001,6 @@ void Document::updateIntersectionObservations()
         m_intersectionObserversNotifyTimer.startOneShot(0_s);
 }
 
-void Document::scheduleForcedIntersectionObservationUpdate()
-{
-    ASSERT(!m_intersectionObservers.isEmpty());
-    if (m_needsForcedIntersectionObservationUpdate)
-        return;
-
-    m_needsForcedIntersectionObservationUpdate = true;
-    if (auto* page = this->page())
-        page->scheduleForcedIntersectionObservationUpdate(*this);
-}
-
 void Document::notifyIntersectionObserversTimerFired()
 {
     for (const auto& observer : m_intersectionObserversWithPendingNotifications) {
@@ -8451,16 +8434,6 @@ void Document::setConsoleMessageListener(RefPtr<StringCallback>&& listener)
     m_consoleMessageListener = listener;
 }
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-DocumentAnimationScheduler& Document::animationScheduler()
-{
-    if (!m_animationScheduler)
-        m_animationScheduler = DocumentAnimationScheduler::create(*this, page() ? page()->chrome().displayID() : 0);
-
-    return *m_animationScheduler;
-}
-#endif
-
 DocumentTimeline& Document::timeline()
 {
     if (!m_timeline)
index 778c213..d9dcef5 100644 (file)
@@ -107,7 +107,6 @@ class DOMWrapperWorld;
 class Database;
 class DatabaseThread;
 class DeferredPromise;
-class DocumentAnimationScheduler;
 class DocumentFragment;
 class DocumentLoader;
 class DocumentMarkerController;
@@ -1045,7 +1044,10 @@ public:
     ScriptedAnimationController* scriptedAnimationController() { return m_scriptedAnimationController.get(); }
     void suspendScriptedAnimationControllerCallbacks();
     void resumeScriptedAnimationControllerCallbacks();
-    
+
+    void updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp);
+    void serviceRequestAnimationFrameCallbacks(DOMHighResTimeStamp timestamp);
+
     void windowScreenDidChange(PlatformDisplayID);
 
     void finishedParsing();
@@ -1398,7 +1400,6 @@ public:
     void addIntersectionObserver(IntersectionObserver&);
     void removeIntersectionObserver(IntersectionObserver&);
     unsigned numberOfIntersectionObservers() const { return m_intersectionObservers.size(); }
-    void scheduleForcedIntersectionObservationUpdate();
     void updateIntersectionObservations();
 #endif
 
@@ -1471,10 +1472,6 @@ public:
 
     WEBCORE_EXPORT void setConsoleMessageListener(RefPtr<StringCallback>&&); // For testing.
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    DocumentAnimationScheduler& animationScheduler();
-#endif
-
     WEBCORE_EXPORT DocumentTimeline& timeline();
     DocumentTimeline* existingTimeline() const { return m_timeline.get(); }
     Vector<RefPtr<WebAnimation>> getAnimations();
@@ -2029,10 +2026,6 @@ private:
     bool m_isTelephoneNumberParsingAllowed { true };
 #endif
 
-#if ENABLE(INTERSECTION_OBSERVER)
-    bool m_needsForcedIntersectionObservationUpdate { false };
-#endif
-
 #if ENABLE(MEDIA_STREAM)
     HashSet<HTMLMediaElement*> m_mediaStreamStateChangeElements;
     String m_idHashSalt;
@@ -2052,9 +2045,6 @@ private:
 
     bool m_grantStorageAccessOverride { false };
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    RefPtr<DocumentAnimationScheduler> m_animationScheduler;
-#endif
     RefPtr<DocumentTimeline> m_timeline;
     DocumentIdentifier m_identifier;
 
index e88bb90..627060d 100644 (file)
@@ -30,7 +30,6 @@
 #include "ChromeClient.h"
 #include "DOMWindow.h"
 #include "Document.h"
-#include "DocumentAnimationScheduler.h"
 #include "DocumentLoader.h"
 #include "Frame.h"
 #include "FrameView.h"
@@ -189,7 +188,7 @@ void ScriptedAnimationController::cancelCallback(CallbackId id)
     }
 }
 
-void ScriptedAnimationController::serviceScriptedAnimations(double timestamp)
+void ScriptedAnimationController::serviceRequestAnimationFrameCallbacks(DOMHighResTimeStamp timestamp)
 {
     if (!m_callbacks.size() || m_suspendCount || !requestAnimationFrameEnabled())
         return;
@@ -197,8 +196,8 @@ void ScriptedAnimationController::serviceScriptedAnimations(double timestamp)
     TraceScope tracingScope(RAFCallbackStart, RAFCallbackEnd);
 
     // We round this to the nearest microsecond so that we can return a time that matches what is returned by document.timeline.currentTime.
-    double highResNowMs = std::round(1000 * timestamp);
-    double legacyHighResNowMs = 1000 * (timestamp + m_document->loader()->timing().referenceWallTime().secondsSinceEpoch().seconds());
+    DOMHighResTimeStamp highResNowMs = std::round(1000 * timestamp);
+    DOMHighResTimeStamp legacyHighResNowMs = 1000 * (timestamp + m_document->loader()->timing().referenceWallTime().secondsSinceEpoch().seconds());
 
     // First, generate a list of callbacks to consider.  Callbacks registered from this point
     // on are considered only for the "next" frame, not this one.
@@ -210,24 +209,21 @@ void ScriptedAnimationController::serviceScriptedAnimations(double timestamp)
     Ref<Document> protectedDocument(*m_document);
 
     for (auto& callback : callbacks) {
-        if (!callback->m_firedOrCancelled) {
-            callback->m_firedOrCancelled = true;
-            InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id);
-            if (callback->m_useLegacyTimeBase)
-                callback->handleEvent(legacyHighResNowMs);
-            else
-                callback->handleEvent(highResNowMs);
-            InspectorInstrumentation::didFireAnimationFrame(cookie);
-        }
+        if (callback->m_firedOrCancelled)
+            continue;
+        callback->m_firedOrCancelled = true;
+        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id);
+        if (callback->m_useLegacyTimeBase)
+            callback->handleEvent(legacyHighResNowMs);
+        else
+            callback->handleEvent(highResNowMs);
+        InspectorInstrumentation::didFireAnimationFrame(cookie);
     }
 
     // Remove any callbacks we fired from the list of pending callbacks.
-    for (size_t i = 0; i < m_callbacks.size();) {
-        if (m_callbacks[i]->m_firedOrCancelled)
-            m_callbacks.remove(i);
-        else
-            ++i;
-    }
+    m_callbacks.removeAllMatching([](auto& callback) {
+        return callback->m_firedOrCancelled;
+    });
 
     if (m_callbacks.size())
         scheduleAnimation();
@@ -262,8 +258,10 @@ void ScriptedAnimationController::scheduleAnimation()
 
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     if (!m_isUsingTimer && !isThrottled()) {
-        if (m_document->animationScheduler().scheduleScriptedAnimationResolution())
+        if (auto* page = this->page()) {
+            page->renderingUpdateScheduler().scheduleRenderingUpdate();
             return;
+        }
 
         m_isUsingTimer = true;
     }
@@ -292,15 +290,7 @@ void ScriptedAnimationController::scheduleAnimation()
 void ScriptedAnimationController::animationTimerFired()
 {
     m_lastAnimationFrameTimestamp = m_document->domWindow()->nowTimestamp();
-    serviceScriptedAnimations(m_lastAnimationFrameTimestamp);
+    serviceRequestAnimationFrameCallbacks(m_lastAnimationFrameTimestamp);
 }
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-void ScriptedAnimationController::documentAnimationSchedulerDidFire()
-{
-    // We obtain the time from the animation scheduler so that we use the same timestamp as the DocumentTimeline.
-    serviceScriptedAnimations(m_document->animationScheduler().lastTimestamp().seconds());
-}
-#endif
-
 }
index 7ab8ec1..3abe051 100644 (file)
@@ -52,7 +52,7 @@ public:
 
     CallbackId registerCallback(Ref<RequestAnimationFrameCallback>&&);
     void cancelCallback(CallbackId);
-    void serviceScriptedAnimations(double timestamp);
+    void serviceRequestAnimationFrameCallbacks(DOMHighResTimeStamp timestamp);
 
     void suspend();
     void resume();
@@ -69,10 +69,6 @@ public:
     WEBCORE_EXPORT bool isThrottled() const;
     WEBCORE_EXPORT Seconds interval() const;
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    void documentAnimationSchedulerDidFire();
-#endif
-
 private:
     ScriptedAnimationController(Document&);
 
index e18827f..d6ac1f3 100644 (file)
@@ -1962,21 +1962,6 @@ void FrameView::viewportContentsChanged()
         if (auto* renderView = frameView.frame().contentRenderer())
             renderView->updateVisibleViewportRect(visibleRect);
     });
-
-#if ENABLE(INTERSECTION_OBSERVER)
-    if (auto* document = frame().document()) {
-        if (auto* page = frame().page()) {
-            if (document->numberOfIntersectionObservers())
-                page->addDocumentNeedingIntersectionObservationUpdate(*document);
-            if (!frame().isMainFrame()) {
-                if (auto* mainDocument = frame().mainFrame().document()) {
-                    if (mainDocument->numberOfIntersectionObservers())
-                        page->addDocumentNeedingIntersectionObservationUpdate(*mainDocument);
-                }
-            }
-        }
-    }
-#endif
 }
 
 IntRect FrameView::unobscuredContentRectExpandedByContentInsets() const
index eb8afe2..fb16a54 100644 (file)
@@ -157,7 +157,6 @@ void IntersectionObserver::observe(Element& target)
     auto* document = trackingDocument();
     if (!hadObservationTargets)
         document->addIntersectionObserver(*this);
-    document->scheduleForcedIntersectionObservationUpdate();
 }
 
 void IntersectionObserver::unobserve(Element& target)
index 3fbdef2..59646ed 100644 (file)
@@ -250,9 +250,6 @@ Page::Page(PageConfiguration&& pageConfiguration)
     , m_storageNamespaceProvider(*WTFMove(pageConfiguration.storageNamespaceProvider))
     , m_userContentProvider(*WTFMove(pageConfiguration.userContentProvider))
     , m_visitedLinkStore(*WTFMove(pageConfiguration.visitedLinkStore))
-#if ENABLE(INTERSECTION_OBSERVER)
-    , m_intersectionObservationUpdateTimer(*this, &Page::updateIntersectionObservations)
-#endif
     , m_sessionID(PAL::SessionID::defaultSessionID())
 #if ENABLE(VIDEO)
     , m_playbackControlsManagerUpdateTimer(*this, &Page::playbackControlsManagerUpdateTimerFired)
@@ -1111,13 +1108,6 @@ void Page::didFinishLoad()
         m_performanceMonitor->didFinishLoad();
 }
 
-void Page::willDisplayPage()
-{
-#if ENABLE(INTERSECTION_OBSERVER)
-    updateIntersectionObservations();
-#endif
-}
-
 bool Page::isOnlyNonUtilityPage() const
 {
     return !isUtilityPage() && nonUtilityPageCount == 1;
@@ -1259,31 +1249,43 @@ void Page::removeActivityStateChangeObserver(ActivityStateChangeObserver& observ
     m_activityStateChangeObservers.remove(&observer);
 }
 
-#if ENABLE(INTERSECTION_OBSERVER)
-void Page::addDocumentNeedingIntersectionObservationUpdate(Document& document)
+void Page::layoutIfNeeded()
 {
-    if (m_documentsNeedingIntersectionObservationUpdate.find(&document) == notFound)
-        m_documentsNeedingIntersectionObservationUpdate.append(makeWeakPtr(document));
+    if (FrameView* view = m_mainFrame->view())
+        view->updateLayoutAndStyleIfNeededRecursive();
 }
 
-void Page::updateIntersectionObservations()
+void Page::renderingUpdate()
 {
-    m_intersectionObservationUpdateTimer.stop();
-    for (const auto& document : m_documentsNeedingIntersectionObservationUpdate) {
-        if (document)
-            document->updateIntersectionObservations();
+    // This function is not reentrant, e.g. a rAF callback may force repaint.
+    if (m_inRenderingUpdate) {
+        layoutIfNeeded();
+        return;
     }
-    m_documentsNeedingIntersectionObservationUpdate.clear();
-}
 
-void Page::scheduleForcedIntersectionObservationUpdate(Document& document)
-{
-    addDocumentNeedingIntersectionObservationUpdate(document);
-    if (m_intersectionObservationUpdateTimer.isActive())
-        return;
-    m_intersectionObservationUpdateTimer.startOneShot(0_s);
-}
+    SetForScope<bool> change(m_inRenderingUpdate, true);
+
+    Vector<RefPtr<Document>> documents;
+
+    // The requestAnimationFrame callbacks may change the frame hierarchy of the page
+    forEachDocument([&documents] (Document& document) {
+        documents.append(&document);
+    });
+
+    for (auto& document : documents) {
+        DOMHighResTimeStamp timestamp = document->domWindow()->nowTimestamp();
+        document->updateAnimationsAndSendEvents(timestamp);
+        document->serviceRequestAnimationFrameCallbacks(timestamp);
+    }
+
+    layoutIfNeeded();
+
+    for (auto& document : documents) {
+#if ENABLE(INTERSECTION_OBSERVER)
+        document->updateIntersectionObservations();
 #endif
+    }
+}
 
 void Page::suspendScriptedAnimations()
 {
@@ -2823,6 +2825,13 @@ void Page::didChangeMainDocument()
 #endif
 }
 
+RenderingUpdateScheduler& Page::renderingUpdateScheduler()
+{
+    if (!m_renderingUpdateScheduler)
+        m_renderingUpdateScheduler = RenderingUpdateScheduler::create(*this);
+    return *m_renderingUpdateScheduler;
+}
+
 void Page::forEachDocument(const Function<void(Document&)>& functor)
 {
     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
index 8617bd4..e8bc6c8 100644 (file)
@@ -33,6 +33,7 @@
 #include "RTCController.h"
 #include "Region.h"
 #include "RegistrableDomain.h"
+#include "RenderingUpdateScheduler.h"
 #include "ScrollTypes.h"
 #include "Supplementable.h"
 #include "Timer.h"
@@ -262,6 +263,8 @@ public:
 
     PerformanceMonitor* performanceMonitor() { return m_performanceMonitor.get(); }
 
+    RenderingUpdateScheduler& renderingUpdateScheduler();
+
     ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient.get(); }
     void updateValidationBubbleStateIfNeeded();
 
@@ -334,8 +337,6 @@ public:
     void didStartProvisionalLoad();
     void didFinishLoad(); // Called when the load has been committed in the main frame.
 
-    WEBCORE_EXPORT void willDisplayPage();
-
     // The view scale factor is multiplied into the page scale factor by all
     // callers of setPageScaleFactor.
     WEBCORE_EXPORT void setViewScaleFactor(float);
@@ -463,11 +464,8 @@ public:
     WEBCORE_EXPORT void addActivityStateChangeObserver(ActivityStateChangeObserver&);
     WEBCORE_EXPORT void removeActivityStateChangeObserver(ActivityStateChangeObserver&);
 
-#if ENABLE(INTERSECTION_OBSERVER)
-    void addDocumentNeedingIntersectionObservationUpdate(Document&);
-    void scheduleForcedIntersectionObservationUpdate(Document&);
-    void updateIntersectionObservations();
-#endif
+    WEBCORE_EXPORT void layoutIfNeeded();
+    WEBCORE_EXPORT void renderingUpdate();
 
     WEBCORE_EXPORT void suspendScriptedAnimations();
     WEBCORE_EXPORT void resumeScriptedAnimations();
@@ -862,6 +860,8 @@ private:
     int m_headerHeight { 0 };
     int m_footerHeight { 0 };
 
+    std::unique_ptr<RenderingUpdateScheduler> m_renderingUpdateScheduler;
+
     HashSet<RenderObject*> m_relevantUnpaintedRenderObjects;
     Region m_topRelevantPaintedRegion;
     Region m_bottomRelevantPaintedRegion;
@@ -902,14 +902,6 @@ private:
 
     HashSet<ActivityStateChangeObserver*> m_activityStateChangeObservers;
 
-#if ENABLE(INTERSECTION_OBSERVER)
-    Vector<WeakPtr<Document>> m_documentsNeedingIntersectionObservationUpdate;
-
-    // FIXME: Schedule intersection observation updates in a way that fits into the HTML
-    // EventLoop. See https://bugs.webkit.org/show_bug.cgi?id=160711.
-    Timer m_intersectionObservationUpdateTimer;
-#endif
-
 #if ENABLE(RESOURCE_USAGE)
     std::unique_ptr<ResourceUsageOverlay> m_resourceUsageOverlay;
 #endif
@@ -970,6 +962,7 @@ private:
     bool m_shouldEnableICECandidateFilteringByDefault { true };
     bool m_mediaPlaybackIsSuspended { false };
     bool m_mediaBufferingIsSuspended { false };
+    bool m_inRenderingUpdate { false };
 };
 
 inline PageGroup& Page::group()
index 580694c..c5bdb82 100644 (file)
@@ -318,7 +318,7 @@ void PageOverlayController::didChangeDeviceScaleFactor()
 
 void PageOverlayController::didChangeViewExposedRect()
 {
-    m_page.chrome().client().scheduleCompositingLayerFlush();
+    m_page.renderingUpdateScheduler().scheduleRenderingUpdate();
 }
 
 void PageOverlayController::didScrollFrame(Frame& frame)
@@ -412,7 +412,7 @@ float PageOverlayController::deviceScaleFactor() const
 
 void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*)
 {
-    m_page.chrome().client().scheduleCompositingLayerFlush();
+    m_page.renderingUpdateScheduler().scheduleRenderingUpdate();
 }
 
 void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay)
diff --git a/Source/WebCore/page/RenderingUpdateScheduler.cpp b/Source/WebCore/page/RenderingUpdateScheduler.cpp
new file mode 100644 (file)
index 0000000..dccc8c2
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderingUpdateScheduler.h"
+
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DisplayRefreshMonitorManager.h"
+#include "Page.h"
+#include <wtf/SystemTracing.h>
+
+namespace WebCore {
+
+RenderingUpdateScheduler::RenderingUpdateScheduler(Page& page)
+    : m_page(page)
+{
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    windowScreenDidChange(page.chrome().displayID());
+#endif
+}
+
+void RenderingUpdateScheduler::scheduleRenderingUpdate()
+{
+    if (isScheduled())
+        return;
+
+    tracePoint(ScheduleRenderingUpdate);
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    if (DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this))
+        m_scheduled = true;
+    else
+#endif
+        startTimer(Seconds(1.0 / 60));
+}
+
+bool RenderingUpdateScheduler::isScheduled() const
+{
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    if (m_scheduled)
+        return true;
+#endif
+    return m_refreshTimer.get();
+}
+    
+void RenderingUpdateScheduler::startTimer(Seconds delay)
+{
+    ASSERT(!isScheduled());
+    m_refreshTimer = std::make_unique<Timer>(*this, &RenderingUpdateScheduler::displayRefreshFired);
+    m_refreshTimer->startOneShot(delay);
+}
+
+void RenderingUpdateScheduler::clearScheduled()
+{
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    m_scheduled = false;
+#endif
+    m_refreshTimer = nullptr;
+}
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+void RenderingUpdateScheduler::windowScreenDidChange(PlatformDisplayID displayID)
+{
+    DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this);
+}
+
+RefPtr<DisplayRefreshMonitor> RenderingUpdateScheduler::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
+{
+    if (auto monitor = m_page.chrome().client().createDisplayRefreshMonitor(displayID))
+        return monitor;
+
+    return DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(displayID);
+}
+#endif
+
+void RenderingUpdateScheduler::displayRefreshFired()
+{
+    tracePoint(TriggerRenderingUpdate);
+
+    clearScheduled();
+    m_page.chrome().client().scheduleCompositingLayerFlush();
+}
+
+}
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #pragma once
 
-#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-
 #include "DisplayRefreshMonitorClient.h"
-#include "PlatformScreen.h"
-#include <wtf/Ref.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
 #include <wtf/Seconds.h>
 
 namespace WebCore {
 
-class Document;
+class Page;
+class Timer;
 
-class DocumentAnimationScheduler : public RefCounted<DocumentAnimationScheduler>
-    , public DisplayRefreshMonitorClient {
+class RenderingUpdateScheduler
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    : public DisplayRefreshMonitorClient
+#endif
+{
+    WTF_MAKE_FAST_ALLOCATED;
 public:
-    static Ref<DocumentAnimationScheduler> create(Document&, PlatformDisplayID);
-    ~DocumentAnimationScheduler();
-
-    void detachFromDocument();
-    void windowScreenDidChange(PlatformDisplayID);
+    static std::unique_ptr<RenderingUpdateScheduler> create(Page& page)
+    {
+        return std::make_unique<RenderingUpdateScheduler>(page);
+    }
 
-    bool scheduleWebAnimationsResolution();
-    void unscheduleWebAnimationsResolution();
-    bool scheduleScriptedAnimationResolution();
+    RenderingUpdateScheduler(Page&);
+    void scheduleRenderingUpdate();
 
-    Seconds lastTimestamp() { return m_lastTimestamp; }
-    bool isFiring() const { return m_isFiring; }
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    void windowScreenDidChange(PlatformDisplayID);
+#endif
 
 private:
-    DocumentAnimationScheduler(Document&, PlatformDisplayID);
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const final;
+    void displayRefreshFired() final;
+#else
+    void displayRefreshFired();
+#endif
 
-    RefPtr<Document> m_document;
-    bool m_scheduledWebAnimationsResolution { false };
-    bool m_scheduledScriptedAnimationResolution { false };
-    bool m_isFiring { false };
-    Seconds m_lastTimestamp { 0_s };
+    bool isScheduled() const;
+    void startTimer(Seconds);
+    void clearScheduled();
 
-    void displayRefreshFired() override;
-    RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
+    Page& m_page;
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    bool m_scheduled { false };
+#endif
+    std::unique_ptr<Timer> m_refreshTimer;
 };
 
-} // namespace WebCore
-
-#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+}
index 102aca4..565d407 100644 (file)
 
 #if PLATFORM(IOS_FAMILY)
 
+#include "Document.h"
+#include "RenderStyleConstants.h"
 #include "WKContentObservation.h"
+#include <wtf/HashSet.h>
+#include <wtf/Seconds.h>
 
 namespace WebCore {
 
 class DOMTimer;
-class Document;
+class Element;
 
 class ContentChangeObserver {
 public:
index c96bed1..93b2417 100644 (file)
@@ -121,7 +121,7 @@ void ServicesOverlayController::Highlight::notifyFlushRequired(const GraphicsLay
     if (!m_controller)
         return;
 
-    m_controller->page().chrome().client().scheduleCompositingLayerFlush();
+    m_controller->page().renderingUpdateScheduler().scheduleRenderingUpdate();
 }
 
 void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior)
index ad7da0c..6e14138 100644 (file)
@@ -431,7 +431,7 @@ void RenderLayerCompositor::notifyFlushRequired(const GraphicsLayer* layer)
 void RenderLayerCompositor::scheduleLayerFlushNow()
 {
     m_hasPendingLayerFlush = false;
-    page().chrome().client().scheduleCompositingLayerFlush();
+    page().renderingUpdateScheduler().scheduleRenderingUpdate();
 }
 
 void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle)
index 2772444..c5f628d 100644 (file)
@@ -1,3 +1,31 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        Replace the calls to Page::layoutIfNeeded() and willDisplayPage() by
+        a single call to Page::renderingUpdate(). This new function implements 
+        "Update the rendering" step of the HTML Event Loop specification
+        <https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering>.
+
+        * WebProcess/WebPage/AcceleratedDrawingArea.cpp:
+        (WebKit::AcceleratedDrawingArea::updateBackingStoreState):
+        * WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
+        (WebKit::LayerTreeHost::layerFlushTimerFired):
+        * WebProcess/WebPage/DrawingAreaImpl.cpp:
+        (WebKit::DrawingAreaImpl::display):
+        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:
+        (WebKit::RemoteLayerTreeDrawingArea::flushLayers):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::layoutIfNeeded):
+        (WebKit::WebPage::renderingUpdate):
+        (WebKit::WebPage::willDisplayPage): Deleted.
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
+        (WebKit::TiledCoreAnimationDrawingArea::flushLayers):
+
 2019-03-07  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Add a setting to be able to turn content change observation on/off
index c97e253..3544358 100644 (file)
@@ -381,10 +381,9 @@ void DrawingAreaCoordinatedGraphics::updateBackingStoreState(uint64_t stateID, b
 
         m_webPage.setDeviceScaleFactor(deviceScaleFactor);
         m_webPage.setSize(size);
-        m_webPage.layoutIfNeeded();
+        m_webPage.renderingUpdate();
         m_webPage.flushPendingEditorStateUpdate();
         m_webPage.scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset);
-        m_webPage.willDisplayPage();
 
         if (m_layerTreeHost)
             m_layerTreeHost->sizeDidChange(m_webPage.size());
@@ -703,7 +702,7 @@ void DrawingAreaCoordinatedGraphics::display(UpdateInfo& updateInfo)
     ASSERT(!m_layerTreeHost);
     ASSERT(!m_webPage.size().isEmpty());
 
-    m_webPage.layoutIfNeeded();
+    m_webPage.renderingUpdate();
     m_webPage.flushPendingEditorStateUpdate();
 
     // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
@@ -711,7 +710,6 @@ void DrawingAreaCoordinatedGraphics::display(UpdateInfo& updateInfo)
     if (m_layerTreeHost)
         return;
 
-    m_webPage.willDisplayPage();
     updateInfo.viewSize = m_webPage.size();
     updateInfo.deviceScaleFactor = m_webPage.corePage()->deviceScaleFactor();
 
index ad16b6c..afc98b0 100644 (file)
@@ -145,8 +145,8 @@ void LayerTreeHost::layerFlushTimerFired()
         return;
 
     m_coordinator.syncDisplayState();
+    m_webPage.renderingUpdate();
     m_webPage.flushPendingEditorStateUpdate();
-    m_webPage.willDisplayPage();
 
     if (!m_isValid || !m_coordinator.rootCompositingLayer())
         return;
index cb706be..d753d59 100644 (file)
@@ -349,8 +349,7 @@ void RemoteLayerTreeDrawingArea::flushLayers()
     RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
     backingStoreCollection.willFlushLayers();
 
-    m_webPage.layoutIfNeeded();
-    m_webPage.willDisplayPage();
+    m_webPage.renderingUpdate();
 
     FloatRect visibleRect(FloatPoint(), m_viewSize);
     if (m_scrolledViewExposedRect)
index d57d969..785aa42 100644 (file)
@@ -1554,12 +1554,6 @@ void WebPage::tryRestoreScrollPosition()
     m_page->mainFrame().loader().history().restoreScrollPositionAndViewState();
 }
 
-void WebPage::layoutIfNeeded()
-{
-    if (m_mainFrame->coreFrame()->view())
-        m_mainFrame->coreFrame()->view()->updateLayoutAndStyleIfNeededRecursive();
-}
-
 WebPage* WebPage::fromCorePage(Page* page)
 {
     return &static_cast<WebChromeClient&>(page->chrome().client()).page();
@@ -3581,9 +3575,14 @@ void WebPage::didFlushLayerTreeAtTime(MonotonicTime timestamp)
 }
 #endif
 
-void WebPage::willDisplayPage()
+void WebPage::layoutIfNeeded()
+{
+    m_page->layoutIfNeeded();
+}
+    
+void WebPage::renderingUpdate()
 {
-    m_page->willDisplayPage();
+    m_page->renderingUpdate();
 }
 
 WebInspector* WebPage::inspector(LazyCreationPolicy behavior)
index 1d010a8..28e5679 100644 (file)
@@ -301,7 +301,8 @@ public:
     void didFlushLayerTreeAtTime(MonotonicTime);
 #endif
 
-    void willDisplayPage();
+    void layoutIfNeeded();
+    void renderingUpdate();
 
     enum class LazyCreationPolicy { UseExistingOnly, CreateIfNeeded };
 
@@ -334,7 +335,6 @@ public:
     // -- Called by the DrawingArea.
     // FIXME: We could genericize these into a DrawingArea client interface. Would that be beneficial?
     void drawRect(WebCore::GraphicsContext&, const WebCore::IntRect&);
-    void layoutIfNeeded();
 
     // -- Called from WebCore clients.
     bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*);
index 751d4d7..d270d73 100644 (file)
@@ -59,6 +59,7 @@
 #import <pal/spi/cocoa/QuartzCoreSPI.h>
 #import <wtf/MachSendRight.h>
 #import <wtf/MainThread.h>
+#import <wtf/SystemTracing.h>
 
 #if ENABLE(ASYNC_SCROLLING)
 #import <WebCore/AsyncScrollingCoordinator.h>
@@ -459,12 +460,13 @@ void TiledCoreAnimationDrawingArea::flushLayers()
     if (layerTreeStateIsFrozen())
         return;
 
+    TraceScope traceScope(RenderingUpdateStart, RenderingUpdateEnd);
+
     @autoreleasepool {
         scaleViewToFitDocumentIfNeeded();
 
-        m_webPage.layoutIfNeeded();
+        m_webPage.renderingUpdate();
         m_webPage.flushPendingEditorStateUpdate();
-        m_webPage.willDisplayPage();
 
         updateIntrinsicContentSizeIfNeeded();
 
index 2798396..3961723 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        * WebView/WebView.mm:
+        (-[WebView _viewWillDrawInternal]):
+        Call Page::renderingUpdate() which implements  "Update the rendering"
+        step of the HTML Event Loop specification.
+
 2019-03-07  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Add a setting to be able to turn content change observation on/off
index f06f518..912b5b5 100644 (file)
@@ -1620,9 +1620,8 @@ static void WebKitInitializeGamepadProviderIfNecessary()
 
 - (void)_viewWillDrawInternal
 {
-    Frame* frame = [self _mainCoreFrame];
-    if (frame && frame->view())
-        frame->view()->updateLayoutAndStyleIfNeededRecursive();
+    if (_private->page)
+        _private->page->renderingUpdate();
 }
 
 + (NSArray *)_supportedMIMETypes
index 3f23ba1..1b5ab35 100644 (file)
@@ -1,3 +1,17 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        * WebView.cpp:
+        (WebView::updateBackingStore):
+        (WebView::flushPendingGraphicsLayerChangesSoon):
+        (WebView::flushPendingGraphicsLayerChanges):
+        Call Page::renderingUpdate() which implements  "Update the rendering"
+        step of the HTML Event Loop specification.
+
 2019-03-06  Ross Kirsling  <ross.kirsling@sony.com>
 
         [Win] Remove -DUCHAR_TYPE=wchar_t stopgap and learn to live with char16_t.
index b4d228f..6f7be12 100644 (file)
@@ -1173,9 +1173,7 @@ void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStore
 
     if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
         // Do a layout first so that everything we render to the backing store is always current.
-        if (Frame* coreFrame = core(m_mainFrame))
-            if (FrameView* view = coreFrame->view())
-                view->updateLayoutAndStyleIfNeededRecursive();
+        m_page->renderingUpdate();
 
         Vector<IntRect> paintRects;
         if (!backingStoreCompletelyDirty && m_backingStoreDirtyRegion) {
@@ -7159,8 +7157,10 @@ void WebView::setRootChildLayer(GraphicsLayer* layer)
 void WebView::flushPendingGraphicsLayerChangesSoon()
 {
 #if USE(CA)
-    if (!m_layerTreeHost)
+    if (!m_layerTreeHost) {
+        m_page->renderingUpdate();
         return;
+    }
     m_layerTreeHost->flushPendingGraphicsLayerChangesSoon();
 #elif USE(TEXTURE_MAPPER_GL)
     if (!m_acceleratedCompositingContext)
@@ -7388,7 +7388,7 @@ void WebView::flushPendingGraphicsLayerChanges()
     if (!isAcceleratedCompositing())
         return;
 
-    view->updateLayoutAndStyleIfNeededRecursive();
+    m_page->renderingUpdate();
 
     // Updating layout might have taken us out of compositing mode.
     if (m_backingLayer)
index 08dd184..ecbb41d 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-07  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestAnimationFrame should execute before the next frame
+        https://bugs.webkit.org/show_bug.cgi?id=177484
+
+        Reviewed by Simon Fraser.
+
+        Add trace points for the page RenderingUpdate.
+
+        * Tracing/SystemTracePoints.plist:
+
 2019-03-07  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Add a setting to be able to turn content change observation on/off
index 940140a..23d2cb2 100644 (file)
              </dict>
              <dict>
                  <key>Name</key>
+                 <string>Schedule rendering update</string>
+                 <key>Type</key>
+                 <string>Impulse</string>
+                 <key>Component</key>
+                 <string>47</string>
+                 <key>Code</key>
+                 <string>5028</string>
+             </dict>
+             <dict>
+                 <key>Name</key>
+                 <string>Trigger rendering update</string>
+                 <key>Type</key>
+                 <string>Impulse</string>
+                 <key>Component</key>
+                 <string>47</string>
+                 <key>Code</key>
+                 <string>5029</string>
+             </dict>
+             <dict>
+                 <key>Name</key>
+                 <string>Rendering update</string>
+                 <key>Type</key>
+                 <string>Interval</string>
+                 <key>Component</key>
+                 <string>47</string>
+                 <key>CodeBegin</key>
+                 <string>5030</string>
+                 <key>CodeEnd</key>
+                 <string>5031</string>
+             </dict>
+             <dict>
+                 <key>Name</key>
                  <string>Paint WebHTMLView</string>
                  <key>Type</key>
                  <string>Interval</string>