Title: [177375] trunk/Source/WebCore
Revision
177375
Author
jer.no...@apple.com
Date
2014-12-16 11:20:46 -0800 (Tue, 16 Dec 2014)

Log Message

[iOS] Crash in WebKit::WebPageProxy::dispatchViewStateChange() tapping a link from another app while playing a video
https://bugs.webkit.org/show_bug.cgi?id=139550

Reviewed by Anders Carlsson.

The existing "dispatch to WebThread, then release" model is insufficient and still
can result in RefPtr race conditions between the main thread and the web thread.
Make WebVideoFullscreenInterfaceAVKit a thread-safe ref-counted class, which
eliminates the necessity of disptaching back to the web thread before releasing.

* platform/ios/WebVideoFullscreenInterfaceAVKit.h:
* platform/ios/WebVideoFullscreenInterfaceAVKit.mm:
(WebVideoFullscreenInterfaceAVKit::setDuration): Use a strongThis model.
(WebVideoFullscreenInterfaceAVKit::setCurrentTime): Ditto.
(WebVideoFullscreenInterfaceAVKit::setRate): Ditto.
(WebVideoFullscreenInterfaceAVKit::setVideoDimensions): Ditto.
(WebVideoFullscreenInterfaceAVKit::setSeekableRanges): Ditto.
(mediaSelectionOptions): Return a RetainPtr object.
(WebVideoFullscreenInterfaceAVKit::setAudioMediaSelectionOptions): Use a strongThis model.
(WebVideoFullscreenInterfaceAVKit::setLegibleMediaSelectionOptions): Ditto.
(WebVideoFullscreenInterfaceAVKit::setExternalPlayback): Ditto.
(WebVideoFullscreenInterfaceAVKit::setupFullscreen): Ditto.
(WebVideoFullscreenInterfaceAVKit::enterFullscreen): Ditto.
(WebVideoFullscreenInterfaceAVKit::exitFullscreen): Ditto.
(WebVideoFullscreenInterfaceAVKit::cleanupFullscreen): Ditto.
(WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal): Added utility
    function. Lets us use the implied this pointer rather than an explicit
    strongThis.
(WebVideoFullscreenInterfaceAVKit::enterFullscreenOptimized): Ditto.
(WebVideoFullscreenInterfaceAVKit::enterFullscreenStandard): Ditto.
(WebVideoFullscreenInterfaceAVKit::exitFullscreenInternal): Ditto.
(WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal): Ditto.
(WebVideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen): Use a strongThis model.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (177374 => 177375)


--- trunk/Source/WebCore/ChangeLog	2014-12-16 19:16:05 UTC (rev 177374)
+++ trunk/Source/WebCore/ChangeLog	2014-12-16 19:20:46 UTC (rev 177375)
@@ -1,3 +1,39 @@
+2014-12-16  Jer Noble  <jer.no...@apple.com>
+
+        [iOS] Crash in WebKit::WebPageProxy::dispatchViewStateChange() tapping a link from another app while playing a video
+        https://bugs.webkit.org/show_bug.cgi?id=139550
+
+        Reviewed by Anders Carlsson.
+
+        The existing "dispatch to WebThread, then release" model is insufficient and still
+        can result in RefPtr race conditions between the main thread and the web thread.
+        Make WebVideoFullscreenInterfaceAVKit a thread-safe ref-counted class, which
+        eliminates the necessity of disptaching back to the web thread before releasing.
+
+        * platform/ios/WebVideoFullscreenInterfaceAVKit.h:
+        * platform/ios/WebVideoFullscreenInterfaceAVKit.mm:
+        (WebVideoFullscreenInterfaceAVKit::setDuration): Use a strongThis model.
+        (WebVideoFullscreenInterfaceAVKit::setCurrentTime): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setRate): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setVideoDimensions): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setSeekableRanges): Ditto.
+        (mediaSelectionOptions): Return a RetainPtr object.
+        (WebVideoFullscreenInterfaceAVKit::setAudioMediaSelectionOptions): Use a strongThis model.
+        (WebVideoFullscreenInterfaceAVKit::setLegibleMediaSelectionOptions): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setExternalPlayback): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setupFullscreen): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::enterFullscreen): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::exitFullscreen): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::cleanupFullscreen): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal): Added utility
+            function. Lets us use the implied this pointer rather than an explicit
+            strongThis.
+        (WebVideoFullscreenInterfaceAVKit::enterFullscreenOptimized): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::enterFullscreenStandard): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::exitFullscreenInternal): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal): Ditto.
+        (WebVideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen): Use a strongThis model.
+
 2014-12-16  Ryosuke Niwa  <rn...@webkit.org>
 
         Nested template contents are not cloned by document.importNode

Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h (177374 => 177375)


--- trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h	2014-12-16 19:16:05 UTC (rev 177374)
+++ trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h	2014-12-16 19:20:46 UTC (rev 177375)
@@ -35,6 +35,7 @@
 #include <WebCore/WebVideoFullscreenInterface.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
+#include <wtf/ThreadSafeRefCounted.h>
 
 OBJC_CLASS WebAVPlayerController;
 OBJC_CLASS AVPlayerViewController;
@@ -64,7 +65,7 @@
 
 class WebVideoFullscreenInterfaceAVKit
     : public WebVideoFullscreenInterface
-    , public RefCounted<WebVideoFullscreenInterfaceAVKit> {
+    , public ThreadSafeRefCounted<WebVideoFullscreenInterfaceAVKit> {
 
 public:
     WEBCORE_EXPORT WebVideoFullscreenInterfaceAVKit();
@@ -94,7 +95,12 @@
     bool mayAutomaticallyShowVideoOptimized();
 
 protected:
-        
+    void setupFullscreenInternal(PlatformLayer&, IntRect initialRect, UIView *, HTMLMediaElement::VideoFullscreenMode, bool allowOptimizedFullscreen);
+    void enterFullscreenOptimized();
+    void enterFullscreenStandard();
+    void exitFullscreenInternal(IntRect finalRect);
+    void cleanupFullscreenInternal();
+
     RetainPtr<WebAVPlayerController> m_playerController;
     RetainPtr<AVPlayerViewController> m_playerViewController;
     RetainPtr<CALayer> m_videoLayer;

Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm (177374 => 177375)


--- trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm	2014-12-16 19:16:05 UTC (rev 177374)
+++ trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm	2014-12-16 19:20:46 UTC (rev 177375)
@@ -649,11 +649,11 @@
 
 void WebVideoFullscreenInterfaceAVKit::setDuration(double duration)
 {
-    WebAVPlayerController* playerController = this->playerController();
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
+    dispatch_async(dispatch_get_main_queue(), [strongThis, duration] {
+        WebAVPlayerController* playerController = strongThis->playerController();
+
         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=127017 use correct values instead of duration for all these
         playerController.contentDuration = duration;
         playerController.maxTime = duration;
@@ -668,59 +668,43 @@
         playerController.canSeek = YES;
         playerController.minTime = 0;
         playerController.status = AVPlayerControllerStatusReadyToPlay;
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setCurrentTime(double currentTime, double anchorTime)
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        NSTimeInterval anchorTimeStamp = ![playerController() rate] ? NAN : anchorTime;
+    dispatch_async(dispatch_get_main_queue(), [strongThis, currentTime, anchorTime] {
+        NSTimeInterval anchorTimeStamp = ![strongThis->playerController() rate] ? NAN : anchorTime;
         AVValueTiming *timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime
             anchorTimeStamp:anchorTimeStamp rate:0];
-        playerController().timing = timing;
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+        strongThis->playerController().timing = timing;
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setRate(bool isPlaying, float playbackRate)
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().rate = isPlaying ? playbackRate : 0.;
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    dispatch_async(dispatch_get_main_queue(), [strongThis, isPlaying, playbackRate] {
+        strongThis->playerController().rate = isPlaying ? playbackRate : 0.;
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setVideoDimensions(bool hasVideo, float width, float height)
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().hasEnabledVideo = hasVideo;
-        playerController().contentDimensions = CGSizeMake(width, height);
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    dispatch_async(dispatch_get_main_queue(), [strongThis, hasVideo, width, height] {
+        strongThis->playerController().hasEnabledVideo = hasVideo;
+        strongThis->playerController().contentDimensions = CGSizeMake(width, height);
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setSeekableRanges(const TimeRanges& timeRanges)
 {
-    NSMutableArray* seekableRanges = [NSMutableArray array];
+    RetainPtr<NSMutableArray> seekableRanges = adoptNS([[NSMutableArray alloc] init]);
     ExceptionCode exceptionCode;
 
     for (unsigned i = 0; i < timeRanges.length(); i++) {
@@ -731,14 +715,10 @@
         [seekableRanges addObject:[NSValue valueWithCMTimeRange:range]];
     }
     
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().seekableTimeRanges = seekableRanges;
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    dispatch_async(dispatch_get_main_queue(), [strongThis, seekableRanges] {
+        strongThis->playerController().seekableTimeRanges = seekableRanges.get();
     });
 }
 
@@ -747,9 +727,9 @@
     playerController().canScanBackward = canPlayFastReverse;
 }
 
-static NSMutableArray *mediaSelectionOptions(const Vector<String>& options)
+static RetainPtr<NSMutableArray> mediaSelectionOptions(const Vector<String>& options)
 {
-    NSMutableArray *webOptions = [NSMutableArray arrayWithCapacity:options.size()];
+    RetainPtr<NSMutableArray> webOptions = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
     for (auto& name : options) {
         RetainPtr<WebAVMediaSelectionOption> webOption = adoptNS([[WebAVMediaSelectionOption alloc] init]);
         [webOption setLocalizedDisplayName:name];
@@ -760,33 +740,25 @@
 
 void WebVideoFullscreenInterfaceAVKit::setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
 {
-    NSMutableArray *webOptions = mediaSelectionOptions(options);
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().audioMediaSelectionOptions = webOptions;
-        if (selectedIndex < webOptions.count)
-            playerController().currentAudioMediaSelectionOption = webOptions[(size_t)selectedIndex];
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    dispatch_async(dispatch_get_main_queue(), [webOptions, strongThis, selectedIndex] {
+        strongThis->playerController().audioMediaSelectionOptions = webOptions.get();
+        if (selectedIndex < [webOptions count])
+            strongThis->playerController().currentAudioMediaSelectionOption = [webOptions objectAtIndex:selectedIndex];
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
 {
-    NSMutableArray *webOptions = mediaSelectionOptions(options);
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().legibleMediaSelectionOptions = webOptions;
-        if (selectedIndex < webOptions.count)
-            playerController().currentLegibleMediaSelectionOption = webOptions[(size_t)selectedIndex];
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
+    dispatch_async(dispatch_get_main_queue(), [webOptions, strongThis, selectedIndex] {
+        strongThis->playerController().legibleMediaSelectionOptions = webOptions.get();
+        if (selectedIndex < [webOptions count])
+            strongThis->playerController().currentLegibleMediaSelectionOption = [webOptions objectAtIndex:selectedIndex];
     });
 }
 
@@ -798,201 +770,217 @@
     else if (targetType == TargetTypeTVOut)
         externalPlaybackType = AVPlayerControllerExternalPlaybackTypeTVOut;
 
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
-        playerController().externalPlaybackAirPlayDeviceLocalizedName = localizedDeviceName;
-        playerController().externalPlaybackType = externalPlaybackType;
-        playerController().externalPlaybackActive = enabled;
-        [m_videoLayerContainer.get() setHidden:enabled];
-        
-        WebThreadRun(^{
-            protect = nullptr;
-        });
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
+    dispatch_async(dispatch_get_main_queue(), [strongThis, enabled, localizedDeviceName, externalPlaybackType] {
+        WebAVPlayerController* playerController = strongThis->playerController();
+        playerController.externalPlaybackAirPlayDeviceLocalizedName = localizedDeviceName;
+        playerController.externalPlaybackType = externalPlaybackType;
+        playerController.externalPlaybackActive = enabled;
+        [strongThis->m_videoLayerContainer.get() setHidden:enabled];
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::setupFullscreen(PlatformLayer& videoLayer, WebCore::IntRect initialRect, UIView* parentView, HTMLMediaElement::VideoFullscreenMode mode, bool allowOptimizedFullscreen)
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
     ASSERT(mode != HTMLMediaElement::VideoFullscreenModeNone);
     m_videoLayer = &videoLayer;
-    
+
     m_mode = mode;
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
 
-        [CATransaction begin];
-        [CATransaction setDisableActions:YES];
-        m_parentView = parentView;
-        m_parentWindow = parentView.window;
+    dispatch_async(dispatch_get_main_queue(), [strongThis, &videoLayer, initialRect, parentView, mode, allowOptimizedFullscreen] {
+        strongThis->setupFullscreenInternal(videoLayer, initialRect, parentView, mode, allowOptimizedFullscreen);
+    });
+}
 
-        if (!applicationIsAdSheet()) {
-            m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
-            [m_window setBackgroundColor:[getUIColorClass() clearColor]];
-            m_viewController = adoptNS([allocUIViewControllerInstance() init]);
-            [[m_viewController view] setFrame:[m_window bounds]];
-            [m_window setRootViewController:m_viewController.get()];
-            [m_window makeKeyAndVisible];
-        }
-        
-        [m_videoLayer removeFromSuperlayer];
-        
-        m_videoLayerContainer = [WebAVVideoLayer videoLayer];
-        [m_videoLayerContainer setHidden:playerController().externalPlaybackActive];
-        [m_videoLayerContainer setVideoSublayer:m_videoLayer.get()];
-        
-        CGSize videoSize = playerController().contentDimensions;
-        CGRect videoRect = CGRectMake(0, 0, videoSize.width, videoSize.height);
-        [m_videoLayerContainer setVideoRect:videoRect];
+void WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal(PlatformLayer& videoLayer, WebCore::IntRect initialRect, UIView* parentView, HTMLMediaElement::VideoFullscreenMode mode, bool allowOptimizedFullscreen)
+{
+    UNUSED_PARAM(videoLayer);
+    UNUSED_PARAM(mode);
 
-        m_playerViewController = adoptNS([allocAVPlayerViewControllerInstance() initWithVideoLayer:m_videoLayerContainer.get()]);
-        [m_playerViewController setShowsPlaybackControls:NO];
-        [m_playerViewController setPlayerController:(AVPlayerController *)playerController()];
-        [m_playerViewController setDelegate:playerController()];
-        [m_playerViewController setAllowsOptimizedFullscreen:allowOptimizedFullscreen];
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+    m_parentView = parentView;
+    m_parentWindow = parentView.window;
 
-        [m_videoLayerContainer setPlayerViewController:m_playerViewController.get()];
+    if (!applicationIsAdSheet()) {
+        m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
+        [m_window setBackgroundColor:[getUIColorClass() clearColor]];
+        m_viewController = adoptNS([allocUIViewControllerInstance() init]);
+        [[m_viewController view] setFrame:[m_window bounds]];
+        [m_window setRootViewController:m_viewController.get()];
+        [m_window makeKeyAndVisible];
+    }
 
-        if (m_viewController) {
-            [m_viewController addChildViewController:m_playerViewController.get()];
-            [[m_viewController view] addSubview:[m_playerViewController view]];
-            [m_playerViewController view].frame = [parentView convertRect:initialRect toView:nil];
-        } else {
-            [parentView addSubview:[m_playerViewController view]];
-            [m_playerViewController view].frame = initialRect;
-        }
+    [m_videoLayer removeFromSuperlayer];
 
-        [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
-        [[m_playerViewController view] setNeedsLayout];
-        [[m_playerViewController view] layoutIfNeeded];
+    m_videoLayerContainer = [WebAVVideoLayer videoLayer];
+    [m_videoLayerContainer setHidden:playerController().externalPlaybackActive];
+    [m_videoLayerContainer setVideoSublayer:m_videoLayer.get()];
 
-        [CATransaction commit];
+    CGSize videoSize = playerController().contentDimensions;
+    CGRect videoRect = CGRectMake(0, 0, videoSize.width, videoSize.height);
+    [m_videoLayerContainer setVideoRect:videoRect];
 
-        dispatch_async(dispatch_get_main_queue(), ^{
-            WebThreadRun(^{
-                if (m_fullscreenChangeObserver)
-                    m_fullscreenChangeObserver->didSetupFullscreen();
+    m_playerViewController = adoptNS([allocAVPlayerViewControllerInstance() initWithVideoLayer:m_videoLayerContainer.get()]);
+    [m_playerViewController setShowsPlaybackControls:NO];
+    [m_playerViewController setPlayerController:(AVPlayerController *)playerController()];
+    [m_playerViewController setDelegate:playerController()];
+    [m_playerViewController setAllowsOptimizedFullscreen:allowOptimizedFullscreen];
 
-                protect = nullptr;
-            });
-        });
+    [m_videoLayerContainer setPlayerViewController:m_playerViewController.get()];
+
+    if (m_viewController) {
+        [m_viewController addChildViewController:m_playerViewController.get()];
+        [[m_viewController view] addSubview:[m_playerViewController view]];
+        [m_playerViewController view].frame = [parentView convertRect:initialRect toView:nil];
+    } else {
+        [parentView addSubview:[m_playerViewController view]];
+        [m_playerViewController view].frame = initialRect;
+    }
+
+    [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
+    [[m_playerViewController view] setNeedsLayout];
+    [[m_playerViewController view] layoutIfNeeded];
+
+    [CATransaction commit];
+
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+    WebThreadRun([strongThis] {
+        if (strongThis->m_fullscreenChangeObserver)
+            strongThis->m_fullscreenChangeObserver->didSetupFullscreen();
     });
 }
 
 void WebVideoFullscreenInterfaceAVKit::enterFullscreen()
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
     m_exitCompleted = false;
     m_exitRequested = false;
     m_enterRequested = true;
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() blackColor] CGColor]];
-        if (m_mode == HTMLMediaElement::VideoFullscreenModeOptimized) {
-            [m_playerViewController startOptimizedFullscreenWithStartCompletionHandler:^(BOOL success, NSError *) {
-                
-                [m_playerViewController setShowsPlaybackControls:YES];
-                
-                WebThreadRun(^{
-                    [m_window setHidden:YES];
-                    if (m_fullscreenChangeObserver)
-                        m_fullscreenChangeObserver->didEnterFullscreen();
-                    
-                    if (!success) {
-                        if (m_videoFullscreenModel)
-                            m_videoFullscreenModel->requestExitFullscreen();
-                        protect = nullptr;
-                    }
-                });
-            } stopCompletionHandler:^(AVPlayerViewControllerOptimizedFullscreenStopReason reason) {
-                m_exitCompleted = true;
-                
-                if (m_fullscreenChangeObserver && reason == AVPlayerViewControllerOptimizedFullscreenStopReasonStopped)
-                    m_fullscreenChangeObserver->fullscreenMayReturnToInline();
 
-                if (m_exitRequested) {
-                    [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
-                    [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
-                    WebThreadRun(^{
-                        if (m_fullscreenChangeObserver)
-                            m_fullscreenChangeObserver->didExitFullscreen();
-                        protect = nullptr;
-                    });
-                } else {
-                    if (m_videoFullscreenModel)
-                        m_videoFullscreenModel->requestExitFullscreen();
-                }
-            }];
-        } else if (m_mode == HTMLMediaElement::VideoFullscreenModeStandard) {
-            [m_playerViewController enterFullScreenWithCompletionHandler:^(BOOL, NSError*)
-            {
-                [m_playerViewController setShowsPlaybackControls:YES];
-                
-                WebThreadRun(^{
-                    if (m_fullscreenChangeObserver)
-                        m_fullscreenChangeObserver->didEnterFullscreen();
-                    
-                    protect = nullptr;
-                });
-            }];
-        }
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+    dispatch_async(dispatch_get_main_queue(), [strongThis] {
+        [strongThis->m_videoLayerContainer setBackgroundColor:[[getUIColorClass() blackColor] CGColor]];
+        if (strongThis->mode() == HTMLMediaElement::VideoFullscreenModeOptimized)
+            strongThis->enterFullscreenOptimized();
+        else if (strongThis->mode() == HTMLMediaElement::VideoFullscreenModeStandard)
+            strongThis->enterFullscreenStandard();
+        else
+            ASSERT_NOT_REACHED();
     });
 }
 
+void WebVideoFullscreenInterfaceAVKit::enterFullscreenOptimized()
+{
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
+    auto startCompletionHandler = [this, strongThis] (BOOL success, NSError *) {
+        [m_playerViewController setShowsPlaybackControls:YES];
+
+        WebThreadRun([this, strongThis, success] {
+            [m_window setHidden:YES];
+            if (m_fullscreenChangeObserver)
+                m_fullscreenChangeObserver->didEnterFullscreen();
+
+            if (!success) {
+                if (m_videoFullscreenModel)
+                    m_videoFullscreenModel->requestExitFullscreen();
+            }
+        });
+    };
+
+    auto stopCompletionHandler = [this, strongThis] (AVPlayerViewControllerOptimizedFullscreenStopReason reason) {
+        m_exitCompleted = true;
+
+        if (m_fullscreenChangeObserver && reason == AVPlayerViewControllerOptimizedFullscreenStopReasonStopped)
+            m_fullscreenChangeObserver->fullscreenMayReturnToInline();
+        if (m_exitRequested) {
+            [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
+            [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
+            WebThreadRun([this, strongThis] {
+                if (m_fullscreenChangeObserver)
+                    m_fullscreenChangeObserver->didExitFullscreen();
+            });
+        } else {
+            if (m_videoFullscreenModel)
+                m_videoFullscreenModel->requestExitFullscreen();
+        }
+    };
+
+    [m_playerViewController startOptimizedFullscreenWithStartCompletionHandler:startCompletionHandler stopCompletionHandler:stopCompletionHandler];
+}
+
+void WebVideoFullscreenInterfaceAVKit::enterFullscreenStandard()
+{
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+    [m_playerViewController enterFullScreenWithCompletionHandler:[this, strongThis] (BOOL, NSError*) {
+        [m_playerViewController setShowsPlaybackControls:YES];
+
+        WebThreadRun([this, strongThis] {
+            if (m_fullscreenChangeObserver)
+                m_fullscreenChangeObserver->didEnterFullscreen();
+        });
+    }];
+}
+
 void WebVideoFullscreenInterfaceAVKit::exitFullscreen(WebCore::IntRect finalRect)
 {
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
     m_exitRequested = true;
     if (m_exitCompleted) {
-        WebThreadRun(^{
-            if (m_fullscreenChangeObserver)
-                m_fullscreenChangeObserver->didExitFullscreen();
-            protect = nullptr;
+        WebThreadRun([strongThis] {
+            if (strongThis->m_fullscreenChangeObserver)
+                strongThis->m_fullscreenChangeObserver->didExitFullscreen();
         });
         return;
     }
-    
+
     m_playerController = nil;
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [m_playerViewController setShowsPlaybackControls:NO];
-        if (m_viewController)
-            [m_playerViewController view].frame = [m_parentView convertRect:finalRect toView:nil];
-        else
-            [m_playerViewController view].frame = finalRect;
 
-        if ([m_videoLayerContainer videoLayerGravity] != AVVideoLayerGravityResizeAspect)
-            [m_videoLayerContainer setVideoLayerGravity:AVVideoLayerGravityResizeAspect];
-        [[m_playerViewController view] layoutIfNeeded];
-        
-        if (m_mode == HTMLMediaElement::VideoFullscreenModeOptimized) {
-            [m_window setHidden:NO];
-            [m_playerViewController stopOptimizedFullscreen];
-        } else if (m_mode == (HTMLMediaElement::VideoFullscreenModeOptimized | HTMLMediaElement::VideoFullscreenModeStandard)) {
-            [m_playerViewController exitFullScreenAnimated:NO completionHandler:^(BOOL , NSError *) {
-                [m_window setHidden:NO];
-                [m_playerViewController stopOptimizedFullscreen];
-            }];
-        } else if (m_mode == HTMLMediaElement::VideoFullscreenModeStandard) {
-            [m_playerViewController exitFullScreenWithCompletionHandler:^(BOOL, NSError*) {
-                m_exitCompleted = true;
-                [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
-                [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
-                WebThreadRun(^{
-                    if (m_fullscreenChangeObserver)
-                        m_fullscreenChangeObserver->didExitFullscreen();
-                    protect = nullptr;
-                });
-
-            }];
-        }
+    dispatch_async(dispatch_get_main_queue(), [strongThis, finalRect] {
+        strongThis->exitFullscreenInternal(finalRect);
     });
 }
 
+void WebVideoFullscreenInterfaceAVKit::exitFullscreenInternal(WebCore::IntRect finalRect)
+{
+    [m_playerViewController setShowsPlaybackControls:NO];
+    if (m_viewController)
+        [m_playerViewController view].frame = [m_parentView convertRect:finalRect toView:nil];
+    else
+        [m_playerViewController view].frame = finalRect;
+
+    if ([m_videoLayerContainer videoLayerGravity] != AVVideoLayerGravityResizeAspect)
+        [m_videoLayerContainer setVideoLayerGravity:AVVideoLayerGravityResizeAspect];
+    [[m_playerViewController view] layoutIfNeeded];
+
+
+    if (m_mode == HTMLMediaElement::VideoFullscreenModeOptimized) {
+        [m_window setHidden:NO];
+        [m_playerViewController stopOptimizedFullscreen];
+    } else if (m_mode == (HTMLMediaElement::VideoFullscreenModeOptimized | HTMLMediaElement::VideoFullscreenModeStandard)) {
+        RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[strongThis] (BOOL, NSError*) {
+            [strongThis->m_window setHidden:NO];
+            [strongThis->m_playerViewController stopOptimizedFullscreen];
+        }];
+    } else if (m_mode == HTMLMediaElement::VideoFullscreenModeStandard) {
+        RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+        [m_playerViewController exitFullScreenWithCompletionHandler:[strongThis] (BOOL, NSError*) {
+            strongThis->m_exitCompleted = true;
+            [strongThis->m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
+            [[strongThis->m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
+            WebThreadRun([strongThis] {
+                if (strongThis->m_fullscreenChangeObserver)
+                    strongThis->m_fullscreenChangeObserver->didExitFullscreen();
+            });
+        }];
+    };
+}
+
 @interface UIApplication ()
 -(void)_setStatusBarOrientation:(UIInterfaceOrientation)o;
 @end
@@ -1003,42 +991,46 @@
 
 void WebVideoFullscreenInterfaceAVKit::cleanupFullscreen()
 {
-    // Retain this to extend object life until async block completes.
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        if (m_window) {
-            [m_window setHidden:YES];
-            [m_window setRootViewController:nil];
-            if (m_parentWindow)
-                [[getUIApplicationClass() sharedApplication] _setStatusBarOrientation:[m_parentWindow interfaceOrientation]];
-        }
-        [m_playerViewController setDelegate:nil];
-        [[m_playerViewController view] removeFromSuperview];
-        if (m_viewController)
-            [m_playerViewController removeFromParentViewController];
-        [m_playerViewController setPlayerController:nil];
-        m_playerViewController = nil;
-        [m_videoLayer removeFromSuperlayer];
-        m_videoLayer = nil;
-        [m_videoLayerContainer removeFromSuperlayer];
-        [m_videoLayerContainer setPlayerViewController:nil];
-        m_videoLayerContainer = nil;
-        [[m_viewController view] removeFromSuperview];
-        m_viewController = nil;
-        m_window = nil;
-        m_parentView = nil;
-        m_parentWindow = nil;
-        
-        WebThreadRun(^{
-            if (m_fullscreenChangeObserver)
-                m_fullscreenChangeObserver->didCleanupFullscreen();
-            m_enterRequested = false;
-            protect = nullptr;
-        });
+    dispatch_async(dispatch_get_main_queue(), [strongThis] {
+        strongThis->cleanupFullscreenInternal();
     });
 }
 
+void WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal()
+{
+    if (m_window) {
+        [m_window setHidden:YES];
+        [m_window setRootViewController:nil];
+        if (m_parentWindow)
+            [[getUIApplicationClass() sharedApplication] _setStatusBarOrientation:[m_parentWindow interfaceOrientation]];
+    }
+    [m_playerViewController setDelegate:nil];
+    [[m_playerViewController view] removeFromSuperview];
+    if (m_viewController)
+        [m_playerViewController removeFromParentViewController];
+    [m_playerViewController setPlayerController:nil];
+    m_playerViewController = nil;
+    [m_videoLayer removeFromSuperlayer];
+    m_videoLayer = nil;
+    [m_videoLayerContainer removeFromSuperlayer];
+    [m_videoLayerContainer setPlayerViewController:nil];
+    m_videoLayerContainer = nil;
+    [[m_viewController view] removeFromSuperview];
+    m_viewController = nil;
+    m_window = nil;
+    m_parentView = nil;
+    m_parentWindow = nil;
+    
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+    WebThreadRun([strongThis] {
+        if (strongThis->m_fullscreenChangeObserver)
+            strongThis->m_fullscreenChangeObserver->didCleanupFullscreen();
+        strongThis->m_enterRequested = false;
+    });
+}
+
 void WebVideoFullscreenInterfaceAVKit::invalidate()
 {
     [m_window setHidden:YES];
@@ -1076,13 +1068,10 @@
     if (m_mode & HTMLMediaElement::VideoFullscreenModeOptimized)
         return;
     
-    __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [m_window setHidden:YES];
-        [m_playerViewController exitFullScreenAnimated:NO completionHandler:^(BOOL, NSError*) {
-            WebThreadRun(^{
-                protect = nullptr;
-            });
+    RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+    dispatch_async(dispatch_get_main_queue(), [strongThis] {
+        [strongThis->m_window setHidden:YES];
+        [strongThis->m_playerViewController exitFullScreenAnimated:NO completionHandler:[strongThis] (BOOL, NSError*) {
         }];
     });
 
@@ -1112,7 +1101,7 @@
 
     if (!m_exitRequested || active)
         return;
-    
+
     m_exitCompleted = true;
     [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
     [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to