WebKit Bugzilla
Attachment 361947 Details for
Bug 177484
: requestAnimationFrame should execute before the next frame
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-177484-20190213153131.patch (text/plain), 43.37 KB, created by
Said Abou-Hallawa
on 2019-02-13 15:31:32 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Said Abou-Hallawa
Created:
2019-02-13 15:31:32 PST
Size:
43.37 KB
patch
obsolete
>Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 241436) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,15 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add tracing signposts for requestAnimationFrame scheduling and flushing >+ the layers interval. >+ >+ * wtf/SystemTracing.h: >+ > 2019-02-12 Tim Horton <timothy_horton@apple.com> > > Remove WKLegacyPDFView >Index: Source/WTF/wtf/SystemTracing.h >=================================================================== >--- Source/WTF/wtf/SystemTracing.h (revision 241436) >+++ Source/WTF/wtf/SystemTracing.h (working copy) >@@ -75,6 +75,11 @@ enum TracePointCode { > DisplayListRecordEnd, > DisplayRefreshDispatchingToMainThread, > >+ ScheduleRenderingUpdate, >+ TriggerRenderingUpdate, >+ RenderingUpdateStart, >+ RenderingUpdateEnd, >+ > WebKitRange = 10000, > WebHTMLViewPaintStart, > WebHTMLViewPaintEnd, >Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 241436) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,75 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This change fixes two issues with animation timing: >+ >+ 1. Calling the requestAnimationFrame callbacks would have happened when >+ the DisplayLink fires. This may have happened even if the frame is >+ missed and no display is committed. >+ >+ 2. Style changes and layout triggered by script could trigger painting >+ at more than 60fps. CoreAnimation commits could happen at more than >+ 60fps, although WindowServer will throttle those, and only some will >+ be shown on the screen. >+ >+ This change introduces a new paint scheduling model where painting is driven >+ by a "RenderingScheduler", which only triggers paints once per 16.7ms frame. >+ >+ Code that previously scheduled a compositing layer flush now schedules a >+ "render", and that render is driven by a DisplayRefreshMonitor callback. >+ When the render happens, we service requestAnimationFrame callbacks, >+ intersection observations and Web Animations 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: >+ * animation/DocumentAnimationScheduler.cpp: >+ (WebCore::DocumentAnimationScheduler::unscheduleWebAnimationsResolution): >+ (WebCore::DocumentAnimationScheduler::displayRefreshFired): >+ (WebCore::DocumentAnimationScheduler::scheduleScriptedAnimationResolution): Deleted. >+ * animation/DocumentAnimationScheduler.h: >+ * dom/Document.cpp: >+ (WebCore::Document::callRequestAnimationFrameCallbacks): >+ * dom/Document.h: >+ * dom/ScriptedAnimationController.cpp: >+ (WebCore::ScriptedAnimationController::callRequestAnimationFrameCallbacks): >+ (WebCore::ScriptedAnimationController::scheduleAnimation): >+ (WebCore::ScriptedAnimationController::animationTimerFired): >+ (WebCore::ScriptedAnimationController::documentAnimationSchedulerDidFire): >+ (WebCore::ScriptedAnimationController::serviceScriptedAnimations): Deleted. >+ * dom/ScriptedAnimationController.h: >+ * page/FrameTree.cpp: >+ * page/Page.cpp: >+ (WebCore::Page::processPreLayoutActions): >+ (WebCore::Page::processPreRenderActions): >+ (WebCore::Page::renderingScheduler): >+ (WebCore::Page::willDisplayPage): Deleted. >+ * page/Page.h: >+ * page/PageOverlayController.cpp: >+ (WebCore::PageOverlayController::didChangeViewExposedRect): >+ (WebCore::PageOverlayController::notifyFlushRequired): >+ * page/RenderingScheduler.cpp: Added. >+ (WebCore::RenderingScheduler::RenderingScheduler): >+ (WebCore::RenderingScheduler::scheduleRender): >+ (WebCore::RenderingScheduler::startTimer): >+ (WebCore::RenderingScheduler::clearTimer): >+ (WebCore::RenderingScheduler::windowScreenDidChange): >+ (WebCore::RenderingScheduler::createDisplayRefreshMonitor const): >+ (WebCore::RenderingScheduler::displayRefreshFired): >+ * page/RenderingScheduler.h: Added. >+ (WebCore::RenderingScheduler::create): >+ * page/mac/ServicesOverlayController.mm: >+ (WebCore::ServicesOverlayController::Highlight::notifyFlushRequired): >+ * rendering/RenderLayerCompositor.cpp: >+ (WebCore::RenderLayerCompositor::scheduleLayerFlushNow): >+ > 2019-02-13 Antoine Quint <graouts@apple.com> > > Support simulated mouse events on iOS based on a PlatformTouchEvent >Index: Source/WebCore/Sources.txt >=================================================================== >--- Source/WebCore/Sources.txt (revision 241436) >+++ Source/WebCore/Sources.txt (working copy) >@@ -1535,6 +1535,7 @@ page/ProcessWarming.cpp > page/Quirks.cpp > page/RemoteDOMWindow.cpp > page/RemoteFrame.cpp >+page/RenderingScheduler.cpp > page/ResourceUsageOverlay.cpp > page/ResourceUsageThread.cpp > page/RuntimeEnabledFeatures.cpp >Index: Source/WebCore/WebCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/WebCore/WebCore.xcodeproj/project.pbxproj (revision 241436) >+++ Source/WebCore/WebCore.xcodeproj/project.pbxproj (working copy) >@@ -1780,6 +1780,7 @@ > 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 /* RenderingScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 556C7C4722123942009B06CA /* RenderingScheduler.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, ); }; }; >@@ -8644,6 +8645,8 @@ > 555130001E7CCCCA00A69E38 /* DecodingOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecodingOptions.h; sourceTree = "<group>"; }; > 555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecoderCG.cpp; sourceTree = "<group>"; }; > 555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDecoderCG.h; sourceTree = "<group>"; }; >+ 556C7C4722123942009B06CA /* RenderingScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderingScheduler.h; sourceTree = "<group>"; }; >+ 556C7C4922123943009B06CA /* RenderingScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderingScheduler.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>"; }; >@@ -20488,6 +20491,8 @@ > 46BCBBC3208500A700710638 /* RemoteDOMWindow.idl */, > 46B9518C207D632900A7D2DD /* RemoteFrame.cpp */, > 46B95192207D632E00A7D2DD /* RemoteFrame.h */, >+ 556C7C4922123943009B06CA /* RenderingScheduler.cpp */, >+ 556C7C4722123942009B06CA /* RenderingScheduler.h */, > A5071E821C56D079009951BE /* ResourceUsageData.h */, > ADBAD6EC1BCDD95000381325 /* ResourceUsageOverlay.cpp */, > ADBAD6ED1BCDD95000381325 /* ResourceUsageOverlay.h */, >@@ -31251,6 +31256,7 @@ > BCEA4876097D93020094C9E4 /* RenderImage.h in Headers */, > 08F2F00A1213E61700DCEC48 /* RenderImageResource.h in Headers */, > 08641D4812142F7D008DE9F6 /* RenderImageResourceStyleImage.h in Headers */, >+ 556C7C4B22123997009B06CA /* RenderingScheduler.h in Headers */, > BCEA4878097D93020094C9E4 /* RenderInline.h in Headers */, > B595FF471824CEE300FF51CD /* RenderIterator.h in Headers */, > BCEA487A097D93020094C9E4 /* RenderLayer.h in Headers */, >Index: Source/WebCore/animation/DocumentAnimationScheduler.cpp >=================================================================== >--- Source/WebCore/animation/DocumentAnimationScheduler.cpp (revision 241436) >+++ Source/WebCore/animation/DocumentAnimationScheduler.cpp (working copy) >@@ -67,15 +67,7 @@ bool DocumentAnimationScheduler::schedul > void DocumentAnimationScheduler::unscheduleWebAnimationsResolution() > { > m_scheduledWebAnimationsResolution = false; >- >- if (!m_scheduledScriptedAnimationResolution) >- DisplayRefreshMonitorManager::sharedManager().unregisterClient(*this); >-} >- >-bool DocumentAnimationScheduler::scheduleScriptedAnimationResolution() >-{ >- m_scheduledScriptedAnimationResolution = true; >- return DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this); >+ DisplayRefreshMonitorManager::sharedManager().unregisterClient(*this); > } > > void DocumentAnimationScheduler::displayRefreshFired() >@@ -94,12 +86,6 @@ void DocumentAnimationScheduler::display > m_document->timeline().documentAnimationSchedulerDidFire(); > } > >- if (m_scheduledScriptedAnimationResolution) { >- m_scheduledScriptedAnimationResolution = false; >- if (auto* scriptedAnimationController = m_document->scriptedAnimationController()) >- scriptedAnimationController->documentAnimationSchedulerDidFire(); >- } >- > m_isFiring = false; > } > >Index: Source/WebCore/animation/DocumentAnimationScheduler.h >=================================================================== >--- Source/WebCore/animation/DocumentAnimationScheduler.h (revision 241436) >+++ Source/WebCore/animation/DocumentAnimationScheduler.h (working copy) >@@ -59,7 +59,6 @@ private: > > RefPtr<Document> m_document; > bool m_scheduledWebAnimationsResolution { false }; >- bool m_scheduledScriptedAnimationResolution { false }; > bool m_isFiring { false }; > Seconds m_lastTimestamp { 0_s }; > >Index: Source/WebCore/dom/Document.cpp >=================================================================== >--- Source/WebCore/dom/Document.cpp (revision 241436) >+++ Source/WebCore/dom/Document.cpp (working copy) >@@ -6293,6 +6293,12 @@ void Document::resumeScriptedAnimationCo > m_scriptedAnimationController->resume(); > } > >+void Document::serviceRequestAnimationFrameCallbacks() >+{ >+ if (m_scriptedAnimationController) >+ m_scriptedAnimationController->serviceRequestAnimationFrameCallbacks(domWindow()->nowTimestamp()); >+} >+ > void Document::windowScreenDidChange(PlatformDisplayID displayID) > { > #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >Index: Source/WebCore/dom/Document.h >=================================================================== >--- Source/WebCore/dom/Document.h (revision 241436) >+++ Source/WebCore/dom/Document.h (working copy) >@@ -1067,7 +1067,9 @@ public: > ScriptedAnimationController* scriptedAnimationController() { return m_scriptedAnimationController.get(); } > void suspendScriptedAnimationControllerCallbacks(); > void resumeScriptedAnimationControllerCallbacks(); >- >+ >+ void serviceRequestAnimationFrameCallbacks(); >+ > void windowScreenDidChange(PlatformDisplayID); > > void finishedParsing(); >Index: Source/WebCore/dom/ScriptedAnimationController.cpp >=================================================================== >--- Source/WebCore/dom/ScriptedAnimationController.cpp (revision 241436) >+++ Source/WebCore/dom/ScriptedAnimationController.cpp (working copy) >@@ -189,7 +189,7 @@ void ScriptedAnimationController::cancel > } > } > >-void ScriptedAnimationController::serviceScriptedAnimations(double timestamp) >+void ScriptedAnimationController::serviceRequestAnimationFrameCallbacks(double timestamp) > { > if (!m_callbacks.size() || m_suspendCount || !requestAnimationFrameEnabled()) > return; >@@ -210,24 +210,21 @@ void ScriptedAnimationController::servic > Ref<Document> protectedDocument(*m_document); > > for (auto& callback : callbacks) { >- if (!callback->m_firedOrCancelled) { >- callback->m_firedOrCancelled = true; >- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id); >- if (callback->m_useLegacyTimeBase) >- callback->handleEvent(legacyHighResNowMs); >- else >- callback->handleEvent(highResNowMs); >- InspectorInstrumentation::didFireAnimationFrame(cookie); >- } >+ if (callback->m_firedOrCancelled) >+ continue; >+ callback->m_firedOrCancelled = true; >+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id); >+ if (callback->m_useLegacyTimeBase) >+ callback->handleEvent(legacyHighResNowMs); >+ else >+ callback->handleEvent(highResNowMs); >+ InspectorInstrumentation::didFireAnimationFrame(cookie); > } > > // Remove any callbacks we fired from the list of pending callbacks. >- for (size_t i = 0; i < m_callbacks.size();) { >- if (m_callbacks[i]->m_firedOrCancelled) >- m_callbacks.remove(i); >- else >- ++i; >- } >+ m_callbacks.removeAllMatching([](auto& callback) { >+ return callback->m_firedOrCancelled; >+ }); > > if (m_callbacks.size()) > scheduleAnimation(); >@@ -262,8 +259,10 @@ void ScriptedAnimationController::schedu > > #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) > if (!m_isUsingTimer && !isThrottled()) { >- if (m_document->animationScheduler().scheduleScriptedAnimationResolution()) >+ if (auto* page = this->page()) { >+ page->renderingScheduler().scheduleRender(); > return; >+ } > > m_isUsingTimer = true; > } >@@ -292,14 +291,14 @@ void ScriptedAnimationController::schedu > 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()); >+ serviceRequestAnimationFrameCallbacks(m_document->animationScheduler().lastTimestamp().seconds()); > } > #endif > >Index: Source/WebCore/dom/ScriptedAnimationController.h >=================================================================== >--- Source/WebCore/dom/ScriptedAnimationController.h (revision 241436) >+++ Source/WebCore/dom/ScriptedAnimationController.h (working copy) >@@ -52,7 +52,7 @@ public: > > CallbackId registerCallback(Ref<RequestAnimationFrameCallback>&&); > void cancelCallback(CallbackId); >- void serviceScriptedAnimations(double timestamp); >+ void serviceRequestAnimationFrameCallbacks(double timestamp); > > void suspend(); > void resume(); >Index: Source/WebCore/page/FrameTree.cpp >=================================================================== >--- Source/WebCore/page/FrameTree.cpp (revision 241436) >+++ Source/WebCore/page/FrameTree.cpp (working copy) >@@ -23,6 +23,7 @@ > > #include "Document.h" > #include "Frame.h" >+#include "FrameLoader.h" > #include "FrameView.h" > #include "HTMLFrameOwnerElement.h" > #include "Page.h" >Index: Source/WebCore/page/Page.cpp >=================================================================== >--- Source/WebCore/page/Page.cpp (revision 241436) >+++ Source/WebCore/page/Page.cpp (working copy) >@@ -1112,13 +1112,6 @@ void Page::didFinishLoad() > m_performanceMonitor->didFinishLoad(); > } > >-void Page::willDisplayPage() >-{ >-#if ENABLE(INTERSECTION_OBSERVER) >- updateIntersectionObservations(); >-#endif >-} >- > bool Page::isOnlyNonUtilityPage() const > { > return !isUtilityPage() && nonUtilityPageCount == 1; >@@ -1260,6 +1253,26 @@ void Page::removeActivityStateChangeObse > m_activityStateChangeObservers.remove(&observer); > } > >+void Page::processPreLayoutActions() >+{ >+ Vector<RefPtr<Document>> documents; >+ >+ // The requestAnimationFrame callbacks may change the frame hierarchy of the page >+ forEachDocument([&documents] (Document& document) { >+ documents.append(&document); >+ }); >+ >+ for (auto& document : documents) >+ document->serviceRequestAnimationFrameCallbacks(); >+} >+ >+void Page::processPreRenderActions() >+{ >+#if ENABLE(INTERSECTION_OBSERVER) >+ updateIntersectionObservations(); >+#endif >+} >+ > #if ENABLE(INTERSECTION_OBSERVER) > void Page::addDocumentNeedingIntersectionObservationUpdate(Document& document) > { >@@ -2815,6 +2828,13 @@ void Page::didChangeMainDocument() > #endif > } > >+RenderingScheduler& Page::renderingScheduler() >+{ >+ if (!m_renderingScheduler) >+ m_renderingScheduler = RenderingScheduler::create(*this); >+ return *m_renderingScheduler; >+} >+ > void Page::forEachDocument(const Function<void(Document&)>& functor) > { > for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) { >Index: Source/WebCore/page/Page.h >=================================================================== >--- Source/WebCore/page/Page.h (revision 241436) >+++ Source/WebCore/page/Page.h (working copy) >@@ -32,6 +32,7 @@ > #include "Pagination.h" > #include "RTCController.h" > #include "Region.h" >+#include "RenderingScheduler.h" > #include "ScrollTypes.h" > #include "Supplementable.h" > #include "Timer.h" >@@ -261,6 +262,8 @@ public: > > PerformanceMonitor* performanceMonitor() { return m_performanceMonitor.get(); } > >+ RenderingScheduler& renderingScheduler(); >+ > ValidationMessageClient* validationMessageClient() const { return m_validationMessageClient.get(); } > void updateValidationBubbleStateIfNeeded(); > >@@ -333,8 +336,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); >@@ -464,6 +465,9 @@ public: > WEBCORE_EXPORT void addActivityStateChangeObserver(ActivityStateChangeObserver&); > WEBCORE_EXPORT void removeActivityStateChangeObserver(ActivityStateChangeObserver&); > >+ WEBCORE_EXPORT void processPreLayoutActions(); >+ WEBCORE_EXPORT void processPreRenderActions(); >+ > #if ENABLE(INTERSECTION_OBSERVER) > void addDocumentNeedingIntersectionObservationUpdate(Document&); > void scheduleForcedIntersectionObservationUpdate(Document&); >@@ -860,6 +864,8 @@ private: > int m_headerHeight { 0 }; > int m_footerHeight { 0 }; > >+ std::unique_ptr<RenderingScheduler> m_renderingScheduler; >+ > HashSet<RenderObject*> m_relevantUnpaintedRenderObjects; > Region m_topRelevantPaintedRegion; > Region m_bottomRelevantPaintedRegion; >Index: Source/WebCore/page/PageOverlayController.cpp >=================================================================== >--- Source/WebCore/page/PageOverlayController.cpp (revision 241436) >+++ Source/WebCore/page/PageOverlayController.cpp (working copy) >@@ -317,7 +317,7 @@ void PageOverlayController::didChangeDev > > void PageOverlayController::didChangeViewExposedRect() > { >- m_page.chrome().client().scheduleCompositingLayerFlush(); >+ m_page.renderingScheduler().scheduleRender(); > } > > void PageOverlayController::didScrollFrame(Frame& frame) >@@ -411,7 +411,7 @@ float PageOverlayController::deviceScale > > void PageOverlayController::notifyFlushRequired(const WebCore::GraphicsLayer*) > { >- m_page.chrome().client().scheduleCompositingLayerFlush(); >+ m_page.renderingScheduler().scheduleRender(); > } > > void PageOverlayController::didChangeOverlayFrame(PageOverlay& overlay) >Index: Source/WebCore/page/RenderingScheduler.cpp >=================================================================== >--- Source/WebCore/page/RenderingScheduler.cpp (nonexistent) >+++ Source/WebCore/page/RenderingScheduler.cpp (working copy) >@@ -0,0 +1,96 @@ >+/* >+ * 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 "RenderingScheduler.h" >+ >+#include "Chrome.h" >+#include "ChromeClient.h" >+#include "DisplayRefreshMonitorManager.h" >+#include "Page.h" >+#include <wtf/SystemTracing.h> >+ >+namespace WebCore { >+ >+RenderingScheduler::RenderingScheduler(Page& page) >+ : m_page(page) >+{ >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+ windowScreenDidChange(page.chrome().displayID()); >+#endif >+} >+ >+void RenderingScheduler::scheduleRender() >+{ >+ if (m_scheduled) >+ return; >+ >+ tracePoint(ScheduleRenderingUpdate); >+ >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+ if (!DisplayRefreshMonitorManager::sharedManager().scheduleAnimation(*this)) >+#endif >+ startTimer(Seconds(1.0 / 60)); >+ >+ m_scheduled = true; >+} >+ >+void RenderingScheduler::startTimer(Seconds delay) >+{ >+ ASSERT(!m_refreshTimer); >+ m_refreshTimer = std::make_unique<Timer>(*this, &RenderingScheduler::displayRefreshFired); >+ m_refreshTimer->startOneShot(delay); >+} >+ >+void RenderingScheduler::clearTimer() >+{ >+ m_refreshTimer = nullptr; >+} >+ >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+void RenderingScheduler::windowScreenDidChange(PlatformDisplayID displayID) >+{ >+ DisplayRefreshMonitorManager::sharedManager().windowScreenDidChange(displayID, *this); >+} >+ >+RefPtr<DisplayRefreshMonitor> RenderingScheduler::createDisplayRefreshMonitor(PlatformDisplayID displayID) const >+{ >+ if (auto monitor = m_page.chrome().client().createDisplayRefreshMonitor(displayID)) >+ return monitor; >+ >+ return DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(displayID); >+} >+#endif >+ >+void RenderingScheduler::displayRefreshFired() >+{ >+ tracePoint(TriggerRenderingUpdate); >+ >+ m_page.chrome().client().scheduleCompositingLayerFlush(); >+ clearTimer(); >+ m_scheduled = false; >+} >+ >+} >Index: Source/WebCore/page/RenderingScheduler.h >=================================================================== >--- Source/WebCore/page/RenderingScheduler.h (nonexistent) >+++ Source/WebCore/page/RenderingScheduler.h (working copy) >@@ -0,0 +1,71 @@ >+/* >+ * 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. >+ */ >+ >+#pragma once >+ >+#include "DisplayRefreshMonitorClient.h" >+#include <wtf/Seconds.h> >+ >+namespace WebCore { >+ >+class Page; >+class Timer; >+ >+class RenderingScheduler >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+ : public DisplayRefreshMonitorClient >+#endif >+{ >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ static std::unique_ptr<RenderingScheduler> create(Page& page) >+ { >+ return std::make_unique<RenderingScheduler>(page); >+ } >+ >+ RenderingScheduler(Page&); >+ void scheduleRender(); >+ >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+ void windowScreenDidChange(PlatformDisplayID); >+#endif >+ >+private: >+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) >+ RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const final; >+ void displayRefreshFired() final; >+#else >+ void displayRefreshFired(); >+#endif >+ >+ void startTimer(Seconds); >+ void clearTimer(); >+ >+ Page& m_page; >+ std::unique_ptr<Timer> m_refreshTimer; >+ bool m_scheduled { false }; >+}; >+ >+} >Index: Source/WebCore/page/mac/ServicesOverlayController.mm >=================================================================== >--- Source/WebCore/page/mac/ServicesOverlayController.mm (revision 241436) >+++ Source/WebCore/page/mac/ServicesOverlayController.mm (working copy) >@@ -121,7 +121,7 @@ void ServicesOverlayController::Highligh > if (!m_controller) > return; > >- m_controller->page().chrome().client().scheduleCompositingLayerFlush(); >+ m_controller->page().renderingScheduler().scheduleRender(); > } > > void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior) >Index: Source/WebCore/rendering/RenderLayerCompositor.cpp >=================================================================== >--- Source/WebCore/rendering/RenderLayerCompositor.cpp (revision 241436) >+++ Source/WebCore/rendering/RenderLayerCompositor.cpp (working copy) >@@ -430,7 +430,7 @@ void RenderLayerCompositor::notifyFlushR > void RenderLayerCompositor::scheduleLayerFlushNow() > { > m_hasPendingLayerFlush = false; >- page().chrome().client().scheduleCompositingLayerFlush(); >+ page().renderingScheduler().scheduleRender(); > } > > void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle) >Index: Source/WebKit/ChangeLog >=================================================================== >--- Source/WebKit/ChangeLog (revision 241436) >+++ Source/WebKit/ChangeLog (working copy) >@@ -1,3 +1,29 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Handle the page-level rendering actions through two phases: one before >+ running the layout and the second is before committing the drawing. >+ >+ * WebProcess/WebPage/AcceleratedDrawingArea.cpp: >+ (WebKit::AcceleratedDrawingArea::updateBackingStoreState): >+ * WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp: >+ (WebKit::CoordinatedLayerTreeHost::layerFlushTimerFired): >+ * WebProcess/WebPage/DrawingAreaImpl.cpp: >+ (WebKit::DrawingAreaImpl::display): >+ * WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm: >+ (WebKit::RemoteLayerTreeDrawingArea::flushLayers): >+ * WebProcess/WebPage/WebPage.cpp: >+ (WebKit::WebPage::processPreLayoutActions): >+ (WebKit::WebPage::processPreRenderActions): >+ (WebKit::WebPage::willDisplayPage): Deleted. >+ * WebProcess/WebPage/WebPage.h: >+ * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm: >+ (WebKit::TiledCoreAnimationDrawingArea::flushLayers): >+ > 2019-02-13 Truitt Savell <tsavell@apple.com> > > Unreviewed, rolling out r241433. >Index: Source/WebKit/WebProcess/WebPage/AcceleratedDrawingArea.cpp >=================================================================== >--- Source/WebKit/WebProcess/WebPage/AcceleratedDrawingArea.cpp (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/AcceleratedDrawingArea.cpp (working copy) >@@ -253,10 +253,11 @@ void AcceleratedDrawingArea::updateBacki > > m_webPage.setDeviceScaleFactor(deviceScaleFactor); > m_webPage.setSize(size); >+ m_webPage.processPreLayoutActions(); > m_webPage.layoutIfNeeded(); > m_webPage.flushPendingEditorStateUpdate(); > m_webPage.scrollMainFrameIfNotAtMaxScrollPosition(scrollOffset); >- m_webPage.willDisplayPage(); >+ m_webPage.processPreRenderActions(); > > if (m_layerTreeHost) > m_layerTreeHost->sizeDidChange(m_webPage.size()); >Index: Source/WebKit/WebProcess/WebPage/DrawingAreaImpl.cpp >=================================================================== >--- Source/WebKit/WebProcess/WebPage/DrawingAreaImpl.cpp (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/DrawingAreaImpl.cpp (working copy) >@@ -398,6 +398,7 @@ void DrawingAreaImpl::display(UpdateInfo > ASSERT(!m_layerTreeHost); > ASSERT(!m_webPage.size().isEmpty()); > >+ m_webPage.processPreLayoutActions(); > m_webPage.layoutIfNeeded(); > m_webPage.flushPendingEditorStateUpdate(); > >@@ -406,7 +407,7 @@ void DrawingAreaImpl::display(UpdateInfo > if (m_layerTreeHost) > return; > >- m_webPage.willDisplayPage(); >+ m_webPage.processPreRenderActions(); > updateInfo.viewSize = m_webPage.size(); > updateInfo.deviceScaleFactor = m_webPage.corePage()->deviceScaleFactor(); > >Index: Source/WebKit/WebProcess/WebPage/WebPage.cpp >=================================================================== >--- Source/WebKit/WebProcess/WebPage/WebPage.cpp (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/WebPage.cpp (working copy) >@@ -3569,9 +3569,14 @@ void WebPage::didFlushLayerTreeAtTime(Mo > } > #endif > >-void WebPage::willDisplayPage() >+void WebPage::processPreLayoutActions() > { >- m_page->willDisplayPage(); >+ m_page->processPreLayoutActions(); >+} >+ >+void WebPage::processPreRenderActions() >+{ >+ m_page->processPreRenderActions(); > } > > WebInspector* WebPage::inspector(LazyCreationPolicy behavior) >Index: Source/WebKit/WebProcess/WebPage/WebPage.h >=================================================================== >--- Source/WebKit/WebProcess/WebPage/WebPage.h (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/WebPage.h (working copy) >@@ -300,7 +300,8 @@ public: > void didFlushLayerTreeAtTime(MonotonicTime); > #endif > >- void willDisplayPage(); >+ void processPreLayoutActions(); >+ void processPreRenderActions(); > > enum class LazyCreationPolicy { UseExistingOnly, CreateIfNeeded }; > >Index: Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp >=================================================================== >--- Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/CoordinatedLayerTreeHost.cpp (working copy) >@@ -189,7 +189,7 @@ void CoordinatedLayerTreeHost::layerFlus > > m_coordinator.syncDisplayState(); > m_webPage.flushPendingEditorStateUpdate(); >- m_webPage.willDisplayPage(); >+ m_webPage.processPreRenderActions(); > > if (!m_isValid || !m_coordinator.rootCompositingLayer()) > return; >Index: Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm >=================================================================== >--- Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteLayerTreeDrawingArea.mm (working copy) >@@ -347,8 +347,9 @@ void RemoteLayerTreeDrawingArea::flushLa > RemoteLayerBackingStoreCollection& backingStoreCollection = m_remoteLayerTreeContext->backingStoreCollection(); > backingStoreCollection.willFlushLayers(); > >+ m_webPage.processPreLayoutActions(); > m_webPage.layoutIfNeeded(); >- m_webPage.willDisplayPage(); >+ m_webPage.processPreRenderActions(); > > FloatRect visibleRect(FloatPoint(), m_viewSize); > if (m_scrolledViewExposedRect) >Index: Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm >=================================================================== >--- Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm (revision 241436) >+++ Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm (working copy) >@@ -59,6 +59,7 @@ > #import <pal/spi/cocoa/QuartzCoreSPI.h> > #import <wtf/MachSendRight.h> > #import <wtf/MainThread.h> >+#import <wtf/SystemTracing.h> > > #if ENABLE(ASYNC_SCROLLING) > #import <WebCore/AsyncScrollingCoordinator.h> >@@ -459,12 +460,15 @@ void TiledCoreAnimationDrawingArea::flus > if (layerTreeStateIsFrozen()) > return; > >+ TraceScope traceScope(RenderingUpdateStart, RenderingUpdateEnd); >+ > @autoreleasepool { > scaleViewToFitDocumentIfNeeded(); > >+ m_webPage.processPreLayoutActions(); > m_webPage.layoutIfNeeded(); > m_webPage.flushPendingEditorStateUpdate(); >- m_webPage.willDisplayPage(); >+ m_webPage.processPreRenderActions(); > > updateIntrinsicContentSizeIfNeeded(); > >Index: Source/WebKitLegacy/mac/ChangeLog >=================================================================== >--- Source/WebKitLegacy/mac/ChangeLog (revision 241436) >+++ Source/WebKitLegacy/mac/ChangeLog (working copy) >@@ -1,3 +1,15 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Call Page::processPreLayoutActions() before flushing the layers. >+ >+ * WebView/WebView.mm: >+ (-[WebView _viewWillDrawInternal]): >+ > 2019-02-12 Wenson Hsieh <wenson_hsieh@apple.com> > > Allow pages to trigger programmatic paste from script on iOS >Index: Source/WebKitLegacy/mac/WebView/WebView.mm >=================================================================== >--- Source/WebKitLegacy/mac/WebView/WebView.mm (revision 241436) >+++ Source/WebKitLegacy/mac/WebView/WebView.mm (working copy) >@@ -1621,8 +1621,13 @@ - (id)_initWithFrame:(NSRect)f frameName > - (void)_viewWillDrawInternal > { > Frame* frame = [self _mainCoreFrame]; >- if (frame && frame->view()) >+ if (frame && frame->view()) { >+ if (_private->page) >+ _private->page->processPreLayoutActions(); > frame->view()->updateLayoutAndStyleIfNeededRecursive(); >+ if (_private->page) >+ _private->page->processPreRenderActions(); >+ } > } > > + (NSArray *)_supportedMIMETypes >Index: Tools/ChangeLog >=================================================================== >--- Tools/ChangeLog (revision 241473) >+++ Tools/ChangeLog (working copy) >@@ -1,3 +1,12 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Tracing/SystemTracePoints.plist: >+ > 2019-02-13 John Wilander <wilander@apple.com> > > Store Ad Click Attribution requests in the network process >Index: Tools/Tracing/SystemTracePoints.plist >=================================================================== >--- Tools/Tracing/SystemTracePoints.plist (revision 241436) >+++ Tools/Tracing/SystemTracePoints.plist (working copy) >@@ -202,10 +202,44 @@ > <key>Component</key> > <string>47</string> > <key>Code</key> >+ <string>5025</string> >+ </dict> >+ >+ >+ <dict> >+ <key>Name</key> >+ <string>Schedule display refresh</string> >+ <key>Type</key> >+ <string>Impulse</string> >+ <key>Component</key> >+ <string>47</string> >+ <key>Code</key> > <string>5026</string> > </dict> > <dict> > <key>Name</key> >+ <string>Trigger display refresh</string> >+ <key>Type</key> >+ <string>Impulse</string> >+ <key>Component</key> >+ <string>47</string> >+ <key>Code</key> >+ <string>5027</string> >+ </dict> >+ <dict> >+ <key>Name</key> >+ <string>Update rendering</string> >+ <key>Type</key> >+ <string>Interval</string> >+ <key>Component</key> >+ <string>47</string> >+ <key>CodeBegin</key> >+ <string>5028</string> >+ <key>CodeEnd</key> >+ <string>5029</string> >+ </dict> >+ <dict> >+ <key>Name</key> > <string>Paint WebHTMLView</string> > <key>Type</key> > <string>Interval</string> >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 241436) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,14 @@ >+2019-02-13 Said Abou-Hallawa <sabouhallawa@apple.com> >+ >+ requestAnimationFrame should execute before the next frame >+ https://bugs.webkit.org/show_bug.cgi?id=177484 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * animations/animation-multiple-callbacks-timestamp.html: >+ * fast/animation/request-animation-frame-in-two-pages.html: >+ * legacy-animation-engine/animations/animation-multiple-callbacks-timestamp.html: >+ > 2019-02-13 Sihui Liu <sihui_liu@apple.com> > > Add two regression tests for reference cycle in IndexedDB >Index: LayoutTests/animations/animation-multiple-callbacks-timestamp.html >=================================================================== >--- LayoutTests/animations/animation-multiple-callbacks-timestamp.html (revision 241436) >+++ LayoutTests/animations/animation-multiple-callbacks-timestamp.html (working copy) >@@ -8,6 +8,7 @@ > var currentFrame = 0; > var timestamp1 = 0; > var failed = false; >+ const MaxFrames = 25; > > function finishTest() > { >@@ -22,10 +23,7 @@ > { > timestamp1 = timestamp; > >- const MaxFrames = 25; >- if (currentFrame == MaxFrames) >- finishTest(); >- else { >+ if (currentFrame < MaxFrames) { > requestAnimationFrame(doAnimation1); > requestAnimationFrame(doAnimation2); > } >@@ -35,9 +33,11 @@ > { > 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; > } >+ if (currentFrame == MaxFrames) >+ finishTest(); > } > > window.jsTestIsAsync = true; >Index: LayoutTests/fast/animation/request-animation-frame-in-two-pages.html >=================================================================== >--- LayoutTests/fast/animation/request-animation-frame-in-two-pages.html (revision 241436) >+++ LayoutTests/fast/animation/request-animation-frame-in-two-pages.html (working copy) >@@ -30,7 +30,6 @@ function onload() > > function raf() > { >- requestAnimationFrame(raf); > if (c == 10) { > src = "data:text/html, <script> c = 0; function raf() { requestAnimationFrame(raf); if (c++ == 10) window.close(); } requestAnimationFrame(raf); <\/script>"; > newWindow = window.open(src, "_blank"); >@@ -40,10 +39,13 @@ function onload() > } > if (c == 20) { > log("PASS"); >- if (window.testRunner) >+ if (window.testRunner) { > testRunner.notifyDone(); >+ return; >+ } > } > c++; >+ requestAnimationFrame(raf); > } > requestAnimationFrame(raf) > } >Index: LayoutTests/legacy-animation-engine/animations/animation-multiple-callbacks-timestamp.html >=================================================================== >--- LayoutTests/legacy-animation-engine/animations/animation-multiple-callbacks-timestamp.html (revision 241436) >+++ LayoutTests/legacy-animation-engine/animations/animation-multiple-callbacks-timestamp.html (working copy) >@@ -8,6 +8,7 @@ > var currentFrame = 0; > var timestamp1 = 0; > var failed = false; >+ var doAnimation2CallbackId; > > function finishTest() > { >@@ -23,11 +24,13 @@ > timestamp1 = timestamp; > > const MaxFrames = 25; >- if (currentFrame == MaxFrames) >+ if (currentFrame == MaxFrames) { >+ cancelAnimationFrame(doAnimation2CallbackId); > finishTest(); >+ } > else { > requestAnimationFrame(doAnimation1); >- requestAnimationFrame(doAnimation2); >+ doAnimation2CallbackId = requestAnimationFrame(doAnimation2); > } > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ews-watchlist
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 177484
:
356578
|
361620
|
361621
|
361622
|
361623
|
361718
|
361727
|
361743
|
361749
|
361750
|
361752
|
361756
|
361760
|
361764
|
361769
|
361775
|
361776
|
361779
|
361783
|
361947
|
361963
|
361970
|
361973
|
361974
|
362845
|
362847
|
362848
|
362849
|
362850
|
362851
|
363268
|
363274
|
363286
|
363295
|
363309
|
363313
|
363417
|
363419
|
363420
|
363831
|
363846
|
363850
|
363857
|
363862
|
363940
|
366413
|
366416
|
366417
|
366418
|
366427
|
366731
|
366736
|
366740
|
366745
|
367083
|
367091
|
367145
|
367151
|
367160
|
367186