Title: [226990] trunk/Source
Revision
226990
Author
[email protected]
Date
2018-01-16 11:46:40 -0800 (Tue, 16 Jan 2018)

Log Message

AVSampleBufferDisplayLayer should be flushed when application activates
https://bugs.webkit.org/show_bug.cgi?id=181623
<rdar://problem/36487738>

Reviewed by Darin Adler.

Source/WebCore:

No new tests, I wasn't able to reproduce it in a test.

* WebCore.xcodeproj/project.pbxproj:
* dom/Document.cpp:
(WebCore::Document::addApplicationStateChangeListener): New.
(WebCore::Document::removeApplicationStateChangeListener): Ditto.
(WebCore::Document::forEachApplicationStateChangeListener): Ditto.
* dom/Document.h:

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::registerWithDocument): Register for application state changes.
(WebCore::HTMLMediaElement::unregisterWithDocument): Unregister.
(WebCore::HTMLMediaElement::applicationWillResignActive): Pass through to the player.
(WebCore::HTMLMediaElement::applicationDidBecomeActive): Ditto.
* html/HTMLMediaElement.h:

* page/ApplicationStateChangeListener.h: Added.
(WebCore::ApplicationStateChangeListener::applicationWillResignActive):
(WebCore::ApplicationStateChangeListener::applicationDidBecomeActive):
* page/Page.cpp:
(WebCore::Page::forEachDocument):
(WebCore::Page::applicationWillResignActive):
(WebCore::Page::applicationDidEnterBackground):
(WebCore::Page::applicationWillEnterForeground):
(WebCore::Page::applicationDidBecomeActive):
* page/Page.h:
* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::applicationWillResignActive):
(WebCore::MediaPlayer::applicationDidBecomeActive):
* platform/graphics/MediaPlayer.h:
* platform/graphics/MediaPlayerPrivate.h:
(WebCore::MediaPlayerPrivateInterface::applicationWillResignActive):
(WebCore::MediaPlayerPrivateInterface::applicationDidBecomeActive):

* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::MediaPlayerPrivateMediaStreamAVFObjC): Switch
to release logging.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::~MediaPlayerPrivateMediaStreamAVFObjC): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::enqueueCorrectedVideoSample): Split out of enqueueVideoSample.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::enqueueVideoSample): Move code that updates
the display later to enqueueCorrectedVideoSample. Rearrange logic to the image painter sample
buffer has the correct timestamp.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::layerErrorDidChange): Switch to release logging.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::layerStatusDidChange): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::applicationDidBecomeActive): f the display
layer is in the "failed" state, flush the renderer and update the display mode.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::ensureLayers): Switch to release logging.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::load): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::cancelLoad): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::prepareToPlay): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateDisplayMode): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::play): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::pause): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setVolume): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setMuted): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateReadyState) Ditto.:
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::logChannel const): Ditto.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateSampleTimes): Deleted.

Source/WebKit:

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::applicationWillResignActive): Call page.
(WebKit::WebPage::applicationDidEnterBackground): Ditto, let it call libWebRTCProvider.
(WebKit::WebPage::applicationWillEnterForeground): Call page.
(WebKit::WebPage::applicationDidBecomeActive): Ditto, let it call libWebRTCProvider.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (226989 => 226990)


--- trunk/Source/WebCore/ChangeLog	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/ChangeLog	2018-01-16 19:46:40 UTC (rev 226990)
@@ -1,3 +1,71 @@
+2018-01-16  Eric Carlson  <[email protected]>
+
+        AVSampleBufferDisplayLayer should be flushed when application activates
+        https://bugs.webkit.org/show_bug.cgi?id=181623
+        <rdar://problem/36487738>
+
+        Reviewed by Darin Adler.
+
+        No new tests, I wasn't able to reproduce it in a test.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/Document.cpp:
+        (WebCore::Document::addApplicationStateChangeListener): New.
+        (WebCore::Document::removeApplicationStateChangeListener): Ditto.
+        (WebCore::Document::forEachApplicationStateChangeListener): Ditto.
+        * dom/Document.h:
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::registerWithDocument): Register for application state changes.
+        (WebCore::HTMLMediaElement::unregisterWithDocument): Unregister.
+        (WebCore::HTMLMediaElement::applicationWillResignActive): Pass through to the player.
+        (WebCore::HTMLMediaElement::applicationDidBecomeActive): Ditto.
+        * html/HTMLMediaElement.h:
+
+        * page/ApplicationStateChangeListener.h: Added.
+        (WebCore::ApplicationStateChangeListener::applicationWillResignActive):
+        (WebCore::ApplicationStateChangeListener::applicationDidBecomeActive):
+        * page/Page.cpp:
+        (WebCore::Page::forEachDocument):
+        (WebCore::Page::applicationWillResignActive):
+        (WebCore::Page::applicationDidEnterBackground):
+        (WebCore::Page::applicationWillEnterForeground):
+        (WebCore::Page::applicationDidBecomeActive):
+        * page/Page.h:
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::applicationWillResignActive):
+        (WebCore::MediaPlayer::applicationDidBecomeActive):
+        * platform/graphics/MediaPlayer.h:
+        * platform/graphics/MediaPlayerPrivate.h:
+        (WebCore::MediaPlayerPrivateInterface::applicationWillResignActive):
+        (WebCore::MediaPlayerPrivateInterface::applicationDidBecomeActive):
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::MediaPlayerPrivateMediaStreamAVFObjC): Switch
+        to release logging.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::~MediaPlayerPrivateMediaStreamAVFObjC): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::enqueueCorrectedVideoSample): Split out of enqueueVideoSample.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::enqueueVideoSample): Move code that updates
+        the display later to enqueueCorrectedVideoSample. Rearrange logic to the image painter sample
+        buffer has the correct timestamp.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::layerErrorDidChange): Switch to release logging.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::layerStatusDidChange): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::applicationDidBecomeActive): f the display
+        layer is in the "failed" state, flush the renderer and update the display mode.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::ensureLayers): Switch to release logging.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::load): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::cancelLoad): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::prepareToPlay): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateDisplayMode): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::play): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::pause): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setVolume): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::setMuted): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateReadyState) Ditto.:
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::logChannel const): Ditto.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateSampleTimes): Deleted.
+
 2018-01-16  Michael Catanzaro  <[email protected]>
 
         PAL should link to _javascript_Core rather than WTF

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (226989 => 226990)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-01-16 19:46:40 UTC (rev 226990)
@@ -218,6 +218,7 @@
 		07E9E13018F62B370011A3A4 /* InbandMetadataTextTrackPrivateAVF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07E9E12F18F62B370011A3A4 /* InbandMetadataTextTrackPrivateAVF.cpp */; };
 		07EE76EC1BE96DB000F89133 /* MockRealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07EE76EA1BE96DB000F89133 /* MockRealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07EE76EF1BEA619800F89133 /* MockRealtimeVideoSourceMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */; };
+		07F04A942006B1E300AE2A0A /* ApplicationStateChangeListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 07F04A92200684BC00AE2A0A /* ApplicationStateChangeListener.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07F876841AD580F900905849 /* MediaPlaybackTargetContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 07F876831AD4A94500905849 /* MediaPlaybackTargetContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07F944161864D046005D31CB /* PlatformMediaSessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = CDAE8C081746B95700532D78 /* PlatformMediaSessionManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07FE99DD18807A7D00256648 /* MediaElementSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 07FE99DB18807A7D00256648 /* MediaElementSession.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5277,6 +5278,7 @@
 		07EE76EA1BE96DB000F89133 /* MockRealtimeVideoSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeVideoSource.h; sourceTree = "<group>"; };
 		07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeVideoSourceMac.h; sourceTree = "<group>"; };
 		07EE76EE1BEA619800F89133 /* MockRealtimeVideoSourceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MockRealtimeVideoSourceMac.mm; sourceTree = "<group>"; };
+		07F04A92200684BC00AE2A0A /* ApplicationStateChangeListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplicationStateChangeListener.h; sourceTree = "<group>"; };
 		07F876831AD4A94500905849 /* MediaPlaybackTargetContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPlaybackTargetContext.h; sourceTree = "<group>"; };
 		07FE99DA18807A7D00256648 /* MediaElementSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaElementSession.cpp; sourceTree = "<group>"; };
 		07FE99DB18807A7D00256648 /* MediaElementSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaElementSession.h; sourceTree = "<group>"; };
@@ -18589,6 +18591,7 @@
 				724EE54F1DC7F25B00A91FFB /* ActivityStateChangeObserver.h */,
 				BCF48CE61370D114004E87D6 /* AdjustViewSizeOrNot.h */,
 				CEDA12D6152CA1CB00D9E08D /* AlternativeTextClient.h */,
+				07F04A92200684BC00AE2A0A /* ApplicationStateChangeListener.h */,
 				C9D467041E60C3EB008195FB /* AutoplayEvent.h */,
 				45830D4B1679B4F800ACF8C3 /* AutoscrollController.cpp */,
 				45830D4C1679B4F800ACF8C3 /* AutoscrollController.h */,
@@ -26350,6 +26353,7 @@
 				63BD4A5F1F778E9F00438722 /* ApplicationManifest.h in Headers */,
 				63152D191F9531EE007A5E4B /* ApplicationManifestLoader.h in Headers */,
 				6354F4C91F7AFC9400D89DF3 /* ApplicationManifestParser.h in Headers */,
+				07F04A942006B1E300AE2A0A /* ApplicationStateChangeListener.h in Headers */,
 				9B417064125662B3006B28FC /* ApplyBlockElementCommand.h in Headers */,
 				93309DD9099E64920056E581 /* ApplyStyleCommand.h in Headers */,
 				512DD8F60D91E6AF000F89EE /* Archive.h in Headers */,

Modified: trunk/Source/WebCore/dom/Document.cpp (226989 => 226990)


--- trunk/Source/WebCore/dom/Document.cpp	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/dom/Document.cpp	2018-01-16 19:46:40 UTC (rev 226990)
@@ -29,6 +29,7 @@
 #include "Document.h"
 
 #include "AXObjectCache.h"
+#include "ApplicationStateChangeListener.h"
 #include "Attr.h"
 #include "BeforeUnloadEvent.h"
 #include "CDATASection.h"
@@ -7371,6 +7372,22 @@
 }
 #endif
 
+void Document::addApplicationStateChangeListener(ApplicationStateChangeListener& listener)
+{
+    m_applicationStateChangeListeners.add(&listener);
+}
+
+void Document::removeApplicationStateChangeListener(ApplicationStateChangeListener& listener)
+{
+    m_applicationStateChangeListeners.remove(&listener);
+}
+
+void Document::forEachApplicationStateChangeListener(const Function<void(ApplicationStateChangeListener&)>& functor)
+{
+    for (auto* listener : m_applicationStateChangeListeners)
+        functor(*listener);
+}
+
 const AtomicString& Document::bgColor() const
 {
     auto* bodyElement = body();

Modified: trunk/Source/WebCore/dom/Document.h (226989 => 226990)


--- trunk/Source/WebCore/dom/Document.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/dom/Document.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -76,6 +76,7 @@
 
 namespace WebCore {
 
+class ApplicationStateChangeListener;
 class AXObjectCache;
 class Attr;
 class CDATASection;
@@ -1401,6 +1402,10 @@
     void setServiceWorkerConnection(SWClientConnection*);
 #endif
 
+    void addApplicationStateChangeListener(ApplicationStateChangeListener&);
+    void removeApplicationStateChangeListener(ApplicationStateChangeListener&);
+    void forEachApplicationStateChangeListener(const Function<void(ApplicationStateChangeListener&)>&);
+
 protected:
     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
     Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);
@@ -1883,6 +1888,8 @@
 #if ENABLE(SERVICE_WORKER)
     RefPtr<SWClientConnection> m_serviceWorkerConnection;
 #endif
+
+    HashSet<ApplicationStateChangeListener*> m_applicationStateChangeListeners;
 };
 
 Element* eventTargetElementForDocument(Document*);

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (226989 => 226990)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2018-01-16 19:46:40 UTC (rev 226990)
@@ -742,6 +742,8 @@
 #if ENABLE(MEDIA_STREAM)
     document.registerForMediaStreamStateChangeCallbacks(*this);
 #endif
+
+    document.addApplicationStateChangeListener(*this);
 }
 
 void HTMLMediaElement::unregisterWithDocument(Document& document)
@@ -782,6 +784,7 @@
     document.unregisterForMediaStreamStateChangeCallbacks(*this);
 #endif
 
+    document.removeApplicationStateChangeListener(*this);
 }
 
 void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
@@ -7864,6 +7867,18 @@
 #endif
 }
 
+void HTMLMediaElement::applicationWillResignActive()
+{
+    if (m_player)
+        m_player->applicationWillResignActive();
 }
 
+void HTMLMediaElement::applicationDidBecomeActive()
+{
+    if (m_player)
+        m_player->applicationDidBecomeActive();
+}
+
+}
+
 #endif

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (226989 => 226990)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -28,6 +28,7 @@
 #if ENABLE(VIDEO)
 
 #include "ActiveDOMObject.h"
+#include "ApplicationStateChangeListener.h"
 #include "AutoplayEvent.h"
 #include "GenericEventQueue.h"
 #include "GenericTaskQueue.h"
@@ -128,6 +129,7 @@
     , private MediaPlayerClient
     , private MediaProducer
     , private VisibilityChangeClient
+    , private ApplicationStateChangeListener
 #if ENABLE(VIDEO_TRACK)
     , private AudioTrackClient
     , private TextTrackClient
@@ -904,6 +906,9 @@
     void handleSeekToPlaybackPosition(double);
     void seekToPlaybackPositionEndedTimerFired();
 
+    void applicationWillResignActive() final;
+    void applicationDidBecomeActive() final;
+
 #if !RELEASE_LOG_DISABLED
     const char* logClassName() const final { return "HTMLMediaElement"; }
 

Added: trunk/Source/WebCore/page/ApplicationStateChangeListener.h (0 => 226990)


--- trunk/Source/WebCore/page/ApplicationStateChangeListener.h	                        (rev 0)
+++ trunk/Source/WebCore/page/ApplicationStateChangeListener.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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
+
+namespace WebCore {
+
+class Document;
+
+class ApplicationStateChangeListener {
+public:
+    virtual void applicationWillResignActive() { }
+    virtual void applicationDidBecomeActive() { }
+
+protected:
+    virtual ~ApplicationStateChangeListener() = default;
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/page/Page.cpp (226989 => 226990)


--- trunk/Source/WebCore/page/Page.cpp	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/page/Page.cpp	2018-01-16 19:46:40 UTC (rev 226990)
@@ -2349,4 +2349,42 @@
 #endif
 }
 
+void Page::forEachDocument(const Function<void(Document&)>& functor)
+{
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (!frame->document())
+            continue;
+
+        functor(*frame->document());
+    }
+}
+
+void Page::applicationWillResignActive()
+{
+    forEachDocument([&] (Document& document) {
+        document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
+            listener.applicationWillResignActive();
+        });
+    });
+}
+
+void Page::applicationDidEnterBackground()
+{
+    m_libWebRTCProvider->setActive(false);
+}
+
+void Page::applicationWillEnterForeground()
+{
+    m_libWebRTCProvider->setActive(true);
+}
+
+void Page::applicationDidBecomeActive()
+{
+    forEachDocument([&] (Document& document) {
+        document.forEachApplicationStateChangeListener([&] (ApplicationStateChangeListener& listener) {
+            listener.applicationDidBecomeActive();
+        });
+    });
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/Page.h (226989 => 226990)


--- trunk/Source/WebCore/page/Page.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/page/Page.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -588,6 +588,11 @@
     bool isLowPowerModeEnabled() const;
     WEBCORE_EXPORT void setLowPowerModeEnabledOverrideForTesting(std::optional<bool>);
 
+    WEBCORE_EXPORT void applicationWillResignActive();
+    WEBCORE_EXPORT void applicationDidEnterBackground();
+    WEBCORE_EXPORT void applicationWillEnterForeground();
+    WEBCORE_EXPORT void applicationDidBecomeActive();
+
 private:
     struct Navigation {
         String domain;
@@ -618,6 +623,8 @@
 
     void handleLowModePowerChange(bool);
 
+    void forEachDocument(const WTF::Function<void(Document&)>&);
+
     enum class TimerThrottlingState { Disabled, Enabled, EnabledIncreasing };
     void hiddenPageDOMTimerThrottlingStateChanged();
     void setTimerThrottlingState(TimerThrottlingState);

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (226989 => 226990)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2018-01-16 19:46:40 UTC (rev 226990)
@@ -1505,6 +1505,16 @@
     return client().mediaPlayerShouldCheckHardwareSupport();
 }
 
+void MediaPlayer::applicationWillResignActive()
+{
+    m_private->applicationWillResignActive();
+}
+
+void MediaPlayer::applicationDidBecomeActive()
+{
+    m_private->applicationDidBecomeActive();
+}
+
 #if !RELEASE_LOG_DISABLED
 const Logger& MediaPlayer::mediaPlayerLogger()
 {

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (226989 => 226990)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -638,6 +638,9 @@
     const void* mediaPlayerLogIdentifier() { return client().mediaPlayerLogIdentifier(); }
 #endif
 
+    void applicationWillResignActive();
+    void applicationDidBecomeActive();
+
 private:
     MediaPlayer(MediaPlayerClient&);
 

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h (226989 => 226990)


--- trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -280,6 +280,9 @@
     virtual void notifyActiveSourceBuffersChanged() { }
 
     virtual void setShouldDisableSleep(bool) { }
+
+    virtual void applicationWillResignActive() { }
+    virtual void applicationDidBecomeActive() { }
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h (226989 => 226990)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h	2018-01-16 19:46:40 UTC (rev 226990)
@@ -33,6 +33,7 @@
 #include "MediaStreamPrivate.h"
 #include <CoreGraphics/CGAffineTransform.h>
 #include <wtf/Function.h>
+#include <wtf/LoggerHelper.h>
 #include <wtf/MediaTime.h>
 #include <wtf/WeakPtr.h>
 
@@ -42,7 +43,6 @@
 OBJC_CLASS AVStreamSession;
 OBJC_CLASS NSNumber;
 OBJC_CLASS WebAVSampleBufferStatusChangeListener;
-typedef struct opaqueCMSampleBuffer *CMSampleBufferRef;
 
 namespace PAL {
 class Clock;
@@ -60,7 +60,11 @@
 class VideoFullscreenLayerManager;
 #endif
 
-class MediaPlayerPrivateMediaStreamAVFObjC final : public MediaPlayerPrivateInterface, private MediaStreamPrivate::Observer, private MediaStreamTrackPrivate::Observer {
+class MediaPlayerPrivateMediaStreamAVFObjC final : public MediaPlayerPrivateInterface, private MediaStreamPrivate::Observer, private MediaStreamTrackPrivate::Observer
+#if !RELEASE_LOG_DISABLED
+    , private LoggerHelper
+#endif
+{
 public:
     explicit MediaPlayerPrivateMediaStreamAVFObjC(MediaPlayer*);
     virtual ~MediaPlayerPrivateMediaStreamAVFObjC();
@@ -89,6 +93,13 @@
     PlatformLayer* displayLayer();
     PlatformLayer* backgroundLayer();
 
+#if !RELEASE_LOG_DISABLED
+    const Logger& logger() const final { return m_logger.get(); }
+    const char* logClassName() const override { return "MediaPlayerPrivateMediaStreamAVFObjC"; }
+    const void* logIdentifier() const final { return reinterpret_cast<const void*>(m_logIdentifier); }
+    WTFLogChannel& logChannel() const final;
+#endif
+
 private:
     // MediaPlayerPrivateInterface
 
@@ -144,10 +155,10 @@
     void addSampleToPendingQueue(PendingSampleQueue&, MediaSample&);
     void removeOldSamplesFromPendingQueue(PendingSampleQueue&);
 
-    void updateSampleTimes(MediaSample&, const MediaTime&, const char*);
     MediaTime calculateTimelineOffset(const MediaSample&, double);
     
     void enqueueVideoSample(MediaStreamTrackPrivate&, MediaSample&);
+    void enqueueCorrectedVideoSample(MediaSample&);
     void flushAndRemoveVideoSampleBuffers();
     void requestNotificationWhenReadyForVideoData();
 
@@ -223,12 +234,12 @@
 
     CGAffineTransform videoTransformationMatrix(MediaSample&, bool forceUpdate = false);
 
+    void applicationDidBecomeActive() final;
+
     MediaPlayer* m_player { nullptr };
     WeakPtrFactory<MediaPlayerPrivateMediaStreamAVFObjC> m_weakPtrFactory;
     RefPtr<MediaStreamPrivate> m_mediaStreamPrivate;
-
     RefPtr<MediaStreamTrackPrivate> m_activeVideoTrack;
-
     RetainPtr<WebAVSampleBufferStatusChangeListener> m_statusChangeListener;
     RetainPtr<AVSampleBufferDisplayLayer> m_sampleBufferDisplayLayer;
     RetainPtr<PlatformLayer> m_backgroundLayer;
@@ -272,6 +283,12 @@
 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     std::unique_ptr<VideoFullscreenLayerManager> m_videoFullscreenLayerManager;
 #endif
+
+#if !RELEASE_LOG_DISABLED
+    Ref<const Logger> m_logger;
+    const void* m_logIdentifier;
+#endif
+
 };
     
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm (226989 => 226990)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm	2018-01-16 19:46:40 UTC (rev 226990)
@@ -194,13 +194,17 @@
 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     , m_videoFullscreenLayerManager(VideoFullscreenLayerManager::create())
 #endif
+#if !RELEASE_LOG_DISABLED
+    , m_logger(player->mediaPlayerLogger())
+    , m_logIdentifier(player->mediaPlayerLogIdentifier())
+#endif
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::MediaPlayerPrivateMediaStreamAVFObjC(%p)", this);
+    INFO_LOG(LOGIDENTIFIER);
 }
 
 MediaPlayerPrivateMediaStreamAVFObjC::~MediaPlayerPrivateMediaStreamAVFObjC()
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::~MediaPlayerPrivateMediaStreamAVFObjC(%p)", this);
+    INFO_LOG(LOGIDENTIFIER);
 
     [m_statusChangeListener invalidate];
 
@@ -276,27 +280,6 @@
     queue.append(sample);
 }
 
-void MediaPlayerPrivateMediaStreamAVFObjC::updateSampleTimes(MediaSample& sample, const MediaTime& timelineOffset, const char* loggingPrefix)
-{
-    LOG(MediaCaptureSamples, "%s(%p): original sample = %s", loggingPrefix, this, toString(sample).utf8().data());
-    sample.offsetTimestampsBy(timelineOffset);
-    LOG(MediaCaptureSamples, "%s(%p): adjusted sample = %s", loggingPrefix, this, toString(sample).utf8().data());
-
-#if !LOG_DISABLED
-    MediaTime now = streamTime();
-    double delta = (sample.presentationTime() - now).toDouble();
-    if (delta < 0)
-        LOG(Media, "%s(%p): *NOTE* audio sample at time %s is %f seconds late", loggingPrefix, this, toString(now).utf8().data(), -delta);
-    else if (delta < .01)
-        LOG(Media, "%s(%p): *NOTE* audio sample at time %s is only %f seconds early", loggingPrefix, this, toString(now).utf8().data(), delta);
-    else if (delta > .3)
-        LOG(Media, "%s(%p): *NOTE* audio sample at time %s is %f seconds early!", loggingPrefix, this, toString(now).utf8().data(), delta);
-#else
-    UNUSED_PARAM(loggingPrefix);
-#endif
-
-}
-
 MediaTime MediaPlayerPrivateMediaStreamAVFObjC::calculateTimelineOffset(const MediaSample& sample, double latency)
 {
     MediaTime sampleTime = sample.outputPresentationTime();
@@ -340,6 +323,36 @@
     [CATransaction commit];
 }
 
+void MediaPlayerPrivateMediaStreamAVFObjC::enqueueCorrectedVideoSample(MediaSample& sample)
+{
+    if (m_sampleBufferDisplayLayer) {
+        if ([m_sampleBufferDisplayLayer status] == AVQueuedSampleBufferRenderingStatusFailed)
+            return;
+
+        if (sample.videoRotation() != m_videoRotation || sample.videoMirrored() != m_videoMirrored) {
+            m_videoRotation = sample.videoRotation();
+            m_videoMirrored = sample.videoMirrored();
+            runWithoutAnimations([this, &sample] {
+                m_sampleBufferDisplayLayer.get().affineTransform = videoTransformationMatrix(sample, true);
+                updateDisplayLayer();
+            });
+        }
+
+        if (![m_sampleBufferDisplayLayer isReadyForMoreMediaData]) {
+            addSampleToPendingQueue(m_pendingVideoSampleQueue, sample);
+            requestNotificationWhenReadyForVideoData();
+            return;
+        }
+
+        [m_sampleBufferDisplayLayer enqueueSampleBuffer:sample.platformSample().sample.cmSampleBuffer];
+    }
+
+    if (!m_hasEverEnqueuedVideoFrame) {
+        m_hasEverEnqueuedVideoFrame = true;
+        m_player->firstVideoFrameAvailable();
+    }
+}
+
 void MediaPlayerPrivateMediaStreamAVFObjC::enqueueVideoSample(MediaStreamTrackPrivate& track, MediaSample& sample)
 {
     ASSERT(m_videoTrackMap.contains(track.id()));
@@ -362,34 +375,26 @@
     if (timelineOffset == MediaTime::invalidTime()) {
         timelineOffset = calculateTimelineOffset(sample, rendererLatency);
         videoTrack->setTimelineOffset(timelineOffset);
-        LOG(MediaCaptureSamples, "MediaPlayerPrivateMediaStreamAVFObjC::enqueueVideoSample: timeline offset for track %s set to %s", track.id().utf8().data(), toString(timelineOffset).utf8().data());
+
+        INFO_LOG(LOGIDENTIFIER, "timeline offset for track ", track.id(), " set to ", timelineOffset);
     }
 
-    updateSampleTimes(sample, timelineOffset, "MediaPlayerPrivateMediaStreamAVFObjC::enqueueVideoSample");
+    DEBUG_LOG(LOGIDENTIFIER, "original sample = ", toString(sample));
+    sample.offsetTimestampsBy(timelineOffset);
+    DEBUG_LOG(LOGIDENTIFIER, "updated sample = ", toString(sample));
 
-    if (m_sampleBufferDisplayLayer) {
-        if (sample.videoRotation() != m_videoRotation || sample.videoMirrored() != m_videoMirrored) {
-            m_videoRotation = sample.videoRotation();
-            m_videoMirrored = sample.videoMirrored();
-            runWithoutAnimations([this, &sample] {
-                m_sampleBufferDisplayLayer.get().affineTransform = videoTransformationMatrix(sample, true);
-                updateDisplayLayer();
-            });
-        }
-
-        if (![m_sampleBufferDisplayLayer isReadyForMoreMediaData]) {
-            addSampleToPendingQueue(m_pendingVideoSampleQueue, sample);
-            requestNotificationWhenReadyForVideoData();
-            return;
-        }
-
-        [m_sampleBufferDisplayLayer enqueueSampleBuffer:sample.platformSample().sample.cmSampleBuffer];
+    if (WILL_LOG(WTFLogLevelDebug)) {
+        MediaTime now = streamTime();
+        double delta = (sample.presentationTime() - now).toDouble();
+        if (delta < 0)
+            DEBUG_LOG(LOGIDENTIFIER, "*NOTE* sample at time is ", now, " is", -delta, " seconds late");
+        else if (delta < .01)
+            DEBUG_LOG(LOGIDENTIFIER, "*NOTE* audio sample at time ", now, " is only ", delta, " seconds early");
+        else if (delta > .3)
+            DEBUG_LOG(LOGIDENTIFIER, "*NOTE* audio sample at time ", now, " is ", delta, " seconds early!");
     }
 
-    if (!m_hasEverEnqueuedVideoFrame) {
-        m_hasEverEnqueuedVideoFrame = true;
-        m_player->firstVideoFrameAvailable();
-    }
+    enqueueCorrectedVideoSample(sample);
 }
 
 void MediaPlayerPrivateMediaStreamAVFObjC::requestNotificationWhenReadyForVideoData()
@@ -422,12 +427,12 @@
 void MediaPlayerPrivateMediaStreamAVFObjC::layerErrorDidChange(AVSampleBufferDisplayLayer* layer)
 {
     UNUSED_PARAM(layer);
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::layerErrorDidChange(%p) - error = %s", this, [[layer.error localizedDescription] UTF8String]);
+    ERROR_LOG(LOGIDENTIFIER, "error = ", [[layer.error localizedDescription] UTF8String]);
 }
 
 void MediaPlayerPrivateMediaStreamAVFObjC::layerStatusDidChange(AVSampleBufferDisplayLayer* layer)
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::layerStatusDidChange(%p) - status = %d", this, (int)layer.status);
+    ALWAYS_LOG(LOGIDENTIFIER, "status = ", (int)layer.status);
 
     if (layer.status != AVQueuedSampleBufferRenderingStatusRendering)
         return;
@@ -439,6 +444,16 @@
         track->setTimelineOffset(MediaTime::invalidTime());
 }
 
+void MediaPlayerPrivateMediaStreamAVFObjC::applicationDidBecomeActive()
+{
+    if (m_sampleBufferDisplayLayer && [m_sampleBufferDisplayLayer status] == AVQueuedSampleBufferRenderingStatusFailed) {
+        flushRenderers();
+        if (m_imagePainter.mediaSample)
+            enqueueCorrectedVideoSample(*m_imagePainter.mediaSample);
+        updateDisplayMode();
+    }
+}
+
 void MediaPlayerPrivateMediaStreamAVFObjC::flushRenderers()
 {
     if (m_sampleBufferDisplayLayer)
@@ -460,7 +475,7 @@
 
     m_sampleBufferDisplayLayer = adoptNS([allocAVSampleBufferDisplayLayerInstance() init]);
     if (!m_sampleBufferDisplayLayer) {
-        LOG_ERROR("MediaPlayerPrivateMediaStreamAVFObjC::ensureLayers: +[AVSampleBufferDisplayLayer alloc] failed.");
+        ERROR_LOG(LOGIDENTIFIER, "+[AVSampleBufferDisplayLayer alloc] failed.");
         return;
     }
 
@@ -531,7 +546,7 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::load(MediaStreamPrivate& stream)
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::load(%p)", this);
+    INFO_LOG(LOGIDENTIFIER);
 
     m_intrinsicSize = FloatSize();
 
@@ -556,7 +571,7 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::cancelLoad()
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::cancelLoad(%p)", this);
+    INFO_LOG(LOGIDENTIFIER);
     if (playing())
         pause();
 }
@@ -563,7 +578,7 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::prepareToPlay()
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::prepareToPlay(%p)", this);
+    INFO_LOG(LOGIDENTIFIER);
 }
 
 PlatformLayer* MediaPlayerPrivateMediaStreamAVFObjC::platformLayer() const
@@ -616,6 +631,8 @@
 
     if (displayMode == m_displayMode)
         return false;
+
+    INFO_LOG(LOGIDENTIFIER, "updated to ", static_cast<int>(displayMode));
     m_displayMode = displayMode;
 
     if (m_sampleBufferDisplayLayer) {
@@ -629,7 +646,7 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::play()
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::play(%p)", this);
+    ALWAYS_LOG(LOGIDENTIFIER);
 
     if (!metaDataAvailable() || playing() || m_ended)
         return;
@@ -653,7 +670,7 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::pause()
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::pause(%p)", this);
+    ALWAYS_LOG(LOGIDENTIFIER);
 
     if (!metaDataAvailable() || !playing() || m_ended)
         return;
@@ -675,11 +692,10 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::setVolume(float volume)
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::setVolume(%p)", this);
-
     if (m_volume == volume)
         return;
 
+    ALWAYS_LOG(LOGIDENTIFIER, volume);
     m_volume = volume;
     for (const auto& track : m_audioTrackMap.values())
         track->setVolume(m_muted ? 0 : m_volume);
@@ -687,11 +703,10 @@
 
 void MediaPlayerPrivateMediaStreamAVFObjC::setMuted(bool muted)
 {
-    LOG(Media, "MediaPlayerPrivateMediaStreamAVFObjC::setMuted(%p)", this);
-
     if (muted == m_muted)
         return;
 
+    ALWAYS_LOG(LOGIDENTIFIER, muted);
     m_muted = muted;
     for (const auto& track : m_audioTrackMap.values())
         track->setVolume(m_muted ? 0 : m_volume);
@@ -778,8 +793,10 @@
 {
     MediaPlayer::ReadyState newReadyState = currentReadyState();
 
-    if (newReadyState != m_readyState)
+    if (newReadyState != m_readyState) {
+        ALWAYS_LOG(LOGIDENTIFIER, "updated to ", (int)newReadyState);
         setReadyState(newReadyState);
+    }
 }
 
 void MediaPlayerPrivateMediaStreamAVFObjC::activeStatusChanged()
@@ -1170,6 +1187,14 @@
     });
 }
 
+#if !RELEASE_LOG_DISABLED
+WTFLogChannel& MediaPlayerPrivateMediaStreamAVFObjC::logChannel() const
+{
+    return LogMedia;
 }
+#endif
 
+
+}
+
 #endif

Modified: trunk/Source/WebKit/ChangeLog (226989 => 226990)


--- trunk/Source/WebKit/ChangeLog	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebKit/ChangeLog	2018-01-16 19:46:40 UTC (rev 226990)
@@ -1,3 +1,17 @@
+2018-01-16  Eric Carlson  <[email protected]>
+
+        AVSampleBufferDisplayLayer should be flushed when application activates
+        https://bugs.webkit.org/show_bug.cgi?id=181623
+        <rdar://problem/36487738>
+
+        Reviewed by Darin Adler.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::applicationWillResignActive): Call page.
+        (WebKit::WebPage::applicationDidEnterBackground): Ditto, let it call libWebRTCProvider.
+        (WebKit::WebPage::applicationWillEnterForeground): Call page.
+        (WebKit::WebPage::applicationDidBecomeActive): Ditto, let it call libWebRTCProvider.
+
 2018-01-16  Zach Li  <[email protected]>
 
         Add pop-up policy support in website policies.

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (226989 => 226990)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-01-16 19:41:49 UTC (rev 226989)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-01-16 19:46:40 UTC (rev 226990)
@@ -2689,6 +2689,7 @@
 void WebPage::applicationWillResignActive()
 {
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillResignActiveNotification object:nil];
+    m_page->applicationWillResignActive();
 }
 
 void WebPage::applicationDidEnterBackground(bool isSuspendedUnderLock)
@@ -2698,7 +2699,7 @@
     m_isSuspendedUnderLock = isSuspendedUnderLock;
     setLayerTreeStateIsFrozen(true);
 
-    m_page->libWebRTCProvider().setActive(false);
+    m_page->applicationDidEnterBackground();
 }
 
 void WebPage::applicationDidFinishSnapshottingAfterEnteringBackground()
@@ -2714,12 +2715,13 @@
 
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillEnterForegroundNotification object:nil userInfo:@{@"isSuspendedUnderLock": @(isSuspendedUnderLock)}];
 
-    m_page->libWebRTCProvider().setActive(true);
+    m_page->applicationWillEnterForeground();
 }
 
 void WebPage::applicationDidBecomeActive()
 {
     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidBecomeActiveNotification object:nil];
+    m_page->applicationDidBecomeActive();
 }
 
 static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity, double& verticalVelocity, double& scaleChangeRate, double exposedRectScale, double minimumScale, double maximumScale)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to