requestAnimationFrame should execute before the next frame
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Apr 2019 05:44:13 +0000 (05:44 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Apr 2019 05:44:13 +0000 (05:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177484

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

LayoutTests/imported/w3c:

Add trace points for the page RenderingUpdate.

* web-platform-tests/resize-observer/resources/resizeTestHelper.js:
Change ResizeTestHelper.TIMEOUT to be 1 second instead of 100 ms which
is too short for layout tests.

Source/WebCore:

This change fixes these 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, intersection observations and resize 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:
(WebCore::AXObjectCache::platformHandleFocusedUIElementChanged):
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::suspendAnimations):
(WebCore::DocumentTimeline::resumeAnimations):
(WebCore::DocumentTimeline::liveCurrentTime const):
(WebCore::DocumentTimeline::currentTime):
(WebCore::DocumentTimeline::cacheCurrentTime):
(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::scheduleRenderingUpdate):
(WebCore::Document::updateIntersectionObservations):
(WebCore::Document::addResizeObserver):
(WebCore::Document::updateResizeObservations):
(WebCore::Document::scheduleForcedIntersectionObservationUpdate): Deleted.
(WebCore::Document::scheduleResizeObservations): Deleted.
(WebCore::Document::animationScheduler): Deleted.
No need to schedule web-animations, intersection observations and resize
observations updates separately. All of them will be updated through the
"Update the rendering" step, i.e. Page::updateRendering().

* 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::didLayout):
(WebCore::FrameView::viewportContentsChanged):
* page/FrameViewLayoutContext.cpp:
(WebCore::FrameViewLayoutContext::layoutTimerFired):
* page/IntersectionObserver.cpp:
(WebCore::IntersectionObserver::observe):
* page/Page.cpp:
(WebCore::Page::Page):
(WebCore::Page::layoutIfNeeded):
(WebCore::Page::updateRendering):
(WebCore::Page::renderingUpdateScheduler):
(WebCore::Page::willDisplayPage): Deleted.
(WebCore::Page::addDocumentNeedingIntersectionObservationUpdate): Deleted.
(WebCore::Page::updateIntersectionObservations): Deleted.
(WebCore::Page::scheduleForcedIntersectionObservationUpdate): Deleted.
(WebCore::Page::hasResizeObservers const): Deleted.
(WebCore::Page::gatherDocumentsNeedingResizeObservationCheck): Deleted.
(WebCore::Page::checkResizeObservations): Deleted.
(WebCore::Page::scheduleResizeObservations): Deleted.
(WebCore::Page::notifyResizeObservers): Deleted.
* page/Page.h:
(WebCore::Page::setNeedsCheckResizeObservations): Deleted.
(WebCore::Page::needsCheckResizeObservations const): Deleted.
The IntersectionObserver and the ResizeObserver do not need to schedule
their own timers. The RenderingUpdateScheduler will schedule the "Update
the rendering" step in which these obverses will be served.

* page/PageOverlayController.cpp:
(WebCore::PageOverlayController::didChangeViewExposedRect):
(WebCore::PageOverlayController::notifyFlushRequired):
Force committing the layers to be 60 fps at maximum.

* page/RenderingUpdateScheduler.cpp: Added.
(WebCore::RenderingUpdateScheduler::RenderingUpdateScheduler):
(WebCore::RenderingUpdateScheduler::scheduleRenderingUpdate):
(WebCore::RenderingUpdateScheduler::isScheduled const):
(WebCore::RenderingUpdateScheduler::startTimer):
(WebCore::RenderingUpdateScheduler::clearScheduled):
(WebCore::RenderingUpdateScheduler::createDisplayRefreshMonitor const):
(WebCore::RenderingUpdateScheduler::windowScreenDidChange):
(WebCore::RenderingUpdateScheduler::displayRefreshFired):
(WebCore::RenderingUpdateScheduler::scheduleCompositingLayerFlush):
* page/RenderingUpdateScheduler.h: Added.
(WebCore::RenderingUpdateScheduler::create):
* page/ResizeObserver.cpp:
(WebCore::ResizeObserver::observe):
(WebCore::ResizeObserver::scheduleObservations): Deleted.
* page/ResizeObserver.h:
(WebCore::ResizeObserver::hasActiveObservations const):
* page/ios/ContentChangeObserver.h:
* page/mac/ServicesOverlayController.mm:
(WebCore::ServicesOverlayController::Highlight::notifyFlushRequired):
* page/scrolling/ScrollingStateTree.cpp:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
(WebCore::RenderLayerCompositor::layerTreeAsText):

Source/WebKit:

Replace the calls to Page::layoutIfNeeded() and willDisplayPage() by
a single call to Page::updateRendering(). 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/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp:
(WebKit::DrawingAreaCoordinatedGraphics::scheduleCompositingLayerFlush):
(WebKit::DrawingAreaCoordinatedGraphics::updateBackingStoreState):
(WebKit::DrawingAreaCoordinatedGraphics::display):
* WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
(WebKit::LayerTreeHost::layerFlushTimerFired):

* WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:
(WebKit::RemoteLayerTreeDrawingArea::flushLayers):
-- Call Page::updateRendering() to make sure that "Update the rendering"
   happens immediately before updating the page.

-- Move the call to RemoteLayerBackingStoreCollection::willFlushLayers()
   to be exactly before flushing the layers. This fixes the assertion
   ASSERT(m_inLayerFlush) which was firing when running a layout test.
   RemoteLayerTreeDrawingArea::flushLayers() now can call itself through
   TestRunner::notifyDone(). flushLayers() was calling willFlushLayers()
   twice before calling didFlushLayers().

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::layoutIfNeeded):
(WebKit::WebPage::updateRendering):
(WebKit::WebPage::willDisplayPage): Deleted.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::TiledCoreAnimationDrawingArea::flushLayers):

Source/WebKitLegacy/mac:

* WebView/WebView.mm:
(-[WebView _viewWillDrawInternal]):
(-[WebView _flushCompositingChanges]):
Call Page::updateRendering() 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::updateRendering() 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.

* accessibility/mac/selection-notification-focus-change-expected.txt:
* accessibility/mac/selection-notification-focus-change.html:
Remove the debug statements form notificationCallback() since the number
of times this function is called back and the order of notifications are
not defined. This test has been flaky and some trials were made to make
it more reliable. With this change it became flaky again.

* 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.

* animations/resources/animation-test-helpers.js:
(waitForAnimationToStart):
The expectation that animation will start at the beginning of the next
event loop is not true anymore. The animation will start at the time the
requestAnimationFrame fires.

* compositing/video/video-clip-change-src.html:
This test loads a video data and pushes it to the encoder. Originally it
used to wait 150 ms after receiving the second canplaythrough. I had to
change this timing to 250 ms.

* css3/filters/composited-during-animation.html:
Ditto. setTimeout({...}, 0) versus requestAnimationFrame.

* media/media-controls-accessibility.html:
Updating the accessibility button happens asynchronously, see
[WebAccessibilityObjectWrapper accessibilityPerformPressAction]. Due to
changing the page update timing, this test became flaky. Originally it used
to setTimeout({...}, 10) to ensure the stringValue of the mutate button
was changed after it was pressed. The fix is to loop using rAF till the
stringValue changes.

* platform/mac-wk2/accessibility/mac/selection-notification-focus-change-expected.txt: Removed.
The number of time notificationCallback() is called and the order of
notifications are not defined. And this is why we have two expected files:
one for WK1 and the other for WK2. Since the test is now simplified, we
can get rid of this duplication. We will test the minimum reliable thing
we can test.

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

54 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/accessibility/mac/selection-notification-focus-change-expected.txt
LayoutTests/accessibility/mac/selection-notification-focus-change.html
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
LayoutTests/animations/resources/animation-test-helpers.js
LayoutTests/compositing/video/video-clip-change-src.html
LayoutTests/css3/filters/composited-during-animation.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/resizeTestHelper.js
LayoutTests/media/media-controls-accessibility.html
LayoutTests/platform/mac-wk2/accessibility/mac/selection-notification-focus-change-expected.txt [deleted file]
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/FrameViewLayoutContext.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/ResizeObserver.cpp
Source/WebCore/page/ResizeObserver.h
Source/WebCore/page/ios/ContentChangeObserver.h
Source/WebCore/page/mac/ServicesOverlayController.mm
Source/WebCore/page/scrolling/ScrollingStateTree.cpp
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 f6e270d..81a74cc 100644 (file)
@@ -1,3 +1,60 @@
+2019-04-10  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. 
+
+        * accessibility/mac/selection-notification-focus-change-expected.txt:
+        * accessibility/mac/selection-notification-focus-change.html:
+        Remove the debug statements form notificationCallback() since the number
+        of times this function is called back and the order of notifications are
+        not defined. This test has been flaky and some trials were made to make 
+        it more reliable. With this change it became flaky again.
+
+        * 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.
+
+        * animations/resources/animation-test-helpers.js:
+        (waitForAnimationToStart):
+        The expectation that animation will start at the beginning of the next 
+        event loop is not true anymore. The animation will start at the time the
+        requestAnimationFrame fires.
+
+        * compositing/video/video-clip-change-src.html:
+        This test loads a video data and pushes it to the encoder. Originally it
+        used to wait 150 ms after receiving the second canplaythrough. I had to 
+        change this timing to 250 ms.
+
+        * css3/filters/composited-during-animation.html:
+        Ditto. setTimeout({...}, 0) versus requestAnimationFrame.
+
+        * media/media-controls-accessibility.html:
+        Updating the accessibility button happens asynchronously, see 
+        [WebAccessibilityObjectWrapper accessibilityPerformPressAction]. Due to
+        changing the page update timing, this test became flaky. Originally it used
+        to setTimeout({...}, 10) to ensure the stringValue of the mutate button
+        was changed after it was pressed. The fix is to loop using rAF till the
+        stringValue changes.
+
+        * platform/mac-wk2/accessibility/mac/selection-notification-focus-change-expected.txt: Removed.
+        The number of time notificationCallback() is called and the order of
+        notifications are not defined. And this is why we have two expected files:
+        one for WK1 and the other for WK2. Since the test is now simplified, we
+        can get rid of this duplication. We will test the minimum reliable thing
+        we can test.
+
 2019-04-10  Ryosuke Niwa  <rniwa@webkit.org>
 
         Nullptr crash in CompositeEditCommand::moveParagraphs when root editable element goes away
index 4def0a0..fc11adc 100644 (file)
@@ -3027,6 +3027,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 8c839e3..1079f2a 100644 (file)
@@ -1,26 +1,15 @@
-This tests that selection changes as a result of advancing focus include AXTextSelectionChangedFocus flag.
+This tests that selection changes as a result of advancing focus.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
 PASS webArea.addNotificationListener(notificationCallback) is true
 eventSender.keyDown(tabCharacter);
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
-Received AXFocusChanged
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
 
 PASS accessibilityController.accessibleElementById("1").isFocusable is true
 accessibilityController.accessibleElementById("1").takeFocus()
-Received AXFocusChanged
 
 eventSender.keyDown(tabCharacter)
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
-Received AXFocusChanged
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 3f373c9..508fbf4 100644 (file)
                     </div>
         </fieldset>
         <script>
-            description("This tests that selection changes as a result of advancing focus include AXTextSelectionChangedFocus flag.");
+            description("This tests that selection changes as a result of advancing focus.");
             jsTestIsAsync = true;
 
             var webArea = 0;
-            var axTextFocusChangeOne = 0;
-            var axTextFocusChangeTwo = 0;
-            var axTextFocusChangeThree = 0;
-            var axTextFocusChangeFour = 0;
             var tabCharacter = "\t";
 
             function notificationCallback(notification, userInfo) {
-                if (notification == "AXSelectedTextChanged") {
-                    debug("Received AXSelectedTextChanged");
-                    window.userInfo = userInfo;
-                    shouldBeTrue("userInfo[\"AXTextSelectionChangedFocus\"]");
-                } else if (notification == "AXFocusChanged")
-                    debug("Received AXFocusChanged");
+                if (notification == "AXSelectedTextChanged" || notification == "AXFocusChanged")
+                    window.promise.resolve();
             }
 
             function runTest() {
-                if (window.accessibilityController) {
-                    testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-
-                    accessibilityController.enableEnhancedAccessibility(true);
-                    webArea = accessibilityController.rootElement.childAtIndex(0);
-                    webArea.setBoolAttributeValue("AXCaretBrowsingEnabled", true)
-
-                    shouldBeTrue("webArea.addNotificationListener(notificationCallback)");
-                    evalAndLog("eventSender.keyDown(tabCharacter);");
-                    setTimeout(runTakeFocusTest, 0);
-                } else {
+                if (!window.accessibilityController) {
                     debug("window.accessibilityController is not present");
                     finishJSTest();
+                    return;
                 }
+
+                runFirstTabMoveTest();
+            }
+
+            function runFirstTabMoveTest() {
+                testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
+
+                accessibilityController.enableEnhancedAccessibility(true);
+                webArea = accessibilityController.rootElement.childAtIndex(0);
+                webArea.setBoolAttributeValue("AXCaretBrowsingEnabled", true)
+
+                shouldBeTrue("webArea.addNotificationListener(notificationCallback)");
+                evalAndLog("eventSender.keyDown(tabCharacter);");
+
+                window.promise = new Promise(function(resolve, reject) {
+                    setTimeout(() => {
+                        runTakeFocusTest();
+                    }, 0);
+                });
             }
 
             function runTakeFocusTest() {
                 debug('');
                 shouldBeTrue("accessibilityController.accessibleElementById(\"1\").isFocusable");
                 evalAndLog("accessibilityController.accessibleElementById(\"1\").takeFocus()");
-                setTimeout(runSecondTabMoveTest, 0);
+
+                window.promise = new Promise(function(resolve, reject) {
+                    setTimeout(() => {
+                        runSecondTabMoveTest();
+                    }, 0);
+                });
             }
 
             function runSecondTabMoveTest() {
                 debug('');
                 evalAndLog("eventSender.keyDown(tabCharacter)");
-                setTimeout(() => {
-                    webArea.removeNotificationListener();
-                    finishJSTest();
-                }, 0);
+
+                window.promise = new Promise(function(resolve, reject) {
+                    setTimeout(() => {
+                        webArea.removeNotificationListener();
+                        finishJSTest();
+                    }, 0);
+                });
             }
 
             </script>
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 ecfd93d..d2d15b4 100644 (file)
@@ -595,6 +595,6 @@ function runAnimationTest(expected, startCallback, event, disablePauseAnimationA
 function waitForAnimationToStart(element, callback)
 {
     element.addEventListener('webkitAnimationStart', function() {
-        window.setTimeout(callback, 0); // delay to give hardware animations a chance to start
+        requestAnimationFrame(callback); // delay to give hardware animations a chance to start
     }, false);
 }
index d021430..83794af 100644 (file)
@@ -37,7 +37,7 @@
 
     function endTest() {
         if (window.testRunner)
-            setTimeout(function() { testRunner.notifyDone(); }, 150);
+            setTimeout(function() { testRunner.notifyDone(); }, 250);
     }
     </script>
     <style>
index 3f462d0..92921fe 100644 (file)
         document.getElementById("preresult").innerHTML = preResult;
 
         // Completed the pre-animation tests. Now start the animation.
-        setTimeout(function () {
+        requestAnimationFrame(function () {
             document.body.className = "animating";
             runAnimationTest(expectedValues);
-        }, 0);
+        });
     }
 
     if (window.testRunner) {
index 9d1d4ca..0de1054 100644 (file)
@@ -1,3 +1,16 @@
+2019-04-10  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.
+
+        * web-platform-tests/resize-observer/resources/resizeTestHelper.js:
+        Change ResizeTestHelper.TIMEOUT to be 1 second instead of 100 ms which
+        is too short for layout tests.
+
 2019-04-09  Youenn Fablet  <youenn@apple.com>
 
         Refresh WPT service worker expectations
index 60c681b..02c7e92 100644 (file)
@@ -52,7 +52,7 @@ function ResizeTestHelper(name, steps)
     this._nextStepBind = this._nextStep.bind(this);
 }
 
-ResizeTestHelper.TIMEOUT = 100;
+ResizeTestHelper.TIMEOUT = 1000;
 
 ResizeTestHelper.prototype = {
   get _currentStep() {
index e8822a3..e8bee13 100644 (file)
@@ -32,17 +32,25 @@ if (window.accessibilityController) {
               
         // Mute button should be a checkbox with on/off state.
         muteButton = videoElement.childAtIndex(0).childAtIndex(9);
+        muteButtonStringValue = muteButton.stringValue;
         debug("muteButton.description: " + muteButton.description);
         debug("muteButton.role: " + muteButton.role);
-        debug("muteButton.stringValue: " + muteButton.stringValue);
+        debug("muteButton.stringValue: " + muteButtonStringValue);
         debug("press muteButton");
         muteButton.press();
-        setTimeout(function() {
+
+        function checkMuteButton() {
+            if (muteButtonStringValue == muteButton.stringValue) {
+                requestAnimationFrame(checkMuteButton);
+                return;
+            }
+
             debug("muteButton.stringValue: " + muteButton.stringValue + "\n");
-              
             // Left/Right arrow key should have 0.5 second step on timeline. 
             checkTimeLineValue(rightArrow);
-        }, 10);
+        }
+
+        requestAnimationFrame(checkMuteButton);
     }); 
     
     waitForEvent("seeked", function () {
diff --git a/LayoutTests/platform/mac-wk2/accessibility/mac/selection-notification-focus-change-expected.txt b/LayoutTests/platform/mac-wk2/accessibility/mac/selection-notification-focus-change-expected.txt
deleted file mode 100644 (file)
index 991575e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-This tests that selection changes as a result of advancing focus include AXTextSelectionChangedFocus flag.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS webArea.addNotificationListener(notificationCallback) is true
-eventSender.keyDown(tabCharacter);
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
-Received AXFocusChanged
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
-
-PASS accessibilityController.accessibleElementById("1").isFocusable is true
-accessibilityController.accessibleElementById("1").takeFocus()
-Received AXFocusChanged
-
-eventSender.keyDown(tabCharacter)
-Received AXSelectedTextChanged
-PASS userInfo["AXTextSelectionChangedFocus"] is true
-Received AXFocusChanged
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
- 1
- 2
index 152bd14..94365b5 100644 (file)
@@ -1,3 +1,14 @@
+2019-04-10  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-04-10  Claudio Saavedra  <csaavedra@igalia.com>
 
         Do not generate empty unified sources when unified builds are disabled
index ac9fda0..bcce0f9 100644 (file)
@@ -77,6 +77,11 @@ enum TracePointCode {
     ComputeEventRegionsStart,
     ComputeEventRegionsEnd,
 
+    ScheduleRenderingUpdate,
+    TriggerRenderingUpdate,
+    RenderingUpdateStart,
+    RenderingUpdateEnd,
+
     WebKitRange = 10000,
     WebHTMLViewPaintStart,
     WebHTMLViewPaintEnd,
index 3cefecd..a02ae9d 100644 (file)
@@ -1,3 +1,153 @@
+2019-04-10  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 these 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, intersection observations and resize 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:
+        (WebCore::AXObjectCache::platformHandleFocusedUIElementChanged):
+        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::suspendAnimations):
+        (WebCore::DocumentTimeline::resumeAnimations):
+        (WebCore::DocumentTimeline::liveCurrentTime const):
+        (WebCore::DocumentTimeline::currentTime):
+        (WebCore::DocumentTimeline::cacheCurrentTime):
+        (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::scheduleRenderingUpdate):
+        (WebCore::Document::updateIntersectionObservations):
+        (WebCore::Document::addResizeObserver):
+        (WebCore::Document::updateResizeObservations):
+        (WebCore::Document::scheduleForcedIntersectionObservationUpdate): Deleted.
+        (WebCore::Document::scheduleResizeObservations): Deleted.
+        (WebCore::Document::animationScheduler): Deleted.
+        No need to schedule web-animations, intersection observations and resize
+        observations updates separately. All of them will be updated through the
+        "Update the rendering" step, i.e. Page::updateRendering().        
+
+        * 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::didLayout):
+        (WebCore::FrameView::viewportContentsChanged):
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::FrameViewLayoutContext::layoutTimerFired):
+        * page/IntersectionObserver.cpp:
+        (WebCore::IntersectionObserver::observe):
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+        (WebCore::Page::layoutIfNeeded):
+        (WebCore::Page::updateRendering):
+        (WebCore::Page::renderingUpdateScheduler):
+        (WebCore::Page::willDisplayPage): Deleted.
+        (WebCore::Page::addDocumentNeedingIntersectionObservationUpdate): Deleted.
+        (WebCore::Page::updateIntersectionObservations): Deleted.
+        (WebCore::Page::scheduleForcedIntersectionObservationUpdate): Deleted.
+        (WebCore::Page::hasResizeObservers const): Deleted.
+        (WebCore::Page::gatherDocumentsNeedingResizeObservationCheck): Deleted.
+        (WebCore::Page::checkResizeObservations): Deleted.
+        (WebCore::Page::scheduleResizeObservations): Deleted.
+        (WebCore::Page::notifyResizeObservers): Deleted.
+        * page/Page.h:
+        (WebCore::Page::setNeedsCheckResizeObservations): Deleted.
+        (WebCore::Page::needsCheckResizeObservations const): Deleted.
+        The IntersectionObserver and the ResizeObserver do not need to schedule
+        their own timers. The RenderingUpdateScheduler will schedule the "Update
+        the rendering" step in which these obverses will be served.
+
+        * page/PageOverlayController.cpp:
+        (WebCore::PageOverlayController::didChangeViewExposedRect):
+        (WebCore::PageOverlayController::notifyFlushRequired):
+        Force committing the layers to be 60 fps at maximum.
+
+        * page/RenderingUpdateScheduler.cpp: Added.
+        (WebCore::RenderingUpdateScheduler::RenderingUpdateScheduler):
+        (WebCore::RenderingUpdateScheduler::scheduleRenderingUpdate):
+        (WebCore::RenderingUpdateScheduler::isScheduled const):
+        (WebCore::RenderingUpdateScheduler::startTimer):
+        (WebCore::RenderingUpdateScheduler::clearScheduled):
+        (WebCore::RenderingUpdateScheduler::createDisplayRefreshMonitor const):
+        (WebCore::RenderingUpdateScheduler::windowScreenDidChange):
+        (WebCore::RenderingUpdateScheduler::displayRefreshFired):
+        (WebCore::RenderingUpdateScheduler::scheduleCompositingLayerFlush):
+        * page/RenderingUpdateScheduler.h: Added.
+        (WebCore::RenderingUpdateScheduler::create):
+        * page/ResizeObserver.cpp:
+        (WebCore::ResizeObserver::observe):
+        (WebCore::ResizeObserver::scheduleObservations): Deleted.
+        * page/ResizeObserver.h:
+        (WebCore::ResizeObserver::hasActiveObservations const):
+        * page/ios/ContentChangeObserver.h:
+        * page/mac/ServicesOverlayController.mm:
+        (WebCore::ServicesOverlayController::Highlight::notifyFlushRequired):
+        * page/scrolling/ScrollingStateTree.cpp:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
+        (WebCore::RenderLayerCompositor::layerTreeAsText):
+
 2019-04-10  Ryosuke Niwa  <rniwa@webkit.org>
 
         Nullptr crash in CompositeEditCommand::moveParagraphs when root editable element goes away
index 219c8b7..23dd2a5 100644 (file)
@@ -426,7 +426,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
@@ -1532,6 +1531,7 @@ page/ProcessWarming.cpp
 page/Quirks.cpp
 page/RemoteDOMWindow.cpp
 page/RemoteFrame.cpp
+page/RenderingUpdateScheduler.cpp
 page/ResizeObservation.cpp
 page/ResizeObserver.cpp
 page/ResourceUsageOverlay.cpp
index 8a0927c..8f84328 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 */; };
                5553592322441C18008F5EC9 /* SVGDecoratedProperty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGDecoratedProperty.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 */,
                                58B2F9F22232D43F00938D63 /* ResizeObservation.cpp */,
                                58B2F9F32232D43F00938D63 /* ResizeObservation.h */,
                                58B2F9EF2232D43D00938D63 /* ResizeObserver.cpp */,
                                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 5d45e44..9ed909e 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 cd6dd0f..bbdd391 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()
@@ -273,36 +265,15 @@ Optional<Seconds> DocumentTimeline::currentTime()
         return WTF::nullopt;
     }
 
-    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.
@@ -325,16 +296,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)
@@ -347,44 +312,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.
@@ -447,8 +412,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)
@@ -472,7 +435,7 @@ void DocumentTimeline::scheduleNextTick()
 
     for (const auto& animation : m_animations) {
         if (!animation->isRunningAccelerated()) {
-            scheduleAnimationResolutionIfNeeded();
+            scheduleAnimationResolution();
             return;
         }
     }
@@ -482,7 +445,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);
@@ -592,18 +555,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()
@@ -624,30 +589,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 064eb94..abee743 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"
@@ -1941,11 +1940,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
@@ -2541,13 +2537,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();
@@ -6265,13 +6254,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);
@@ -7810,6 +7806,12 @@ void Document::removeAppearanceDependentPicture(HTMLPictureElement& picture)
     m_appearanceDependentPictures.remove(&picture);
 }
 
+void Document::scheduleRenderingUpdate()
+{
+    if (auto page = this->page())
+        page->renderingUpdateScheduler().scheduleRenderingUpdate();
+}
+
 #if ENABLE(INTERSECTION_OBSERVER)
 void Document::addIntersectionObserver(IntersectionObserver& observer)
 {
@@ -7941,8 +7943,6 @@ void Document::updateIntersectionObservations()
     if (needsLayout || hasPendingStyleRecalc())
         return;
 
-    m_needsForcedIntersectionObservationUpdate = false;
-
     for (const auto& observer : m_intersectionObservers) {
         bool needNotify = false;
         DOMHighResTimeStamp timestamp;
@@ -8019,17 +8019,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) {
@@ -8043,8 +8032,8 @@ void Document::notifyIntersectionObserversTimerFired()
 #if ENABLE(RESIZE_OBSERVER)
 void Document::addResizeObserver(ResizeObserver& observer)
 {
-    ASSERT(m_resizeObservers.find(&observer) == notFound);
-    m_resizeObservers.append(makeWeakPtr(&observer));
+    if (!m_resizeObservers.contains(&observer))
+        m_resizeObservers.append(makeWeakPtr(&observer));
 }
 
 void Document::removeResizeObserver(ResizeObserver& observer)
@@ -8093,11 +8082,31 @@ void Document::setHasSkippedResizeObservations(bool skipped)
         observer->setHasSkippedObservations(skipped);
 }
 
-void Document::scheduleResizeObservations()
+void Document::updateResizeObservations(Page& page)
 {
-    if (!page())
+    if (!hasResizeObservers())
         return;
-    page()->scheduleResizeObservations();
+
+    // We need layout the whole frame tree here. Because ResizeObserver could observe element in other frame,
+    // and it could change other frame in deliverResizeObservations().
+    page.layoutIfNeeded();
+
+    // Start check resize obervers;
+    for (size_t depth = gatherResizeObservations(0); depth != ResizeObserver::maxElementDepth(); depth = gatherResizeObservations(depth)) {
+        deliverResizeObservations();
+        page.layoutIfNeeded();
+    }
+
+    if (hasSkippedResizeObservations()) {
+        setHasSkippedResizeObservations(false);
+        String url;
+        unsigned line = 0;
+        unsigned column = 0;
+        getParserLocation(url, line, column);
+        reportException("ResizeObserver loop completed with undelivered notifications.", line, column, url, nullptr, nullptr);
+        // Starting a new schedule the next round of notify.
+        scheduleRenderingUpdate();
+    }
 }
 #endif
 
@@ -8524,16 +8533,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 722b07f..1c772aa 100644 (file)
@@ -108,7 +108,6 @@ class DOMWrapperWorld;
 class Database;
 class DatabaseThread;
 class DeferredPromise;
-class DocumentAnimationScheduler;
 class DocumentFragment;
 class DocumentLoader;
 class DocumentMarkerController;
@@ -1056,7 +1055,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();
@@ -1411,11 +1413,12 @@ public:
     void addAppearanceDependentPicture(HTMLPictureElement&);
     void removeAppearanceDependentPicture(HTMLPictureElement&);
 
+    void scheduleRenderingUpdate();
+
 #if ENABLE(INTERSECTION_OBSERVER)
     void addIntersectionObserver(IntersectionObserver&);
     void removeIntersectionObserver(IntersectionObserver&);
     unsigned numberOfIntersectionObservers() const { return m_intersectionObservers.size(); }
-    void scheduleForcedIntersectionObservationUpdate();
     void updateIntersectionObservations();
 #endif
 
@@ -1428,7 +1431,7 @@ public:
     void deliverResizeObservations();
     bool hasSkippedResizeObservations() const;
     void setHasSkippedResizeObservations(bool);
-    void scheduleResizeObservations();
+    void updateResizeObservations(Page&);
 #endif
 
 #if ENABLE(MEDIA_STREAM)
@@ -1500,10 +1503,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();
@@ -2071,10 +2070,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;
@@ -2094,9 +2089,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 180510c..8726f03 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,7 +196,7 @@ 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);
+    DOMHighResTimeStamp highResNowMs = std::round(1000 * timestamp);
 
     // First, generate a list of callbacks to consider.  Callbacks registered from this point
     // on are considered only for the "next" frame, not this one.
@@ -209,21 +208,18 @@ 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);
-            callback->handleEvent(highResNowMs);
-            InspectorInstrumentation::didFireAnimationFrame(cookie);
-        }
+        if (callback->m_firedOrCancelled)
+            continue;
+        callback->m_firedOrCancelled = true;
+        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id);
+        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();
@@ -258,8 +254,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;
     }
@@ -288,15 +286,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 f08556f..38e1fb7 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 1e0a34d..7e946a7 100644 (file)
@@ -1267,11 +1267,6 @@ void FrameView::willDoLayout(WeakPtr<RenderElement> layoutRoot)
 
 void FrameView::didLayout(WeakPtr<RenderElement> layoutRoot)
 {
-#if ENABLE(RESIZE_OBSERVER)
-    auto page = frame().page();
-    if (page && page->hasResizeObservers())
-        page->setNeedsCheckResizeObservations(true);
-#endif
     renderView()->releaseProtectedRenderWidgets();
     auto* layoutRootEnclosingLayer = layoutRoot->enclosingLayer();
     layoutRootEnclosingLayer->updateLayerPositionsAfterLayout(renderView()->layer(), updateLayerPositionFlags(layoutRootEnclosingLayer, !is<RenderView>(*layoutRoot), layoutContext().needsFullRepaint()));
@@ -1976,21 +1971,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::visualViewportRectExpandedByContentInsets() const
index 6df0f39..5901de0 100644 (file)
@@ -456,14 +456,6 @@ void FrameViewLayoutContext::layoutTimerFired()
         LOG(Layout, "FrameView %p layout timer fired at %.3fs", this, frame().document()->timeSinceDocumentCreation().value());
 #endif
     layout();
-
-#if ENABLE(RESIZE_OBSERVER)
-    // After this layout, it might not trigger display timer. E.g.: Running layout test for WK1.
-    // So scheduleResizeObservations() here to make sure ResizeObserver could be fired properly.
-    auto page = frame().page();
-    if (page && page->needsCheckResizeObservations())
-        page->scheduleResizeObservations();
-#endif
 }
 
 void FrameViewLayoutContext::convertSubtreeLayoutToFullLayout()
index 0664406..1836278 100644 (file)
@@ -158,7 +158,6 @@ void IntersectionObserver::observe(Element& target)
     auto* document = trackingDocument();
     if (!hadObservationTargets)
         document->addIntersectionObserver(*this);
-    document->scheduleForcedIntersectionObservationUpdate();
 }
 
 void IntersectionObserver::unobserve(Element& target)
index 0851367..30fe9e3 100644 (file)
 #include "WebGLStateTracker.h"
 #include "WheelEventDeltaFilter.h"
 #include "Widget.h"
-#if ENABLE(RESIZE_OBSERVER)
-#include <JavaScriptCore/ScriptCallStack.h>
-#endif
 #include <wtf/FileSystem.h>
 #include <wtf/RefCountedLeakCounter.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/SystemTracing.h>
 #include <wtf/text/Base64.h>
 #include <wtf/text/StringHash.h>
 
@@ -257,16 +255,10 @@ 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)
 #endif
-#if ENABLE(RESIZE_OBSERVER)
-    , m_resizeObserverTimer(*this, &Page::checkResizeObservations)
-#endif
     , m_isUtilityPage(isUtilityPageChromeClient(chrome().client()))
     , m_performanceMonitor(isUtilityPage() ? nullptr : std::make_unique<PerformanceMonitor>(*this))
     , m_lowPowerModeNotifier(std::make_unique<LowPowerModeNotifier>([this](bool isLowPowerModeEnabled) { handleLowModePowerChange(isLowPowerModeEnabled); }))
@@ -1121,17 +1113,6 @@ void Page::didFinishLoad()
         m_performanceMonitor->didFinishLoad();
 }
 
-void Page::willDisplayPage()
-{
-#if ENABLE(RESIZE_OBSERVER)
-    checkResizeObservations();
-#endif
-
-#if ENABLE(INTERSECTION_OBSERVER)
-    updateIntersectionObservations();
-#endif
-}
-
 bool Page::isOnlyNonUtilityPage() const
 {
     return !isUtilityPage() && nonUtilityPageCount == 1;
@@ -1273,105 +1254,50 @@ 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::updateRendering()
 {
-    m_intersectionObservationUpdateTimer.stop();
-    for (const auto& document : m_documentsNeedingIntersectionObservationUpdate) {
-        if (document)
-            document->updateIntersectionObservations();
-    }
-    m_documentsNeedingIntersectionObservationUpdate.clear();
-}
-
-void Page::scheduleForcedIntersectionObservationUpdate(Document& document)
-{
-    addDocumentNeedingIntersectionObservationUpdate(document);
-    if (m_intersectionObservationUpdateTimer.isActive())
+    // This function is not reentrant, e.g. a rAF callback may force repaint.
+    if (m_inUpdateRendering) {
+        layoutIfNeeded();
         return;
-    m_intersectionObservationUpdateTimer.startOneShot(0_s);
-}
-#endif
-
-#if ENABLE(RESIZE_OBSERVER)
-bool Page::hasResizeObservers() const
-{
-    for (const Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        auto doc = frame->document();
-        if (doc && doc->hasResizeObservers())
-            return true;
     }
-    return false;
-}
 
-void Page::gatherDocumentsNeedingResizeObservationCheck(Vector<WeakPtr<Document>>& documentsNeedingResizeObservationCheck)
-{
-    forEachDocument([&] (Document& document) {
-        if (document.hasResizeObservers())
-            documentsNeedingResizeObservationCheck.append(makeWeakPtr(document));
-    });
-}
+    TraceScope traceScope(RenderingUpdateStart, RenderingUpdateEnd);
 
-void Page::checkResizeObservations()
-{
-    if (!needsCheckResizeObservations())
-        return;
-    setNeedsCheckResizeObservations(false);
-    m_resizeObserverTimer.stop();
+    SetForScope<bool> change(m_inUpdateRendering, true);
 
-    Vector<WeakPtr<Document>> documentsNeedingResizeObservationCheck;
-    gatherDocumentsNeedingResizeObservationCheck(documentsNeedingResizeObservationCheck);
-    for (const auto& document : documentsNeedingResizeObservationCheck)
-        notifyResizeObservers(document);
-    documentsNeedingResizeObservationCheck.clear();
-}
+    Vector<RefPtr<Document>> documents;
 
-void Page::scheduleResizeObservations()
-{
-    setNeedsCheckResizeObservations(true);
-    if (m_resizeObserverTimer.isActive())
-        return;
-    m_resizeObserverTimer.startOneShot(0_s);
-}
+    // The requestAnimationFrame callbacks may change the frame hierarchy of the page
+    forEachDocument([&documents] (Document& document) {
+        documents.append(&document);
+    });
 
-void Page::notifyResizeObservers(WeakPtr<Document> document)
-{
-    if (!document)
-        return;
+    for (auto& document : documents) {
+        DOMHighResTimeStamp timestamp = document->domWindow()->nowTimestamp();
+        document->updateAnimationsAndSendEvents(timestamp);
+        document->serviceRequestAnimationFrameCallbacks(timestamp);
+    }
 
-    // We need layout the whole frame tree here. Because ResizeObserver could observe element in other frame,
-    // and it could change other frame in deliverResizeObservations().
-    if (mainFrame().view())
-        mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
+    layoutIfNeeded();
 
-    // Start check resize obervers;
-    for (size_t depth = document->gatherResizeObservations(0); depth != ResizeObserver::maxElementDepth(); depth = document->gatherResizeObservations(depth)) {
-        document->deliverResizeObservations();
-        if (!document)
-            return;
-        if (mainFrame().view())
-            mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
-    }
+#if ENABLE(INTERSECTION_OBSERVER)
+    for (auto& document : documents)
+        document->updateIntersectionObservations();
+#endif
+#if ENABLE(RESIZE_OBSERVER)
+    for (auto& document : documents)
+        document->updateResizeObservations(*this);
+#endif
 
-    if (document->hasSkippedResizeObservations()) {
-        document->setHasSkippedResizeObservations(false);
-        String url;
-        unsigned line = 0;
-        unsigned column = 0;
-        document->getParserLocation(url, line, column);
-        document->reportException("ResizeObserver loop completed with undelivered notifications.", line, column, url, nullptr, nullptr);
-        // TODO: We are starting a timer to schedule the next round of notify.
-        // However, this should be in synchrony with the next requestAnimationFrame.
-        scheduleResizeObservations();
-    }
+    layoutIfNeeded();
 }
-#endif
 
 void Page::suspendScriptedAnimations()
 {
@@ -2911,6 +2837,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 7ef211d..dcd1f2d 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"
@@ -264,6 +265,8 @@ public:
 
     PerformanceMonitor* performanceMonitor() { return m_performanceMonitor.get(); }
 
+    RenderingUpdateScheduler& renderingUpdateScheduler();
+
     ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient.get(); }
     void updateValidationBubbleStateIfNeeded();
 
@@ -339,8 +342,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);
@@ -468,22 +469,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
-
-#if ENABLE(RESIZE_OBSERVER)
-    WEBCORE_EXPORT void checkResizeObservations();
-    bool hasResizeObservers() const;
-    void gatherDocumentsNeedingResizeObservationCheck(Vector<WeakPtr<Document>>&);
-    void scheduleResizeObservations();
-    void notifyResizeObservers(WeakPtr<Document>);
-    void setNeedsCheckResizeObservations(bool check) { m_needsCheckResizeObservations = check; }
-    bool needsCheckResizeObservations() const { return m_needsCheckResizeObservations; }
-
-#endif
+    WEBCORE_EXPORT void layoutIfNeeded();
+    WEBCORE_EXPORT void updateRendering();
 
     WEBCORE_EXPORT void suspendScriptedAnimations();
     WEBCORE_EXPORT void resumeScriptedAnimations();
@@ -888,6 +875,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;
@@ -928,14 +917,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
@@ -951,11 +932,6 @@ private:
     Timer m_playbackControlsManagerUpdateTimer;
 #endif
 
-#if ENABLE(RESIZE_OBSERVER)
-    Timer m_resizeObserverTimer;
-    bool m_needsCheckResizeObservations { false };
-#endif
-
     bool m_allowsMediaDocumentInlinePlayback { false };
     bool m_allowsPlaybackControlsForAutoplayingAudio { false };
     bool m_showAllPlugins { false };
@@ -1001,6 +977,7 @@ private:
     bool m_shouldEnableICECandidateFilteringByDefault { true };
     bool m_mediaPlaybackIsSuspended { false };
     bool m_mediaBufferingIsSuspended { false };
+    bool m_inUpdateRendering { 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..610176d
--- /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))
+#endif
+        startTimer(Seconds(1.0 / 60));
+
+    m_scheduled = true;
+}
+
+bool RenderingUpdateScheduler::isScheduled() const
+{
+    ASSERT_IMPLIES(m_refreshTimer.get(), m_scheduled);
+    return m_scheduled;
+}
+    
+void RenderingUpdateScheduler::startTimer(Seconds delay)
+{
+    ASSERT(!isScheduled());
+    m_refreshTimer = std::make_unique<Timer>(*this, &RenderingUpdateScheduler::displayRefreshFired);
+    m_refreshTimer->startOneShot(delay);
+}
+
+void RenderingUpdateScheduler::clearScheduled()
+{
+    m_scheduled = false;
+    m_refreshTimer = nullptr;
+}
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+RefPtr<DisplayRefreshMonitor> RenderingUpdateScheduler::createDisplayRefreshMonitor(PlatformDisplayID displayID) const
+{
+    if (auto monitor = m_page.chrome().client().createDisplayRefreshMonitor(displayID))
+        return monitor;
+
+    return DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(displayID);
+}
+
+void RenderingUpdateScheduler::windowScreenDidChange(PlatformDisplayID displayID)
+{
+    DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this);
+}
+#endif
+
+void RenderingUpdateScheduler::displayRefreshFired()
+{
+    tracePoint(TriggerRenderingUpdate);
+
+    clearScheduled();
+    scheduleCompositingLayerFlush();
+}
+
+void RenderingUpdateScheduler::scheduleCompositingLayerFlush()
+{
+    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();
-
-    Seconds lastTimestamp() { return m_lastTimestamp; }
-    bool isFiring() const { return m_isFiring; }
+    RenderingUpdateScheduler(Page&);
+    void scheduleRenderingUpdate();
+    void scheduleCompositingLayerFlush();
 
 private:
-    DocumentAnimationScheduler(Document&, PlatformDisplayID);
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const final;
+    void windowScreenDidChange(PlatformDisplayID);
+    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;
+    bool m_scheduled { false };
+    std::unique_ptr<Timer> m_refreshTimer;
 };
 
-} // namespace WebCore
-
-#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+}
index c3513b7..9ff2b6e 100644 (file)
@@ -53,29 +53,27 @@ ResizeObserver::~ResizeObserver()
         m_document->removeResizeObserver(*this);
 }
 
-void ResizeObserver::scheduleObservations()
-{
-    if (m_document)
-        m_document->scheduleResizeObservations();
-}
-
 void ResizeObserver::observe(Element& target)
 {
     if (!m_callback)
         return;
 
-    for (auto& observation : m_observations) {
-        if (observation->target() == &target)
-            return;
-    }
+    auto position = m_observations.findMatching([&](auto& observation) {
+        return observation->target() == &target;
+    });
+
+    if (position != notFound)
+        return;
 
     auto& observerData = target.ensureResizeObserverData();
     observerData.observers.append(makeWeakPtr(this));
-    if (m_document && !hasObservations())
-        m_document->addResizeObserver(*this);
+
     m_observations.append(ResizeObservation::create(&target));
 
-    scheduleObservations();
+    if (m_document) {
+        m_document->addResizeObserver(*this);
+        m_document->scheduleRenderingUpdate();
+    }
 }
 
 void ResizeObserver::unobserve(Element& target)
index dad1401..a181960 100644 (file)
@@ -50,7 +50,6 @@ public:
 
     bool hasObservations() const { return m_observations.size(); }
     bool hasActiveObservations() const { return m_activeObservations.size(); }
-    void scheduleObservations();
 
     void observe(Element&);
     void unobserve(Element&);
index 39d4dec..7e11fe7 100644 (file)
 #if PLATFORM(IOS_FAMILY)
 
 #include "CSSPropertyNames.h"
+#include "Document.h"
 #include "PlatformEvent.h"
+#include "RenderStyleConstants.h"
 #include "Timer.h"
 #include "WKContentObservation.h"
 #include <wtf/HashSet.h>
+#include <wtf/Seconds.h>
 
 namespace WebCore {
 
 class Animation;
 class DOMTimer;
-class Document;
 class Element;
 
 class ContentChangeObserver {
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 b55da04..c5d70bd 100644 (file)
@@ -34,6 +34,7 @@
 #include "ScrollingStateFrameHostingNode.h"
 #include "ScrollingStateFrameScrollingNode.h"
 #include "ScrollingStateOverflowScrollingNode.h"
+#include "ScrollingStatePositionedNode.h"
 #include "ScrollingStateStickyNode.h"
 #include <wtf/text/CString.h>
 #include <wtf/text/TextStream.h>
index 765e9d7..1c2bb90 100644 (file)
@@ -450,7 +450,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)
@@ -1923,6 +1923,7 @@ String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags)
         return String();
 
     flushPendingLayerChanges(true);
+    page().renderingUpdateScheduler().scheduleCompositingLayerFlush();
 
     LayerTreeAsTextBehavior layerTreeBehavior = LayerTreeAsTextBehaviorNormal;
     if (flags & LayerTreeFlagsIncludeDebugInfo)
index 63b7116..f0bba19 100644 (file)
@@ -1,3 +1,42 @@
+2019-04-10  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::updateRendering(). 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/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp:
+        (WebKit::DrawingAreaCoordinatedGraphics::scheduleCompositingLayerFlush):
+        (WebKit::DrawingAreaCoordinatedGraphics::updateBackingStoreState):
+        (WebKit::DrawingAreaCoordinatedGraphics::display):
+        * WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
+        (WebKit::LayerTreeHost::layerFlushTimerFired):
+
+        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:
+        (WebKit::RemoteLayerTreeDrawingArea::flushLayers):
+        -- Call Page::updateRendering() to make sure that "Update the rendering"
+           happens immediately before updating the page.
+
+        -- Move the call to RemoteLayerBackingStoreCollection::willFlushLayers()
+           to be exactly before flushing the layers. This fixes the assertion
+           ASSERT(m_inLayerFlush) which was firing when running a layout test.
+           RemoteLayerTreeDrawingArea::flushLayers() now can call itself through
+           TestRunner::notifyDone(). flushLayers() was calling willFlushLayers()
+           twice before calling didFlushLayers().
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::layoutIfNeeded):
+        (WebKit::WebPage::updateRendering):
+        (WebKit::WebPage::willDisplayPage): Deleted.
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
+        (WebKit::TiledCoreAnimationDrawingArea::flushLayers):
+
 2019-04-10  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: save sheet should be anchored underneath the tab bar when detached
index 28b83c2..90f74f2 100644 (file)
@@ -303,6 +303,8 @@ void DrawingAreaCoordinatedGraphics::scheduleCompositingLayerFlush()
 {
     if (m_layerTreeHost)
         m_layerTreeHost->scheduleLayerFlush();
+    else
+        setNeedsDisplay();
 }
 
 void DrawingAreaCoordinatedGraphics::layerHostDidFlushLayers()
@@ -381,10 +383,9 @@ void DrawingAreaCoordinatedGraphics::updateBackingStoreState(uint64_t stateID, b
 
         m_webPage.setDeviceScaleFactor(deviceScaleFactor);
         m_webPage.setSize(size);
-        m_webPage.layoutIfNeeded();
+        m_webPage.updateRendering();
         m_webPage.flushPendingEditorStateUpdate();
         m_webPage.scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset);
-        m_webPage.willDisplayPage();
 
         if (m_layerTreeHost)
             m_layerTreeHost->sizeDidChange(m_webPage.size());
@@ -706,7 +707,7 @@ void DrawingAreaCoordinatedGraphics::display(UpdateInfo& updateInfo)
     ASSERT(!m_layerTreeHost);
     ASSERT(!m_webPage.size().isEmpty());
 
-    m_webPage.layoutIfNeeded();
+    m_webPage.updateRendering();
     m_webPage.flushPendingEditorStateUpdate();
 
     // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is
@@ -714,7 +715,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 76b0770..2cb82f7 100644 (file)
@@ -145,8 +145,8 @@ void LayerTreeHost::layerFlushTimerFired()
         return;
 
     m_coordinator.syncDisplayState();
+    m_webPage.updateRendering();
     m_webPage.flushPendingEditorStateUpdate();
-    m_webPage.willDisplayPage();
 
     if (!m_isValid || !m_coordinator.rootCompositingLayer())
         return;
index cb706be..06277e3 100644 (file)
@@ -344,13 +344,7 @@ void RemoteLayerTreeDrawingArea::flushLayers()
             scheduleCompositingLayerFlush();
     }
 
-    RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
-
-    RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
-    backingStoreCollection.willFlushLayers();
-
-    m_webPage.layoutIfNeeded();
-    m_webPage.willDisplayPage();
+    m_webPage.updateRendering();
 
     FloatRect visibleRect(FloatPoint(), m_viewSize);
     if (m_scrolledViewExposedRect)
@@ -373,6 +367,11 @@ void RemoteLayerTreeDrawingArea::flushLayers()
     if (m_viewOverlayRootLayer)
         m_viewOverlayRootLayer->flushCompositingState(visibleRect);
 
+    RELEASE_ASSERT(!m_pendingBackingStoreFlusher || m_pendingBackingStoreFlusher->hasFlushed());
+
+    RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection();
+    backingStoreCollection.willFlushLayers();
+
     m_rootLayer->flushCompositingStateForThisLayerOnly();
 
     // FIXME: Minimize these transactions if nothing changed.
index a96cbad..e8ec7d4 100644 (file)
@@ -1611,12 +1611,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();
@@ -3652,9 +3646,14 @@ void WebPage::didFlushLayerTreeAtTime(MonotonicTime timestamp)
 }
 #endif
 
-void WebPage::willDisplayPage()
+void WebPage::layoutIfNeeded()
+{
+    m_page->layoutIfNeeded();
+}
+    
+void WebPage::updateRendering()
 {
-    m_page->willDisplayPage();
+    m_page->updateRendering();
 }
 
 WebInspector* WebPage::inspector(LazyCreationPolicy behavior)
index 12c1f20..aee7748 100644 (file)
@@ -306,7 +306,8 @@ public:
     void didFlushLayerTreeAtTime(MonotonicTime);
 #endif
 
-    void willDisplayPage();
+    void layoutIfNeeded();
+    void updateRendering();
 
     enum class LazyCreationPolicy { UseExistingOnly, CreateIfNeeded };
 
@@ -339,7 +340,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 a0bc5b0..a4b9fa5 100644 (file)
@@ -459,9 +459,8 @@ void TiledCoreAnimationDrawingArea::flushLayers(FlushType flushType)
     @autoreleasepool {
         scaleViewToFitDocumentIfNeeded();
 
-        m_webPage.layoutIfNeeded();
+        m_webPage.updateRendering();
         m_webPage.flushPendingEditorStateUpdate();
-        m_webPage.willDisplayPage();
 
         updateIntrinsicContentSizeIfNeeded();
 
index 4d11348..70758a3 100644 (file)
@@ -1,3 +1,16 @@
+2019-04-10  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]):
+        (-[WebView _flushCompositingChanges]):
+        Call Page::updateRendering() which implements "Update the rendering"
+        step of the HTML Event Loop specification.
+
 2019-04-10  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: save sheet should be anchored underneath the tab bar when detached
index 98c3176..8137188 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->updateRendering();
 }
 
 + (NSArray *)_supportedMIMETypes
@@ -9388,11 +9387,6 @@ bool LayerFlushController::flushLayers()
 
 - (BOOL)_flushCompositingChanges
 {
-#if ENABLE(RESIZE_OBSERVER)
-    if (_private->page)
-        _private->page->checkResizeObservations();
-#endif
-
     Frame* frame = [self _mainCoreFrame];
     if (frame && frame->view())
         return frame->view()->flushCompositingStateIncludingSubframes();
index 1265a6e..0248251 100644 (file)
@@ -1,3 +1,17 @@
+2019-04-10  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::updateRendering() which implements "Update the rendering"
+        step of the HTML Event Loop specification.
+
 2019-04-10  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: save sheet should be anchored underneath the tab bar when detached
index 631253a..2ac1483 100644 (file)
@@ -1171,9 +1171,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->updateRendering();
 
         Vector<IntRect> paintRects;
         if (!backingStoreCompletelyDirty && m_backingStoreDirtyRegion) {
@@ -7160,8 +7158,10 @@ void WebView::setRootChildLayer(GraphicsLayer* layer)
 void WebView::flushPendingGraphicsLayerChangesSoon()
 {
 #if USE(CA)
-    if (!m_layerTreeHost)
+    if (!m_layerTreeHost) {
+        m_page->updateRendering();
         return;
+    }
     m_layerTreeHost->flushPendingGraphicsLayerChangesSoon();
 #elif USE(TEXTURE_MAPPER_GL)
     if (!m_acceleratedCompositingContext)
@@ -7389,7 +7389,7 @@ void WebView::flushPendingGraphicsLayerChanges()
     if (!isAcceleratedCompositing())
         return;
 
-    view->updateLayoutAndStyleIfNeededRecursive();
+    m_page->updateRendering();
 
     // Updating layout might have taken us out of compositing mode.
     if (m_backingLayer)
index 76a566d..f4881bc 100644 (file)
@@ -1,3 +1,14 @@
+2019-04-10  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-04-10  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [Win] Use a bundled vswhere.exe instead of downloading by update-vswhere.py
index 940140a..c140e91 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>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>