Changeset 253299 in webkit


Ignore:
Timestamp:
Dec 9, 2019 1:12:17 PM (4 years ago)
Author:
commit-queue@webkit.org
Message:

Throttling requestAnimationFrame should be controlled by RenderingUpdateScheduler
https://bugs.webkit.org/show_bug.cgi?id=204713

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

Source/WebCore:

Test: fast/animation/request-animation-frame-throttling-outside-viewport.html

requestAnimationFrame is throttled by a timer although its callback are
serviced by the page RenderingUpdate. This led to excessive rAF firing
which makes it more than the preferred frame per seconds.

The solution is to have two throttling types:

1) Page throttling (or full throttling) which slows down all the steps of

RenderingUpdate for the main document and all the sub-documents.

2) Document throttling (or partial throttling) which only slows down the

rAF of a certain document.

  • Headers.cmake:
  • WebCore.xcodeproj/project.pbxproj:
  • animation/DocumentTimeline.cpp:

(WebCore::DocumentTimeline::animationInterval const):
(WebCore::DocumentTimeline::updateThrottlingState): Deleted.

  • animation/DocumentTimeline.h:

There is no need to have DocumentTimeline throttling. It is throttled
when the page RenderingUpdate is throttled.

  • dom/Document.cpp:

(WebCore::Document::requestAnimationFrame):
(WebCore::Document::updateLastHandledUserGestureTimestamp):
LowPowerMode throttling is now handled by the page. So remove its handling
in the Document side.

  • dom/ScriptedAnimationController.cpp:

(WebCore::ScriptedAnimationController::ScriptedAnimationController):
(WebCore::ScriptedAnimationController::page const):
(WebCore::ScriptedAnimationController::interval const):
(WebCore::ScriptedAnimationController::isThrottled const):
(WebCore::ScriptedAnimationController::registerCallback):
(WebCore::ScriptedAnimationController::cancelCallback):
(WebCore::ScriptedAnimationController::serviceRequestAnimationFrameCallbacks):
(WebCore::ScriptedAnimationController::scheduleAnimation):
(WebCore::throttlingReasonToString): Deleted.
(WebCore::throttlingReasonsToString): Deleted.
(WebCore::ScriptedAnimationController::addThrottlingReason): Deleted.
(WebCore::ScriptedAnimationController::removeThrottlingReason): Deleted.
(WebCore::ScriptedAnimationController::animationTimerFired): Deleted.

  • dom/ScriptedAnimationController.h:

(WebCore::ScriptedAnimationController::addThrottlingReason):
(WebCore::ScriptedAnimationController::removeThrottlingReason):
Get rid of the rAF throttling timer. Service the rAF callback only when
the period from the current time stamp till the last service time stamp
is greater than the preferred rAF interval .

  • page/FrameView.cpp:

(WebCore::FrameView::updateScriptedAnimationsAndTimersThrottlingState):
ThrottlingReason is now defined outside ScriptedAnimationController.

  • page/Page.cpp:

(WebCore::Page::suspendScriptedAnimations):
(WebCore::Page::resumeScriptedAnimations):
Use forEachDocument().

(WebCore::Page::preferredRenderingUpdateInterval const):
Calculate the preferred RenderingUpdate interval from the throttling
reasons.

(WebCore::Page::setIsVisuallyIdleInternal):
(WebCore::Page::handleLowModePowerChange):
Call adjustRenderingUpdateFrequency() when isLowPowerModeEnabled or
IsVisuallyIdle is toggled.

(WebCore::updateScriptedAnimationsThrottlingReason): Deleted.

  • page/Page.h:

(WebCore::Page::isRenderingUpdateThrottled const):

  • page/RenderingUpdateScheduler.cpp:

(WebCore::RenderingUpdateScheduler::adjustFramesPerSecond):
(WebCore::RenderingUpdateScheduler::adjustRenderingUpdateFrequency):
Change the preferredFramesPerSecond of the DisplayRefreshMonitor if the
throttling is not aggressive e.g. 10_s. Otherwise use the timer.

(WebCore::RenderingUpdateScheduler::scheduleTimedRenderingUpdate):
Call adjustFramesPerSecond() when DisplayRefreshMonitor is created.

(WebCore::RenderingUpdateScheduler::startTimer):

  • page/RenderingUpdateScheduler.h:
  • platform/graphics/AnimationFrameRate.h: Added.

(WebCore::preferredFrameInterval):
(WebCore::preferredFramesPerSecond):

  • platform/graphics/DisplayRefreshMonitor.h:

(WebCore::DisplayRefreshMonitor::setPreferredFramesPerSecond):

  • platform/graphics/DisplayRefreshMonitorManager.cpp:

(WebCore::DisplayRefreshMonitorManager::monitorForClient):
Rename createMonitorForClient() to monitorForClient() since it may return
a cached DisplayRefreshMonitor.

(WebCore::DisplayRefreshMonitorManager::setPreferredFramesPerSecond):
(WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
(WebCore::DisplayRefreshMonitorManager::displayDidRefresh):
No need to call registerClient(). This function was just ensuring the
DisplayRefreshMonitor is created. scheduleAnimation() does the same thing.

(WebCore::DisplayRefreshMonitorManager::createMonitorForClient): Deleted.
(WebCore::DisplayRefreshMonitorManager::registerClient): Deleted.

  • platform/graphics/DisplayRefreshMonitorManager.h:

(WebCore::DisplayRefreshMonitorManager::DisplayRefreshMonitorManager): Deleted.

  • platform/graphics/GraphicsLayerUpdater.cpp:

(WebCore::GraphicsLayerUpdater::GraphicsLayerUpdater):

  • platform/graphics/ios/DisplayRefreshMonitorIOS.mm:

(-[WebDisplayLinkHandler setPreferredFramesPerSecond:]):
Set the preferredFramesPerSecond of the CADisplayLink.

Source/WebKit:

Create an IPC message on the DrawingArea to send a message from the
WebProcess to the UIProcess to setPreferredFramesPerSecond of the
DisplayRefreshMonitor.

  • UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h:
  • UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.messages.in:
  • UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:

(-[WKOneShotDisplayLinkHandler setPreferredFramesPerSecond:]):
(WebKit::RemoteLayerTreeDrawingAreaProxy::setPreferredFramesPerSecond):
Set the preferredFramesPerSecond of the CADisplayLink.

  • WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.h:
  • WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.mm:

(WebKit::RemoteLayerTreeDisplayRefreshMonitor::setPreferredFramesPerSecond):
Delegate the call to RemoteLayerTreeDrawingArea.

  • WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h:
  • WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:

(WebKit::RemoteLayerTreeDrawingArea::setPreferredFramesPerSecond):
Send the IPC message from the WebProcess to the UIProcess.

LayoutTests:

  • fast/animation/request-animation-frame-throttling-outside-viewport-expected.txt: Added.
  • fast/animation/request-animation-frame-throttling-outside-viewport.html: Added.
  • fast/animation/request-animation-frame-throttling-lowPowerMode-expected.txt:
  • fast/animation/request-animation-frame-throttling-lowPowerMode.html:
  • fast/animation/resources/frame-with-animation-2.html: Added.
Location:
trunk
Files:
4 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r253297 r253299  
     12019-12-09  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Throttling requestAnimationFrame should be controlled by RenderingUpdateScheduler
     4        https://bugs.webkit.org/show_bug.cgi?id=204713
     5
     6        Reviewed by Simon Fraser.
     7
     8        * fast/animation/request-animation-frame-throttling-outside-viewport-expected.txt: Added.
     9        * fast/animation/request-animation-frame-throttling-outside-viewport.html: Added.
     10        * fast/animation/request-animation-frame-throttling-lowPowerMode-expected.txt:
     11        * fast/animation/request-animation-frame-throttling-lowPowerMode.html:
     12        * fast/animation/resources/frame-with-animation-2.html: Added.
     13
    1142019-12-09  youenn fablet  <youenn@apple.com>
    215
  • trunk/LayoutTests/fast/animation/request-animation-frame-throttling-lowPowerMode-expected.txt

    r213169 r253299  
    44
    55
    6 PASS internals.isRequestAnimationFrameThrottled() is false
    7 PASS internals.requestAnimationFrameInterval is Infinity
    8 rAFHandle = requestAnimationFrame(doWork);
    9 PASS internals.isRequestAnimationFrameThrottled() is false
    10 PASS internals.requestAnimationFrameInterval is 0.015
    11 internals.setLowPowerModeEnabled(true);
    12 PASS internals.isRequestAnimationFrameThrottled() is true
    13 PASS internals.requestAnimationFrameInterval is 0.030
    14 cancelAnimationFrame(rAFHandle);
    15 PASS internals.isRequestAnimationFrameThrottled() is true
    16 PASS internals.requestAnimationFrameInterval is 0.030
    17 rAFHandle = requestAnimationFrame(doWork);
    18 PASS internals.isRequestAnimationFrameThrottled() is true
    19 PASS internals.requestAnimationFrameInterval is 0.030
    20 internals.setLowPowerModeEnabled(false);
    21 PASS internals.isRequestAnimationFrameThrottled() is false
    22 PASS internals.requestAnimationFrameInterval is 0.015
     6PASS farmesPerSecond < 35 is true
    237PASS successfullyParsed is true
    248
  • trunk/LayoutTests/fast/animation/request-animation-frame-throttling-lowPowerMode.html

    r213169 r253299  
    22<html>
    33<body>
    4 <script src="../../resources/js-test-pre.js"></script>
    5 <script>
    6 description("Test that requestAnimationFrame gets throttled in low power mode.");
     4    <script src="../../resources/js-test-pre.js"></script>
     5    <script>
     6        description("Test that requestAnimationFrame gets throttled in low power mode.");
    77
    8 let rAFHandle;
    9 let i = 0;
    10 function doWork()
    11 {
    12     i++;
    13     rAFHandle = requestAnimationFrame(doWork);
    14 }
     8        window.jsTestIsAsync = true;
    159
    16 shouldBeFalse("internals.isRequestAnimationFrameThrottled()");
    17 shouldBe("internals.requestAnimationFrameInterval", "Infinity");
    18 evalAndLog("rAFHandle = requestAnimationFrame(doWork);");
    19 shouldBeFalse("internals.isRequestAnimationFrameThrottled()");
    20 shouldBe("internals.requestAnimationFrameInterval", "0.015");
    21 evalAndLog("internals.setLowPowerModeEnabled(true);");
    22 shouldBeTrue("internals.isRequestAnimationFrameThrottled()");
    23 shouldBe("internals.requestAnimationFrameInterval", "0.030");
    24 evalAndLog("cancelAnimationFrame(rAFHandle);");
    25 shouldBeTrue("internals.isRequestAnimationFrameThrottled()");
    26 shouldBe("internals.requestAnimationFrameInterval", "0.030");
    27 evalAndLog("rAFHandle = requestAnimationFrame(doWork);");
    28 shouldBeTrue("internals.isRequestAnimationFrameThrottled()");
    29 shouldBe("internals.requestAnimationFrameInterval", "0.030");
    30 evalAndLog("internals.setLowPowerModeEnabled(false);");
    31 shouldBeFalse("internals.isRequestAnimationFrameThrottled()");
    32 shouldBe("internals.requestAnimationFrameInterval", "0.015");
    33 </script>
    34 <script src="../../resources/js-test-post.js"></script>
     10        if (window.internals)
     11            internals.setLowPowerModeEnabled(true);
     12
     13        var start = null;
     14        var farmesPerSecond = 0;
     15        function doWork(timestamp) {
     16            if (!start)
     17                start = timestamp;
     18            if (timestamp - start < 1000) {
     19                ++farmesPerSecond;
     20                window.requestAnimationFrame(doWork);
     21            }
     22            else {
     23                // The LowPowerMode throttling interval = 30_ms. The frame rate ~= 33.3 fps.
     24                shouldBeTrue("farmesPerSecond < 35");
     25                finishJSTest();
     26            }
     27        }
     28        window.requestAnimationFrame(doWork);
     29    </script>
     30    <script src="../../resources/js-test-post.js"></script>
    3531</body>
    3632</html>
  • trunk/Source/WebCore/ChangeLog

    r253296 r253299  
     12019-12-09  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Throttling requestAnimationFrame should be controlled by RenderingUpdateScheduler
     4        https://bugs.webkit.org/show_bug.cgi?id=204713
     5
     6        Reviewed by Simon Fraser.
     7
     8        Test: fast/animation/request-animation-frame-throttling-outside-viewport.html
     9
     10        requestAnimationFrame is throttled by a timer although its callback are
     11        serviced by the page RenderingUpdate. This led to excessive rAF firing
     12        which makes it more than the preferred frame per seconds.
     13
     14        The solution is to have two throttling types:
     15
     16        1) Page throttling (or full throttling) which slows down all the steps of
     17           RenderingUpdate for the main document and all the sub-documents.
     18        2) Document throttling (or partial throttling) which only slows down the
     19           rAF of a certain document.
     20
     21        * Headers.cmake:
     22        * WebCore.xcodeproj/project.pbxproj:
     23
     24        * animation/DocumentTimeline.cpp:
     25        (WebCore::DocumentTimeline::animationInterval const):
     26        (WebCore::DocumentTimeline::updateThrottlingState): Deleted.
     27        * animation/DocumentTimeline.h:
     28        There is no need to have DocumentTimeline throttling. It is throttled
     29        when the page RenderingUpdate is throttled.
     30
     31        * dom/Document.cpp:
     32        (WebCore::Document::requestAnimationFrame):
     33        (WebCore::Document::updateLastHandledUserGestureTimestamp):
     34        LowPowerMode throttling is now handled by the page. So remove its handling
     35        in the Document side.
     36
     37        * dom/ScriptedAnimationController.cpp:
     38        (WebCore::ScriptedAnimationController::ScriptedAnimationController):
     39        (WebCore::ScriptedAnimationController::page const):
     40        (WebCore::ScriptedAnimationController::interval const):
     41        (WebCore::ScriptedAnimationController::isThrottled const):
     42        (WebCore::ScriptedAnimationController::registerCallback):
     43        (WebCore::ScriptedAnimationController::cancelCallback):
     44        (WebCore::ScriptedAnimationController::serviceRequestAnimationFrameCallbacks):
     45        (WebCore::ScriptedAnimationController::scheduleAnimation):
     46        (WebCore::throttlingReasonToString): Deleted.
     47        (WebCore::throttlingReasonsToString): Deleted.
     48        (WebCore::ScriptedAnimationController::addThrottlingReason): Deleted.
     49        (WebCore::ScriptedAnimationController::removeThrottlingReason): Deleted.
     50        (WebCore::ScriptedAnimationController::animationTimerFired): Deleted.
     51        * dom/ScriptedAnimationController.h:
     52        (WebCore::ScriptedAnimationController::addThrottlingReason):
     53        (WebCore::ScriptedAnimationController::removeThrottlingReason):
     54        Get rid of the rAF throttling timer. Service the rAF callback only when
     55        the period from the current time stamp till the last service time stamp
     56        is greater than the preferred rAF interval .
     57
     58        * page/FrameView.cpp:
     59        (WebCore::FrameView::updateScriptedAnimationsAndTimersThrottlingState):
     60        ThrottlingReason is now defined outside ScriptedAnimationController.
     61
     62        * page/Page.cpp:
     63        (WebCore::Page::suspendScriptedAnimations):
     64        (WebCore::Page::resumeScriptedAnimations):
     65        Use forEachDocument().
     66
     67        (WebCore::Page::preferredRenderingUpdateInterval const):
     68        Calculate the preferred RenderingUpdate interval from the throttling
     69        reasons.
     70
     71        (WebCore::Page::setIsVisuallyIdleInternal):
     72        (WebCore::Page::handleLowModePowerChange):
     73        Call adjustRenderingUpdateFrequency() when isLowPowerModeEnabled or
     74        IsVisuallyIdle is toggled.
     75
     76        (WebCore::updateScriptedAnimationsThrottlingReason): Deleted.
     77        * page/Page.h:
     78        (WebCore::Page::isRenderingUpdateThrottled const):
     79   
     80        * page/RenderingUpdateScheduler.cpp:
     81        (WebCore::RenderingUpdateScheduler::adjustFramesPerSecond):
     82        (WebCore::RenderingUpdateScheduler::adjustRenderingUpdateFrequency):
     83        Change the preferredFramesPerSecond of the DisplayRefreshMonitor if the
     84        throttling is not aggressive e.g. 10_s. Otherwise use the timer.
     85
     86        (WebCore::RenderingUpdateScheduler::scheduleTimedRenderingUpdate):
     87        Call adjustFramesPerSecond() when DisplayRefreshMonitor is created.
     88
     89        (WebCore::RenderingUpdateScheduler::startTimer):
     90        * page/RenderingUpdateScheduler.h:
     91
     92        * platform/graphics/AnimationFrameRate.h: Added.
     93        (WebCore::preferredFrameInterval):
     94        (WebCore::preferredFramesPerSecond):
     95        * platform/graphics/DisplayRefreshMonitor.h:
     96        (WebCore::DisplayRefreshMonitor::setPreferredFramesPerSecond):
     97   
     98        * platform/graphics/DisplayRefreshMonitorManager.cpp:
     99        (WebCore::DisplayRefreshMonitorManager::monitorForClient):
     100        Rename createMonitorForClient() to monitorForClient() since it may return
     101        a cached DisplayRefreshMonitor.
     102
     103        (WebCore::DisplayRefreshMonitorManager::setPreferredFramesPerSecond):
     104        (WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
     105        (WebCore::DisplayRefreshMonitorManager::displayDidRefresh):
     106        No need to call registerClient(). This function was just ensuring the
     107        DisplayRefreshMonitor is created. scheduleAnimation() does the same thing.
     108
     109        (WebCore::DisplayRefreshMonitorManager::createMonitorForClient): Deleted.
     110        (WebCore::DisplayRefreshMonitorManager::registerClient): Deleted.
     111        * platform/graphics/DisplayRefreshMonitorManager.h:
     112        (WebCore::DisplayRefreshMonitorManager::DisplayRefreshMonitorManager): Deleted.
     113
     114        * platform/graphics/GraphicsLayerUpdater.cpp:
     115        (WebCore::GraphicsLayerUpdater::GraphicsLayerUpdater):
     116        * platform/graphics/ios/DisplayRefreshMonitorIOS.mm:
     117        (-[WebDisplayLinkHandler setPreferredFramesPerSecond:]):
     118        Set the preferredFramesPerSecond of the CADisplayLink.
     119
    11202019-12-09  Per Arne Vollan  <pvollan@apple.com>
    2121
  • trunk/Source/WebCore/Headers.cmake

    r253249 r253299  
    10121012
    10131013    platform/graphics/ANGLEWebKitBridge.h
     1014    platform/graphics/AnimationFrameRate.h
    10141015    platform/graphics/AudioTrackPrivate.h
    10151016    platform/graphics/BitmapImage.h
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r253258 r253299  
    21212121                72144334223EC91600F12FF7 /* SVGPropertyOwner.h in Headers */ = {isa = PBXBuildFile; fileRef = 55EE5360223B2A2100FBA944 /* SVGPropertyOwner.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21222122                72283F0E230B268C00F5D828 /* ImagePaintingOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 72C18A3F230B04B7006847C7 /* ImagePaintingOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2123                722A815D238FDAF000C00583 /* AnimationFrameRate.h in Headers */ = {isa = PBXBuildFile; fileRef = 722A815C238FD50500C00583 /* AnimationFrameRate.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21232124                724ED3321A3A8B2300F5F13C /* JSEXTBlendMinMax.h in Headers */ = {isa = PBXBuildFile; fileRef = 724ED3301A3A8B2300F5F13C /* JSEXTBlendMinMax.h */; };
    21242125                724EE5501DC80D7F00A91FFB /* ActivityState.h in Headers */ = {isa = PBXBuildFile; fileRef = 724EE54E1DC7F25B00A91FFB /* ActivityState.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    95649565                721443452240C8BA00F12FF7 /* SVGAnimatedValueProperty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedValueProperty.h; sourceTree = "<group>"; };
    95659566                721443462240CAD200F12FF7 /* SVGValueProperty.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGValueProperty.h; sourceTree = "<group>"; };
     9567                722A815C238FD50500C00583 /* AnimationFrameRate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnimationFrameRate.h; sourceTree = "<group>"; };
    95669568                724ED3291A3A7E5400F5F13C /* EXTBlendMinMax.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EXTBlendMinMax.cpp; sourceTree = "<group>"; };
    95679569                724ED32A1A3A7E5400F5F13C /* EXTBlendMinMax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTBlendMinMax.h; sourceTree = "<group>"; };
     
    1674816750                                E4FB4B35239BEB10003C336A /* DisplayInlineContent.cpp */,
    1674916751                                E451C6332394058E00993190 /* DisplayInlineContent.h */,
     16752                                112FB350239C23C40087054A /* DisplayInlineRect.h */,
    1675016753                                6FB47E612277425A00C7BCB0 /* DisplayLineBox.h */,
    1675116754                                6F77868523491AC6004D9636 /* DisplayPainter.cpp */,
    1675216755                                6F77868723491AD7004D9636 /* DisplayPainter.h */,
    1675316756                                6FD9CD52227E21C800E53957 /* DisplayRect.h */,
    16754                                 112FB350239C23C40087054A /* DisplayInlineRect.h */,
    1675516757                                6FCE1A1822618AB3004F0343 /* DisplayRun.h */,
    1675616758                        );
     
    2491424916                                490707E41219C04300D90E51 /* ANGLEWebKitBridge.cpp */,
    2491524917                                490707E51219C04300D90E51 /* ANGLEWebKitBridge.h */,
     24918                                722A815C238FD50500C00583 /* AnimationFrameRate.h */,
    2491624919                                BEF29EE91715DD0900C4B4C9 /* AudioTrackPrivate.h */,
    2491724920                                A89943270B42338700D7C802 /* BitmapImage.cpp */,
     
    2893028933                                71E2C42621C935280024F8C8 /* AnimationEffectPhase.h in Headers */,
    2893128934                                319848011A1D817B00A13318 /* AnimationEvent.h in Headers */,
     28935                                722A815D238FDAF000C00583 /* AnimationFrameRate.h in Headers */,
    2893228936                                49E912AD0EFAC906009D0CAF /* AnimationList.h in Headers */,
    2893328937                                714C7C661FDAD2A100F2BEE1 /* AnimationPlaybackEvent.h in Headers */,
     
    2960729611                                1199FA5B208E3C7F002358CC /* DisplayBox.h in Headers */,
    2960829612                                E451C6342394058F00993190 /* DisplayInlineContent.h in Headers */,
     29613                                112FB352239C23C40087054A /* DisplayInlineRect.h in Headers */,
     29614                                6FB47E632277425A00C7BCB0 /* DisplayLineBox.h in Headers */,
    2960929615                                0FE5FBD31C3DD51E0007A2CA /* DisplayList.h in Headers */,
    2961029616                                0FE5FBD51C3DD51E0007A2CA /* DisplayListItems.h in Headers */,
     
    3026630272                                6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */,
    3026730273                                BCE789161120D6080060ECE5 /* InlineIterator.h in Headers */,
    30268                                 6FB47E632277425A00C7BCB0 /* DisplayLineBox.h in Headers */,
    3026930274                                6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */,
    3027030275                                6F0CD695229ED32700C5994E /* InlineLineBuilder.h in Headers */,
     
    3192831933                                436708C112D9CA4B00044234 /* RenderSVGBlock.h in Headers */,
    3192931934                                436708C312D9CA4B00044234 /* RenderSVGContainer.h in Headers */,
    31930                                 112FB352239C23C40087054A /* DisplayInlineRect.h in Headers */,
    3193131935                                2B365C841525119E0091D27B /* RenderSVGEllipse.h in Headers */,
    3193231936                                43C092BC12D9E4EE00A989C3 /* RenderSVGForeignObject.h in Headers */,
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r253091 r253299  
    4545#include <JavaScriptCore/VM.h>
    4646
    47 static const Seconds defaultAnimationInterval { 15_ms };
    48 static const Seconds throttledAnimationInterval { 30_ms };
    49 
    5047namespace WebCore {
    5148
     
    194191}
    195192
    196 void DocumentTimeline::updateThrottlingState()
    197 {
    198     scheduleAnimationResolution();
    199 }
    200 
    201193Seconds DocumentTimeline::animationInterval() const
    202194{
    203195    if (!m_document || !m_document->page())
    204196        return Seconds::infinity();
    205     return m_document->page()->isLowPowerModeEnabled() ? throttledAnimationInterval : defaultAnimationInterval;
     197    return m_document->page()->preferredRenderingUpdateInterval();
    206198}
    207199
  • trunk/Source/WebCore/animation/DocumentTimeline.h

    r252527 r253299  
    7474    void updateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp);
    7575
    76     void updateThrottlingState();
    7776    WEBCORE_EXPORT Seconds animationInterval() const;
    7877    WEBCORE_EXPORT void suspendAnimations();
  • trunk/Source/WebCore/dom/Document.cpp

    r253279 r253299  
    64926492            m_scriptedAnimationController->suspend();
    64936493
    6494         if (page() && page()->isLowPowerModeEnabled())
    6495             m_scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::LowPowerMode);
    6496 
    64976494        if (!topOrigin().canAccess(securityOrigin()) && !hasHadUserInteraction())
    6498             m_scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::NonInteractedCrossOriginFrame);
     6495            m_scriptedAnimationController->addThrottlingReason(ThrottlingReason::NonInteractedCrossOriginFrame);
    64996496    }
    65006497
     
    67356732    if (static_cast<bool>(time) && m_scriptedAnimationController) {
    67366733        // It's OK to always remove NonInteractedCrossOriginFrame even if this frame isn't cross-origin.
    6737         m_scriptedAnimationController->removeThrottlingReason(ScriptedAnimationController::ThrottlingReason::NonInteractedCrossOriginFrame);
     6734        m_scriptedAnimationController->removeThrottlingReason(ThrottlingReason::NonInteractedCrossOriginFrame);
    67386735    }
    67396736
  • trunk/Source/WebCore/dom/ScriptedAnimationController.cpp

    r250672 r253299  
    11/*
    22 * Copyright (C) 2011 Google Inc. All Rights Reserved.
     3 * Copyright (C) 2019 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    2728#include "ScriptedAnimationController.h"
    2829
    29 #include "Chrome.h"
    30 #include "ChromeClient.h"
    31 #include "CustomHeaderFields.h"
    32 #include "DOMWindow.h"
    33 #include "Document.h"
    34 #include "DocumentLoader.h"
    35 #include "Frame.h"
    36 #include "FrameView.h"
    3730#include "InspectorInstrumentation.h"
    38 #include "Logging.h"
    3931#include "Page.h"
    4032#include "RequestAnimationFrameCallback.h"
    4133#include "Settings.h"
    42 #include <algorithm>
    43 #include <wtf/Ref.h>
    4434#include <wtf/SystemTracing.h>
    45 #include <wtf/text/StringBuilder.h>
    46 
    47 // Allow a little more than 60fps to make sure we can at least hit that frame rate.
    48 static const Seconds fullSpeedAnimationInterval { 15_ms };
    49 // Allow a little more than 30fps to make sure we can at least hit that frame rate.
    50 static const Seconds halfSpeedThrottlingAnimationInterval { 30_ms };
    51 static const Seconds aggressiveThrottlingAnimationInterval { 10_s };
    52 
    53 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(page() && page()->isAlwaysOnLoggingAllowed(), PerformanceLogging, "%p - ScriptedAnimationController::" fmt, this, ##__VA_ARGS__)
    5435
    5536namespace WebCore {
     
    5738ScriptedAnimationController::ScriptedAnimationController(Document& document)
    5839    : m_document(makeWeakPtr(document))
    59     , m_animationTimer(*this, &ScriptedAnimationController::animationTimerFired)
    6040{
    6141}
     
    6646{
    6747    return m_document && m_document->settings().requestAnimationFrameEnabled();
     48}
     49
     50Page* ScriptedAnimationController::page() const
     51{
     52    return m_document ? m_document->page() : nullptr;
     53}
     54
     55Seconds ScriptedAnimationController::interval() const
     56{
     57    if (auto* page = this->page())
     58        return std::max(preferredFrameInterval(m_throttlingReasons), page->preferredRenderingUpdateInterval());
     59    return preferredFrameInterval(m_throttlingReasons);
    6860}
    6961
     
    8476}
    8577
    86 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) && !RELEASE_LOG_DISABLED
    87 
    88 static const char* throttlingReasonToString(ScriptedAnimationController::ThrottlingReason reason)
    89 {
    90     switch (reason) {
    91     case ScriptedAnimationController::ThrottlingReason::VisuallyIdle:
    92         return "VisuallyIdle";
    93     case ScriptedAnimationController::ThrottlingReason::OutsideViewport:
    94         return "OutsideViewport";
    95     case ScriptedAnimationController::ThrottlingReason::LowPowerMode:
    96         return "LowPowerMode";
    97     case ScriptedAnimationController::ThrottlingReason::NonInteractedCrossOriginFrame:
    98         return "NonInteractiveCrossOriginFrame";
    99     }
    100 }
    101 
    102 static String throttlingReasonsToString(OptionSet<ScriptedAnimationController::ThrottlingReason> reasons)
    103 {
    104     if (reasons.isEmpty())
    105         return "[Unthrottled]"_s;
    106 
    107     StringBuilder builder;
    108     for (auto reason : reasons) {
    109         if (!builder.isEmpty())
    110             builder.append('|');
    111         builder.append(throttlingReasonToString(reason));
    112     }
    113     return builder.toString();
    114 }
    115 
    116 #endif
    117 
    118 void ScriptedAnimationController::addThrottlingReason(ThrottlingReason reason)
    119 {
    120 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    121     if (m_throttlingReasons.contains(reason))
    122         return;
    123 
    124     m_throttlingReasons.add(reason);
    125 
    126     RELEASE_LOG_IF_ALLOWED("addThrottlingReason(%s) -> %s", throttlingReasonToString(reason), throttlingReasonsToString(m_throttlingReasons).utf8().data());
    127 
    128     if (m_animationTimer.isActive()) {
    129         m_animationTimer.stop();
    130         scheduleAnimation();
    131     }
    132 #else
    133     UNUSED_PARAM(reason);
    134 #endif
    135 }
    136 
    137 void ScriptedAnimationController::removeThrottlingReason(ThrottlingReason reason)
    138 {
    139 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    140     if (!m_throttlingReasons.contains(reason))
    141         return;
    142 
    143     m_throttlingReasons.remove(reason);
    144 
    145     RELEASE_LOG_IF_ALLOWED("removeThrottlingReason(%s) -> %s", throttlingReasonToString(reason), throttlingReasonsToString(m_throttlingReasons).utf8().data());
    146 
    147     if (m_animationTimer.isActive()) {
    148         m_animationTimer.stop();
    149         scheduleAnimation();
    150     }
    151 #else
    152     UNUSED_PARAM(reason);
    153 #endif
    154 }
    155 
    15678bool ScriptedAnimationController::isThrottled() const
    15779{
    158 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    159     return !m_throttlingReasons.isEmpty();
    160 #else
     80    auto* page = this->page();
     81    if (!m_throttlingReasons.isEmpty() || (page && page->isRenderingUpdateThrottled())) {
     82        ASSERT(interval() > FullSpeedAnimationInterval);
     83        return true;
     84    }
    16185    return false;
    162 #endif
    16386}
    16487
    16588ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(Ref<RequestAnimationFrameCallback>&& callback)
    16689{
    167     ScriptedAnimationController::CallbackId id = ++m_nextCallbackId;
     90    CallbackId callbackId = ++m_nextCallbackId;
    16891    callback->m_firedOrCancelled = false;
    169     callback->m_id = id;
     92    callback->m_id = callbackId;
    17093    m_callbacks.append(WTFMove(callback));
    17194
    17295    if (m_document)
    173         InspectorInstrumentation::didRequestAnimationFrame(*m_document, id);
     96        InspectorInstrumentation::didRequestAnimationFrame(*m_document, callbackId);
    17497
    17598    if (!m_suspendCount)
    17699        scheduleAnimation();
    177     return id;
     100    return callbackId;
    178101}
    179102
    180 void ScriptedAnimationController::cancelCallback(CallbackId id)
     103void ScriptedAnimationController::cancelCallback(CallbackId callbackId)
    181104{
    182     for (size_t i = 0; i < m_callbacks.size(); ++i) {
    183         if (m_callbacks[i]->m_id == id) {
    184             m_callbacks[i]->m_firedOrCancelled = true;
    185             InspectorInstrumentation::didCancelAnimationFrame(*m_document, id);
    186             m_callbacks.remove(i);
    187             return;
    188         }
    189     }
     105    bool cancelled = m_callbacks.removeFirstMatching([&](auto& callback) {
     106        if (callback->m_id != callbackId)
     107            return false;
     108        callback->m_firedOrCancelled = true;
     109        return true;
     110    });
     111
     112    if (cancelled && m_document)
     113        InspectorInstrumentation::didCancelAnimationFrame(*m_document, callbackId);
    190114}
    191115
     
    195119        return;
    196120
     121    bool isThrottlingRelativeToPage = page() && page()->preferredRenderingUpdateInterval() < preferredFrameInterval(m_throttlingReasons);
     122    bool canSkipFrame = Seconds(timestamp - m_lastAnimationFrameTimestamp) < preferredFrameInterval(m_throttlingReasons);
     123    if (isThrottlingRelativeToPage && canSkipFrame) {
     124        scheduleAnimation();
     125        return;
     126    }
     127   
    197128    TraceScope tracingScope(RAFCallbackStart, RAFCallbackEnd);
    198129
     
    224155    });
    225156
     157    m_lastAnimationFrameTimestamp = timestamp;
     158
    226159    if (m_callbacks.size())
    227160        scheduleAnimation();
    228 }
    229 
    230 Seconds ScriptedAnimationController::interval() const
    231 {
    232 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    233     if (m_throttlingReasons.contains(ThrottlingReason::VisuallyIdle) || m_throttlingReasons.contains(ThrottlingReason::OutsideViewport))
    234         return aggressiveThrottlingAnimationInterval;
    235 
    236     if (m_throttlingReasons.contains(ThrottlingReason::LowPowerMode))
    237         return halfSpeedThrottlingAnimationInterval;
    238 
    239     if (m_throttlingReasons.contains(ThrottlingReason::NonInteractedCrossOriginFrame))
    240         return halfSpeedThrottlingAnimationInterval;
    241 
    242     ASSERT(m_throttlingReasons.isEmpty());
    243 #endif
    244     return fullSpeedAnimationInterval;
    245 }
    246 
    247 Page* ScriptedAnimationController::page() const
    248 {
    249     return m_document ? m_document->page() : nullptr;
    250161}
    251162
     
    255166        return;
    256167
    257 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    258     if (!m_isUsingTimer && !isThrottled()) {
    259         if (auto* page = this->page()) {
    260             page->renderingUpdateScheduler().scheduleTimedRenderingUpdate();
    261             return;
    262         }
    263 
    264         m_isUsingTimer = true;
    265     }
    266 #endif
    267     if (m_animationTimer.isActive())
    268         return;
    269 
    270     Seconds animationInterval = interval();
    271     Seconds scheduleDelay = std::max(animationInterval - Seconds(m_document->domWindow()->nowTimestamp() - m_lastAnimationFrameTimestamp), 0_s);
    272 
    273     if (isThrottled()) {
    274         // FIXME: not ideal to snapshot time both in now() and nowTimestamp(), the latter of which also has reduced resolution.
    275         MonotonicTime now = MonotonicTime::now();
    276 
    277         MonotonicTime fireTime = now + scheduleDelay;
    278         Seconds alignmentInterval = 10_ms;
    279         // Snap to the nearest alignmentInterval.
    280         Seconds alignment = (fireTime + alignmentInterval / 2) % alignmentInterval;
    281         MonotonicTime alignedFireTime = fireTime - alignment;
    282         scheduleDelay = alignedFireTime - now;
    283     }
    284 
    285     m_animationTimer.startOneShot(scheduleDelay);
    286 }
    287 
    288 void ScriptedAnimationController::animationTimerFired()
    289 {
    290     m_lastAnimationFrameTimestamp = m_document->domWindow()->nowTimestamp();
    291     serviceRequestAnimationFrameCallbacks(m_lastAnimationFrameTimestamp);
     168    if (auto* page = this->page())
     169        page->renderingUpdateScheduler().scheduleTimedRenderingUpdate();
    292170}
    293171
  • trunk/Source/WebCore/dom/ScriptedAnimationController.h

    r244234 r253299  
    11/*
    22 * Copyright (C) 2011 Google Inc. All Rights Reserved.
     3 * Copyright (C) 2019 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    2627#pragma once
    2728
     29#include "AnimationFrameRate.h"
    2830#include "DOMHighResTimeStamp.h"
    29 #include "Timer.h"
    3031#include <wtf/OptionSet.h>
    3132#include <wtf/RefCounted.h>
    3233#include <wtf/RefPtr.h>
    3334#include <wtf/Vector.h>
     35#include <wtf/WeakPtr.h>
    3436
    3537namespace WebCore {
     
    4951    void clearDocumentPointer() { m_document = nullptr; }
    5052    bool requestAnimationFrameEnabled() const;
     53    WEBCORE_EXPORT Seconds interval() const;
    5154
    5255    typedef int CallbackId;
     
    5861    void suspend();
    5962    void resume();
    60 
    61     enum class ThrottlingReason {
    62         VisuallyIdle                    = 1 << 0,
    63         OutsideViewport                 = 1 << 1,
    64         LowPowerMode                    = 1 << 2,
    65         NonInteractedCrossOriginFrame   = 1 << 3,
    66     };
    67     void addThrottlingReason(ThrottlingReason);
    68     void removeThrottlingReason(ThrottlingReason);
    69 
     63   
     64    void addThrottlingReason(ThrottlingReason reason) { m_throttlingReasons.add(reason); }
     65    void removeThrottlingReason(ThrottlingReason reason) { m_throttlingReasons.remove(reason); }
    7066    WEBCORE_EXPORT bool isThrottled() const;
    71     WEBCORE_EXPORT Seconds interval() const;
    7267
    7368private:
    7469    ScriptedAnimationController(Document&);
    7570
     71    Page* page() const;
    7672    void scheduleAnimation();
    77     void animationTimerFired();
    7873
    79     Page* page() const;
    80 
    81     typedef Vector<RefPtr<RequestAnimationFrameCallback>> CallbackList;
     74    using CallbackList = Vector<RefPtr<RequestAnimationFrameCallback>>;
    8275    CallbackList m_callbacks;
     76    DOMHighResTimeStamp m_lastAnimationFrameTimestamp { 0 };
    8377
    8478    WeakPtr<Document> m_document;
     
    8680    int m_suspendCount { 0 };
    8781
    88     Timer m_animationTimer;
    89     double m_lastAnimationFrameTimestamp { 0 };
    90 
    91 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    9282    OptionSet<ThrottlingReason> m_throttlingReasons;
    93     bool m_isUsingTimer { false };
    94 #endif
    9583};
    9684
  • trunk/Source/WebCore/page/FrameView.cpp

    r252935 r253299  
    25252525    if (auto* scriptedAnimationController = document->scriptedAnimationController()) {
    25262526        if (shouldThrottle)
    2527             scriptedAnimationController->addThrottlingReason(ScriptedAnimationController::ThrottlingReason::OutsideViewport);
     2527            scriptedAnimationController->addThrottlingReason(ThrottlingReason::OutsideViewport);
    25282528        else
    2529             scriptedAnimationController->removeThrottlingReason(ScriptedAnimationController::ThrottlingReason::OutsideViewport);
     2529            scriptedAnimationController->removeThrottlingReason(ThrottlingReason::OutsideViewport);
    25302530    }
    25312531
  • trunk/Source/WebCore/page/Page.cpp

    r253231 r253299  
    2323#include "ActivityStateChangeObserver.h"
    2424#include "AlternativeTextClient.h"
     25#include "AnimationFrameRate.h"
    2526#include "ApplicationCacheStorage.h"
    2627#include "ApplicationStateChangeListener.h"
     
    13701371{
    13711372    m_scriptedAnimationsSuspended = true;
    1372     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
    1373         if (frame->document())
    1374             frame->document()->suspendScriptedAnimationControllerCallbacks();
    1375     }
     1373    forEachDocument([&] (Document& document) {
     1374        document.suspendScriptedAnimationControllerCallbacks();
     1375    });
    13761376}
    13771377
     
    13791379{
    13801380    m_scriptedAnimationsSuspended = false;
    1381     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
    1382         if (frame->document())
    1383             frame->document()->resumeScriptedAnimationControllerCallbacks();
    1384     }
    1385 }
    1386 
    1387 enum class ThrottlingReasonOperation { Add, Remove };
    1388 static void updateScriptedAnimationsThrottlingReason(Page& page, ThrottlingReasonOperation operation, ScriptedAnimationController::ThrottlingReason reason)
    1389 {
    1390     for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
    1391         auto* document = frame->document();
    1392         if (!document)
    1393             continue;
    1394         auto* scriptedAnimationController = document->scriptedAnimationController();
    1395         if (!scriptedAnimationController)
    1396             continue;
    1397 
    1398         if (operation == ThrottlingReasonOperation::Add)
    1399             scriptedAnimationController->addThrottlingReason(reason);
    1400         else
    1401             scriptedAnimationController->removeThrottlingReason(reason);
    1402     }
     1381    forEachDocument([&] (Document& document) {
     1382        document.resumeScriptedAnimationControllerCallbacks();
     1383    });
     1384}
     1385
     1386Seconds Page::preferredRenderingUpdateInterval() const
     1387{
     1388    return preferredFrameInterval(m_throttlingReasons);
    14031389}
    14041390
    14051391void Page::setIsVisuallyIdleInternal(bool isVisuallyIdle)
    14061392{
    1407     updateScriptedAnimationsThrottlingReason(*this, isVisuallyIdle ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::VisuallyIdle);
     1393    if (isVisuallyIdle == m_throttlingReasons.contains(ThrottlingReason::VisuallyIdle))
     1394        return;
     1395
     1396    m_throttlingReasons = m_throttlingReasons ^ ThrottlingReason::VisuallyIdle;
     1397    renderingUpdateScheduler().adjustRenderingUpdateFrequency();
    14081398}
    14091399
    14101400void Page::handleLowModePowerChange(bool isLowPowerModeEnabled)
    14111401{
    1412     updateScriptedAnimationsThrottlingReason(*this, isLowPowerModeEnabled ? ThrottlingReasonOperation::Add : ThrottlingReasonOperation::Remove, ScriptedAnimationController::ThrottlingReason::LowPowerMode);
    1413     if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
    1414         forEachDocument([&] (Document& document) {
    1415             if (auto timeline = document.existingTimeline())
    1416                 timeline->updateThrottlingState();
    1417         });
    1418     } else
     1402    if (isLowPowerModeEnabled == m_throttlingReasons.contains(ThrottlingReason::LowPowerMode))
     1403        return;
     1404
     1405    m_throttlingReasons = m_throttlingReasons ^ ThrottlingReason::LowPowerMode;
     1406    renderingUpdateScheduler().adjustRenderingUpdateFrequency();
     1407
     1408    if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled())
    14191409        mainFrame().animation().updateThrottlingState();
     1410
    14201411    updateDOMTimerAlignmentInterval();
    14211412}
  • trunk/Source/WebCore/page/Page.h

    r253279 r253299  
    2222
    2323#include "ActivityState.h"
     24#include "AnimationFrameRate.h"
    2425#include "DisabledAdaptations.h"
    2526#include "Document.h"
     
    274275
    275276    RenderingUpdateScheduler& renderingUpdateScheduler();
     277    bool isRenderingUpdateThrottled() const { return !m_throttlingReasons.isEmpty(); }
    276278
    277279    ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient.get(); }
     
    714716    WEBCORE_EXPORT void setLowPowerModeEnabledOverrideForTesting(Optional<bool>);
    715717
     718    Seconds preferredRenderingUpdateInterval() const;
     719
    716720    WEBCORE_EXPORT void applicationWillResignActive();
    717721    WEBCORE_EXPORT void applicationDidEnterBackground();
     
    10091013    bool m_mediaBufferingIsSuspended { false };
    10101014    bool m_inUpdateRendering { false };
     1015    OptionSet<ThrottlingReason> m_throttlingReasons;
    10111016};
    10121017
  • trunk/Source/WebCore/page/RenderingUpdateScheduler.cpp

    r248846 r253299  
    4343}
    4444
     45#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) && PLATFORM(IOS_FAMILY)
     46void RenderingUpdateScheduler::adjustFramesPerSecond()
     47{
     48    Seconds interval = m_page.preferredRenderingUpdateInterval();
     49    // CADisplayLink.preferredFramesPerSecond is an integer. So a fraction PreferredFramesPerSecond can't be set.
     50    if (interval < 1_s)
     51        DisplayRefreshMonitorManager::sharedManager().setPreferredFramesPerSecond(*this, preferredFramesPerSecond(interval));
     52}
     53#endif
     54
     55void RenderingUpdateScheduler::adjustRenderingUpdateFrequency()
     56{
     57#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) && PLATFORM(IOS_FAMILY)
     58    adjustFramesPerSecond();
     59#endif
     60    if (isScheduled()) {
     61        clearScheduled();
     62        scheduleTimedRenderingUpdate();
     63    }
     64}
     65
    4566void RenderingUpdateScheduler::scheduleTimedRenderingUpdate()
    4667{
     
    5677    tracePoint(ScheduleRenderingUpdate);
    5778
     79    Seconds interval = m_page.preferredRenderingUpdateInterval();
     80
    5881#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    59     if (!DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this))
     82    // CADisplayLink.preferredFramesPerSecond is an integer. Fall back to timer if the PreferredFramesPerSecond is a fraction.
     83    if (interval < 1_s) {
     84#if PLATFORM(IOS_FAMILY)
     85        if (!m_isMonitorCreated) {
     86            adjustFramesPerSecond();
     87            m_isMonitorCreated = true;
     88        }
     89#else
     90        if (interval == FullSpeedAnimationInterval)
    6091#endif
    61         startTimer(Seconds(1.0 / 60));
     92            m_scheduled = DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this);
     93    }
     94#endif
    6295
    63     m_scheduled = true;
     96    if (!isScheduled())
     97        startTimer(interval);
    6498}
    6599
     
    75109    m_refreshTimer = makeUnique<Timer>(*this, &RenderingUpdateScheduler::displayRefreshFired);
    76110    m_refreshTimer->startOneShot(delay);
     111    m_scheduled = true;
    77112}
    78113
  • trunk/Source/WebCore/page/RenderingUpdateScheduler.h

    r248846 r253299  
    4747
    4848    RenderingUpdateScheduler(Page&);
     49
     50    void adjustRenderingUpdateFrequency();
    4951    void scheduleTimedRenderingUpdate();
    5052    void scheduleImmediateRenderingUpdate();
     
    5355private:
    5456#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     57#if PLATFORM(IOS_FAMILY)
     58    void adjustFramesPerSecond();
     59#endif
    5560    RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const final;
    5661    void windowScreenDidChange(PlatformDisplayID);
     
    6570
    6671    Page& m_page;
     72#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) && PLATFORM(IOS_FAMILY)
     73    bool m_isMonitorCreated;
     74#endif
    6775    bool m_scheduled { false };
    6876    std::unique_ptr<Timer> m_refreshTimer;
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.h

    r247273 r253299  
    2828#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    2929
     30#include "AnimationFrameRate.h"
    3031#include "PlatformScreen.h"
    3132#include <wtf/HashSet.h>
     
    4546
    4647    virtual void displayLinkFired() { }
     48
     49    virtual void setPreferredFramesPerSecond(FramesPerSecond) { }
    4750
    4851    // Return true if callback request was scheduled, false if it couldn't be
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.cpp

    r247534 r253299  
    4343}
    4444
    45 DisplayRefreshMonitor* DisplayRefreshMonitorManager::createMonitorForClient(DisplayRefreshMonitorClient& client)
     45DisplayRefreshMonitor* DisplayRefreshMonitorManager::monitorForClient(DisplayRefreshMonitorClient& client)
    4646{
     47    if (!client.hasDisplayID())
     48        return nullptr;
     49
    4750    PlatformDisplayID clientDisplayID = client.displayID();
    4851    if (auto* existingMonitor = monitorForDisplayID(clientDisplayID)) {
     
    5558        return nullptr;
    5659
    57     LOG(RequestAnimationFrame, "DisplayRefreshMonitorManager::createMonitorForClient() - created monitor %p", monitor.get());
     60    LOG(RequestAnimationFrame, "DisplayRefreshMonitorManager::monitorForClient() - created monitor %p", monitor.get());
    5861    monitor->addClient(client);
    5962    DisplayRefreshMonitor* result = monitor.get();
    6063    m_monitors.append({ WTFMove(monitor) });
    6164    return result;
    62 }
    63 
    64 void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient& client)
    65 {
    66     if (!client.hasDisplayID())
    67         return;
    68 
    69     createMonitorForClient(client);
    7065}
    7166
     
    8681}
    8782
     83void DisplayRefreshMonitorManager::setPreferredFramesPerSecond(DisplayRefreshMonitorClient& client, FramesPerSecond preferredFramesPerSecond)
     84{
     85    if (auto* monitor = monitorForClient(client))
     86        monitor->setPreferredFramesPerSecond(preferredFramesPerSecond);
     87}
     88
    8889bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient& client)
    8990{
    90     if (!client.hasDisplayID())
    91         return false;
    92 
    93     DisplayRefreshMonitor* monitor = createMonitorForClient(client);
    94     if (!monitor)
    95         return false;
    96 
    97     client.setIsScheduled(true);
    98     return monitor->requestRefreshCallback();
     91    if (auto* monitor = monitorForClient(client)) {
     92        client.setIsScheduled(true);
     93        return monitor->requestRefreshCallback();
     94    }
     95    return false;
    9996}
    10097
     
    117114    unregisterClient(client);
    118115    client.setDisplayID(displayID);
    119     registerClient(client);
    120116    if (client.isScheduled())
    121117        scheduleAnimation(client);
  • trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.h

    r247534 r253299  
    2828#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
    2929
     30#include "AnimationFrameRate.h"
    3031#include "DisplayRefreshMonitor.h"
    3132#include "PlatformScreen.h"
     
    3839class DisplayRefreshMonitorManager {
    3940    friend class NeverDestroyed<DisplayRefreshMonitorManager>;
     41    friend class DisplayRefreshMonitor;
    4042public:
    4143    WEBCORE_EXPORT static DisplayRefreshMonitorManager& sharedManager();
    42    
    43     void registerClient(DisplayRefreshMonitorClient&);
     44
    4445    void unregisterClient(DisplayRefreshMonitorClient&);
    4546
     47    void setPreferredFramesPerSecond(DisplayRefreshMonitorClient&, FramesPerSecond);
    4648    bool scheduleAnimation(DisplayRefreshMonitorClient&);
    4749    void windowScreenDidChange(PlatformDisplayID, DisplayRefreshMonitorClient&);
    4850
    4951    WEBCORE_EXPORT void displayWasUpdated(PlatformDisplayID);
    50    
     52
    5153private:
    52     friend class DisplayRefreshMonitor;
     54    DisplayRefreshMonitorManager() = default;
     55    virtual ~DisplayRefreshMonitorManager();
     56
    5357    void displayDidRefresh(DisplayRefreshMonitor&);
    54    
    55     DisplayRefreshMonitorManager() { }
    56     virtual ~DisplayRefreshMonitorManager();
    5758
    5859    size_t findMonitorForDisplayID(PlatformDisplayID) const;
    5960    DisplayRefreshMonitor* monitorForDisplayID(PlatformDisplayID) const;
    60 
    61     DisplayRefreshMonitor* createMonitorForClient(DisplayRefreshMonitorClient&);
     61    DisplayRefreshMonitor* monitorForClient(DisplayRefreshMonitorClient&);
    6262
    6363    struct DisplayRefreshMonitorWrapper {
  • trunk/Source/WebCore/platform/graphics/GraphicsLayerUpdater.cpp

    r202399 r253299  
    3636    : m_client(client)
    3737{
    38     DisplayRefreshMonitorManager::sharedManager().registerClient(*this);
    3938    DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this);
    4039    DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this);
  • trunk/Source/WebCore/platform/graphics/ios/DisplayRefreshMonitorIOS.mm

    r237266 r253299  
    4141
    4242- (id)initWithMonitor:(DisplayRefreshMonitorIOS*)monitor;
     43- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond;
    4344- (void)handleDisplayLink:(CADisplayLink *)sender;
    4445- (void)invalidate;
     
    6465    ASSERT(!m_displayLink); // -invalidate should have been called already.
    6566    [super dealloc];
     67}
     68
     69- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond
     70{
     71    m_displayLink.preferredFramesPerSecond = preferredFramesPerSecond;
    6672}
    6773
  • trunk/Source/WebKit/ChangeLog

    r253297 r253299  
     12019-12-09  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Throttling requestAnimationFrame should be controlled by RenderingUpdateScheduler
     4        https://bugs.webkit.org/show_bug.cgi?id=204713
     5
     6        Reviewed by Simon Fraser.
     7
     8        Create an IPC message on the DrawingArea to send a message from the
     9        WebProcess to the UIProcess to setPreferredFramesPerSecond of the
     10        DisplayRefreshMonitor.
     11
     12        * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h:
     13        * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.messages.in:
     14
     15        * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
     16        (-[WKOneShotDisplayLinkHandler setPreferredFramesPerSecond:]):
     17        (WebKit::RemoteLayerTreeDrawingAreaProxy::setPreferredFramesPerSecond):
     18        Set the preferredFramesPerSecond of the CADisplayLink.
     19
     20        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.h:
     21        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.mm:
     22        (WebKit::RemoteLayerTreeDisplayRefreshMonitor::setPreferredFramesPerSecond):
     23        Delegate the call to RemoteLayerTreeDrawingArea.
     24
     25        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h:
     26        * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm:
     27        (WebKit::RemoteLayerTreeDrawingArea::setPreferredFramesPerSecond):
     28        Send the IPC message from the WebProcess to the UIProcess.
     29
    1302019-12-09  youenn fablet  <youenn@apple.com>
    231
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h

    r249093 r253299  
    2929#include "RemoteLayerTreeHost.h"
    3030#include "TransactionID.h"
     31#include <WebCore/AnimationFrameRate.h>
    3132#include <WebCore/FloatPoint.h>
    3233#include <WebCore/IntPoint.h>
     
    9899
    99100    // Message handlers
     101    void setPreferredFramesPerSecond(WebCore::FramesPerSecond);
    100102    void willCommitLayerTree(TransactionID);
    101103    void commitLayerTree(const RemoteLayerTreeTransaction&, const RemoteScrollingCoordinatorTransaction&);
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.messages.in

    r252655 r253299  
    2222
    2323messages -> RemoteLayerTreeDrawingAreaProxy : DrawingAreaProxy NotRefCounted {
     24    void SetPreferredFramesPerSecond(unsigned preferredFramesPerSecond)
    2425    void WillCommitLayerTree(WebKit::TransactionID transactionID)
    2526    void CommitLayerTree(WebKit::RemoteLayerTreeTransaction layerTreeTransaction, WebKit::RemoteScrollingCoordinatorTransaction scrollingTreeTransaction)
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm

    r253157 r253299  
    5050
    5151- (id)initWithDrawingAreaProxy:(WebKit::RemoteLayerTreeDrawingAreaProxy*)drawingAreaProxy;
     52- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond;
    5253- (void)displayLinkFired:(CADisplayLink *)sender;
    5354- (void)invalidate;
     
    7778}
    7879
     80- (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond
     81{
     82    _displayLink.preferredFramesPerSecond = preferredFramesPerSecond;
     83}
     84
    7985- (void)displayLinkFired:(CADisplayLink *)sender
    8086{
     
    182188    send(Messages::DrawingArea::UpdateGeometry(m_size, false /* flushSynchronously */, MachSendRight()));
    183189    m_isWaitingForDidUpdateGeometry = true;
     190}
     191
     192void RemoteLayerTreeDrawingAreaProxy::setPreferredFramesPerSecond(FramesPerSecond preferredFramesPerSecond)
     193{
     194#if PLATFORM(IOS_FAMILY)
     195    [displayLinkHandler() setPreferredFramesPerSecond:preferredFramesPerSecond];
     196#else
     197    UNUSED_PARAM(preferredFramesPerSecond);
     198#endif
    184199}
    185200
  • trunk/Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.h

    r250165 r253299  
    2929
    3030#include "RemoteLayerTreeDrawingArea.h"
     31#include <WebCore/AnimationFrameRate.h>
    3132#include <WebCore/DisplayRefreshMonitor.h>
    3233
     
    4243    virtual ~RemoteLayerTreeDisplayRefreshMonitor();
    4344
     45    void setPreferredFramesPerSecond(WebCore::FramesPerSecond) override;
    4446    bool requestRefreshCallback() override;
    4547
  • trunk/Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDisplayRefreshMonitor.mm

    r250165 r253299  
    4444}
    4545
     46void RemoteLayerTreeDisplayRefreshMonitor::setPreferredFramesPerSecond(FramesPerSecond preferredFramesPerSecond)
     47{
     48    if (m_drawingArea)
     49        m_drawingArea->setPreferredFramesPerSecond(preferredFramesPerSecond);
     50}
     51
    4652bool RemoteLayerTreeDisplayRefreshMonitor::requestRefreshCallback()
    4753{
  • trunk/Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.h

    r249961 r253299  
    3030#include "GraphicsLayerCARemote.h"
    3131#include "RemoteLayerTreeTransaction.h"
     32#include <WebCore/AnimationFrameRate.h>
    3233#include <WebCore/GraphicsLayerClient.h>
    3334#include <WebCore/Timer.h>
     
    7475    RefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(WebCore::PlatformDisplayID) override;
    7576    void willDestroyDisplayRefreshMonitor(WebCore::DisplayRefreshMonitor*);
     77    void setPreferredFramesPerSecond(WebCore::FramesPerSecond);
    7678
    7779    bool shouldUseTiledBackingForFrameView(const WebCore::FrameView&) override;
  • trunk/Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm

    r250165 r253299  
    127127}
    128128
     129void RemoteLayerTreeDrawingArea::setPreferredFramesPerSecond(FramesPerSecond preferredFramesPerSecond)
     130{
     131    send(Messages::RemoteLayerTreeDrawingAreaProxy::SetPreferredFramesPerSecond(preferredFramesPerSecond));
     132}
     133
    129134void RemoteLayerTreeDrawingArea::updateRootLayers()
    130135{
Note: See TracChangeset for help on using the changeset viewer.