<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[177375] trunk/Source/WebCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/177375">177375</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-12-16 11:20:46 -0800 (Tue, 16 Dec 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>[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.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformiosWebVideoFullscreenInterfaceAVKith">trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h</a></li>
<li><a href="#trunkSourceWebCoreplatformiosWebVideoFullscreenInterfaceAVKitmm">trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (177374 => 177375)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2014-12-16 Jer Noble <jer.noble@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.
+
</ins><span class="cx"> 2014-12-16 Ryosuke Niwa <rniwa@webkit.org>
</span><span class="cx">
</span><span class="cx"> Nested template contents are not cloned by document.importNode
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformiosWebVideoFullscreenInterfaceAVKith"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h (177374 => 177375)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include <WebCore/WebVideoFullscreenInterface.h>
</span><span class="cx"> #include <wtf/RefPtr.h>
</span><span class="cx"> #include <wtf/RetainPtr.h>
</span><ins>+#include <wtf/ThreadSafeRefCounted.h>
</ins><span class="cx">
</span><span class="cx"> OBJC_CLASS WebAVPlayerController;
</span><span class="cx"> OBJC_CLASS AVPlayerViewController;
</span><span class="lines">@@ -64,7 +65,7 @@
</span><span class="cx">
</span><span class="cx"> class WebVideoFullscreenInterfaceAVKit
</span><span class="cx"> : public WebVideoFullscreenInterface
</span><del>- , public RefCounted<WebVideoFullscreenInterfaceAVKit> {
</del><ins>+ , public ThreadSafeRefCounted<WebVideoFullscreenInterfaceAVKit> {
</ins><span class="cx">
</span><span class="cx"> public:
</span><span class="cx"> WEBCORE_EXPORT WebVideoFullscreenInterfaceAVKit();
</span><span class="lines">@@ -94,7 +95,12 @@
</span><span class="cx"> bool mayAutomaticallyShowVideoOptimized();
</span><span class="cx">
</span><span class="cx"> protected:
</span><del>-
</del><ins>+ void setupFullscreenInternal(PlatformLayer&, IntRect initialRect, UIView *, HTMLMediaElement::VideoFullscreenMode, bool allowOptimizedFullscreen);
+ void enterFullscreenOptimized();
+ void enterFullscreenStandard();
+ void exitFullscreenInternal(IntRect finalRect);
+ void cleanupFullscreenInternal();
+
</ins><span class="cx"> RetainPtr<WebAVPlayerController> m_playerController;
</span><span class="cx"> RetainPtr<AVPlayerViewController> m_playerViewController;
</span><span class="cx"> RetainPtr<CALayer> m_videoLayer;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformiosWebVideoFullscreenInterfaceAVKitmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm (177374 => 177375)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -649,11 +649,11 @@
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setDuration(double duration)
</span><span class="cx"> {
</span><del>- WebAVPlayerController* playerController = this->playerController();
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-
- dispatch_async(dispatch_get_main_queue(), ^{
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, duration] {
+ WebAVPlayerController* playerController = strongThis->playerController();
+
</ins><span class="cx"> // FIXME: https://bugs.webkit.org/show_bug.cgi?id=127017 use correct values instead of duration for all these
</span><span class="cx"> playerController.contentDuration = duration;
</span><span class="cx"> playerController.maxTime = duration;
</span><span class="lines">@@ -668,59 +668,43 @@
</span><span class="cx"> playerController.canSeek = YES;
</span><span class="cx"> playerController.minTime = 0;
</span><span class="cx"> playerController.status = AVPlayerControllerStatusReadyToPlay;
</span><del>-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setCurrentTime(double currentTime, double anchorTime)
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- NSTimeInterval anchorTimeStamp = ![playerController() rate] ? NAN : anchorTime;
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, currentTime, anchorTime] {
+ NSTimeInterval anchorTimeStamp = ![strongThis->playerController() rate] ? NAN : anchorTime;
</ins><span class="cx"> AVValueTiming *timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime
</span><span class="cx"> anchorTimeStamp:anchorTimeStamp rate:0];
</span><del>- playerController().timing = timing;
-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><ins>+ strongThis->playerController().timing = timing;
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setRate(bool isPlaying, float playbackRate)
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- playerController().rate = isPlaying ? playbackRate : 0.;
-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, isPlaying, playbackRate] {
+ strongThis->playerController().rate = isPlaying ? playbackRate : 0.;
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setVideoDimensions(bool hasVideo, float width, float height)
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- playerController().hasEnabledVideo = hasVideo;
- playerController().contentDimensions = CGSizeMake(width, height);
-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, hasVideo, width, height] {
+ strongThis->playerController().hasEnabledVideo = hasVideo;
+ strongThis->playerController().contentDimensions = CGSizeMake(width, height);
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setSeekableRanges(const TimeRanges& timeRanges)
</span><span class="cx"> {
</span><del>- NSMutableArray* seekableRanges = [NSMutableArray array];
</del><ins>+ RetainPtr<NSMutableArray> seekableRanges = adoptNS([[NSMutableArray alloc] init]);
</ins><span class="cx"> ExceptionCode exceptionCode;
</span><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < timeRanges.length(); i++) {
</span><span class="lines">@@ -731,14 +715,10 @@
</span><span class="cx"> [seekableRanges addObject:[NSValue valueWithCMTimeRange:range]];
</span><span class="cx"> }
</span><span class="cx">
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- playerController().seekableTimeRanges = seekableRanges;
-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, seekableRanges] {
+ strongThis->playerController().seekableTimeRanges = seekableRanges.get();
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -747,9 +727,9 @@
</span><span class="cx"> playerController().canScanBackward = canPlayFastReverse;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static NSMutableArray *mediaSelectionOptions(const Vector<String>& options)
</del><ins>+static RetainPtr<NSMutableArray> mediaSelectionOptions(const Vector<String>& options)
</ins><span class="cx"> {
</span><del>- NSMutableArray *webOptions = [NSMutableArray arrayWithCapacity:options.size()];
</del><ins>+ RetainPtr<NSMutableArray> webOptions = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
</ins><span class="cx"> for (auto& name : options) {
</span><span class="cx"> RetainPtr<WebAVMediaSelectionOption> webOption = adoptNS([[WebAVMediaSelectionOption alloc] init]);
</span><span class="cx"> [webOption setLocalizedDisplayName:name];
</span><span class="lines">@@ -760,33 +740,25 @@
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
</span><span class="cx"> {
</span><del>- NSMutableArray *webOptions = mediaSelectionOptions(options);
- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RetainPtr<NSMutableArray> webOptions = mediaSelectionOptions(options);
+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- playerController().audioMediaSelectionOptions = webOptions;
- if (selectedIndex < webOptions.count)
- playerController().currentAudioMediaSelectionOption = webOptions[(size_t)selectedIndex];
-
- WebThreadRun(^{
- protect = nullptr;
- });
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [webOptions, strongThis, selectedIndex] {
+ strongThis->playerController().audioMediaSelectionOptions = webOptions.get();
+ if (selectedIndex < [webOptions count])
+ strongThis->playerController().currentAudioMediaSelectionOption = [webOptions objectAtIndex:selectedIndex];
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
</span><span class="cx"> {
</span><del>- 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;
- });
</del><ins>+ 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];
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -798,201 +770,217 @@
</span><span class="cx"> else if (targetType == TargetTypeTVOut)
</span><span class="cx"> externalPlaybackType = AVPlayerControllerExternalPlaybackTypeTVOut;
</span><span class="cx">
</span><del>- __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;
- });
</del><ins>+ 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];
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::setupFullscreen(PlatformLayer& videoLayer, WebCore::IntRect initialRect, UIView* parentView, HTMLMediaElement::VideoFullscreenMode mode, bool allowOptimizedFullscreen)
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
</ins><span class="cx"> ASSERT(mode != HTMLMediaElement::VideoFullscreenModeNone);
</span><span class="cx"> m_videoLayer = &videoLayer;
</span><del>-
</del><ins>+
</ins><span class="cx"> m_mode = mode;
</span><del>-
- dispatch_async(dispatch_get_main_queue(), ^{
</del><span class="cx">
</span><del>- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- m_parentView = parentView;
- m_parentWindow = parentView.window;
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, &videoLayer, initialRect, parentView, mode, allowOptimizedFullscreen] {
+ strongThis->setupFullscreenInternal(videoLayer, initialRect, parentView, mode, allowOptimizedFullscreen);
+ });
+}
</ins><span class="cx">
</span><del>- 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];
</del><ins>+void WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal(PlatformLayer& videoLayer, WebCore::IntRect initialRect, UIView* parentView, HTMLMediaElement::VideoFullscreenMode mode, bool allowOptimizedFullscreen)
+{
+ UNUSED_PARAM(videoLayer);
+ UNUSED_PARAM(mode);
</ins><span class="cx">
</span><del>- 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];
</del><ins>+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+ m_parentView = parentView;
+ m_parentWindow = parentView.window;
</ins><span class="cx">
</span><del>- [m_videoLayerContainer setPlayerViewController:m_playerViewController.get()];
</del><ins>+ 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];
+ }
</ins><span class="cx">
</span><del>- 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;
- }
</del><ins>+ [m_videoLayer removeFromSuperlayer];
</ins><span class="cx">
</span><del>- [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
- [[m_playerViewController view] setNeedsLayout];
- [[m_playerViewController view] layoutIfNeeded];
</del><ins>+ m_videoLayerContainer = [WebAVVideoLayer videoLayer];
+ [m_videoLayerContainer setHidden:playerController().externalPlaybackActive];
+ [m_videoLayerContainer setVideoSublayer:m_videoLayer.get()];
</ins><span class="cx">
</span><del>- [CATransaction commit];
</del><ins>+ CGSize videoSize = playerController().contentDimensions;
+ CGRect videoRect = CGRectMake(0, 0, videoSize.width, videoSize.height);
+ [m_videoLayerContainer setVideoRect:videoRect];
</ins><span class="cx">
</span><del>- dispatch_async(dispatch_get_main_queue(), ^{
- WebThreadRun(^{
- if (m_fullscreenChangeObserver)
- m_fullscreenChangeObserver->didSetupFullscreen();
</del><ins>+ 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];
</ins><span class="cx">
</span><del>- protect = nullptr;
- });
- });
</del><ins>+ [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();
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::enterFullscreen()
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-
</del><span class="cx"> m_exitCompleted = false;
</span><span class="cx"> m_exitRequested = false;
</span><span class="cx"> m_enterRequested = true;
</span><del>-
- 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();
</del><span class="cx">
</span><del>- 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;
- });
- }];
- }
</del><ins>+ 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();
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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();
+ });
+ }];
+}
+
</ins><span class="cx"> void WebVideoFullscreenInterfaceAVKit::exitFullscreen(WebCore::IntRect finalRect)
</span><span class="cx"> {
</span><del>- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
-
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
+
</ins><span class="cx"> m_exitRequested = true;
</span><span class="cx"> if (m_exitCompleted) {
</span><del>- WebThreadRun(^{
- if (m_fullscreenChangeObserver)
- m_fullscreenChangeObserver->didExitFullscreen();
- protect = nullptr;
</del><ins>+ WebThreadRun([strongThis] {
+ if (strongThis->m_fullscreenChangeObserver)
+ strongThis->m_fullscreenChangeObserver->didExitFullscreen();
</ins><span class="cx"> });
</span><span class="cx"> return;
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> m_playerController = nil;
</span><del>-
- 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;
</del><span class="cx">
</span><del>- 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;
- });
-
- }];
- }
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis, finalRect] {
+ strongThis->exitFullscreenInternal(finalRect);
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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();
+ });
+ }];
+ };
+}
+
</ins><span class="cx"> @interface UIApplication ()
</span><span class="cx"> -(void)_setStatusBarOrientation:(UIInterfaceOrientation)o;
</span><span class="cx"> @end
</span><span class="lines">@@ -1003,42 +991,46 @@
</span><span class="cx">
</span><span class="cx"> void WebVideoFullscreenInterfaceAVKit::cleanupFullscreen()
</span><span class="cx"> {
</span><del>- // Retain this to extend object life until async block completes.
- __block RefPtr<WebVideoFullscreenInterfaceAVKit> protect(this);
</del><ins>+ RefPtr<WebVideoFullscreenInterfaceAVKit> strongThis(this);
</ins><span class="cx">
</span><del>- 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;
- });
</del><ins>+ dispatch_async(dispatch_get_main_queue(), [strongThis] {
+ strongThis->cleanupFullscreenInternal();
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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;
+ });
+}
+
</ins><span class="cx"> void WebVideoFullscreenInterfaceAVKit::invalidate()
</span><span class="cx"> {
</span><span class="cx"> [m_window setHidden:YES];
</span><span class="lines">@@ -1076,13 +1068,10 @@
</span><span class="cx"> if (m_mode & HTMLMediaElement::VideoFullscreenModeOptimized)
</span><span class="cx"> return;
</span><span class="cx">
</span><del>- __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;
- });
</del><ins>+ 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*) {
</ins><span class="cx"> }];
</span><span class="cx"> });
</span><span class="cx">
</span><span class="lines">@@ -1112,7 +1101,7 @@
</span><span class="cx">
</span><span class="cx"> if (!m_exitRequested || active)
</span><span class="cx"> return;
</span><del>-
</del><ins>+
</ins><span class="cx"> m_exitCompleted = true;
</span><span class="cx"> [m_videoLayerContainer setBackgroundColor:[[getUIColorClass() clearColor] CGColor]];
</span><span class="cx"> [[m_playerViewController view] setBackgroundColor:[getUIColorClass() clearColor]];
</span></span></pre>
</div>
</div>
</body>
</html>