Enable API related to the video fullscreen layer in MediaPlayerPrivateAVFoundationObjC
authoradachan@apple.com <adachan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jan 2016 18:35:36 +0000 (18:35 +0000)
committeradachan@apple.com <adachan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Jan 2016 18:35:36 +0000 (18:35 +0000)
also on Mac with video presentation mode support.
https://bugs.webkit.org/show_bug.cgi?id=153222

Reviewed by Eric Carlson.

No new tests. Covered by existing tests.

Introduce VideoFullscreenLayerManager to deal with the video layer when switching
between inline and fullscreen mode. We'll reuse it in other MediaPlayerPrivateInterface
implementations.

Now that MediaPlayerPrivateAVFoundationObjC's platform layer can be a WebVideoContainerLayer,
this exposes a bug in PlatformCALayerCocoa::clone() where we assumed the platform layer
is always an AVPlayerLayer if the PlatformCALayer's layer type is LayerTypeAVPlayerLayer.
Add a helper method to get an AVPlayerLayer from a PlatformCALayerCocoa (which also handles
WebVideoContainerLayer case) and use it in PlatformCALayerCocoa::clone().

* WebCore.xcodeproj/project.pbxproj:
Add VideoFullscreenLayerManager to the project.

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC):
Create m_videoFullscreenLayerManager. The video inline layer, video fullscreen layer,
and the video fullscreen frame are now managed by that class.
(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayerLayer):
Just call VideoFullscreenLayerManager::setVideoLayer() to handle adding the video
layer in either the inline or fullscreen layer.
(WebCore::MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer):
Call VideoFullscreenLayerManager::didDestroyVideoLayer().
(WebCore::MediaPlayerPrivateAVFoundationObjC::platformLayer):
Get the video inline layer from VideoFullscreenLayerManager.
(WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer):
Call VideoFullscreenLayerManager::setVideoFullscreenLayer().
(WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenFrame):
Call VideoFullscreenLayerManager::setVideoFullscreenFrame().
(WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenMode):
Guard the iOS specific code properly.
(WebCore::MediaPlayerPrivateAVFoundationObjC::updateVideoLayerGravity):
Get the video fullscreen layer from VideoFullscreenLayerManager.
(WebCore::MediaPlayerPrivateAVFoundationObjC::requiresTextTrackRepresentation):
Ditto.
(WebCore::MediaPlayerPrivateAVFoundationObjC::syncTextTrackBounds):
Get the video fullscreen layer and video fullscreen frame from VideoFullscreenLayerManager.
(WebCore::MediaPlayerPrivateAVFoundationObjC::setTextTrackRepresentation):
Get the video fullscreen layer from VideoFullscreenLayerManager.

* platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.h: Added.
(WebCore::VideoFullscreenLayerManager::videoInlineLayer):
(WebCore::VideoFullscreenLayerManager::videoFullscreenLayer):
(WebCore::VideoFullscreenLayerManager::videoFullscreenFrame):
* platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.mm: Added.
(-[WebVideoContainerLayer setBounds:]):
(-[WebVideoContainerLayer setPosition:]):
WebVideoContainerLayer was moved from MediaPlayerPrivateAVFoundationObjC.mm.
(WebCore::VideoFullscreenLayerManager::create):
(WebCore::VideoFullscreenLayerManager::VideoFullscreenLayerManager):
(WebCore::VideoFullscreenLayerManager::setVideoLayer):
Code moved from MediaPlayerPrivateAVFoundationObjC::createAVPlayerLayer().
(WebCore::VideoFullscreenLayerManager::setVideoFullscreenLayer):
Code moved from MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer().
(WebCore::VideoFullscreenLayerManager::setVideoFullscreenFrame):
Code moved from MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenFrame().
(WebCore::VideoFullscreenLayerManager::didDestroyVideoLayer):
Code moved from MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer().

* platform/graphics/ca/cocoa/PlatformCALayerCocoa.h:
* platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
(PlatformCALayerCocoa::clone):
Use the new PlatformCALayerCocoa::avPlayerLayer() method to get the AVPlayerLayer from both the
destination and source PlatformCALayers.
(PlatformCALayerCocoa::avPlayerLayer):
Return nil if the layer type is not LayerTypeAVPlayerLayer. Otherwise, return the
platform layer if it is indeed an AVPlayerLayer. If not, it should be a WebVideoContainerLayer
and we should return its sublayer which should be an AVPlayerLayer.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@195595 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm
Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.h [new file with mode: 0644]
Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.mm [new file with mode: 0644]
Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.h
Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm

index 9ef721b..16e0ce6 100644 (file)
@@ -1,3 +1,82 @@
+2016-01-22  Ada Chan  <adachan@apple.com>
+
+        Enable API related to the video fullscreen layer in MediaPlayerPrivateAVFoundationObjC
+        also on Mac with video presentation mode support.
+        https://bugs.webkit.org/show_bug.cgi?id=153222
+
+        Reviewed by Eric Carlson.
+
+        No new tests. Covered by existing tests.
+
+        Introduce VideoFullscreenLayerManager to deal with the video layer when switching
+        between inline and fullscreen mode. We'll reuse it in other MediaPlayerPrivateInterface
+        implementations.
+
+        Now that MediaPlayerPrivateAVFoundationObjC's platform layer can be a WebVideoContainerLayer,
+        this exposes a bug in PlatformCALayerCocoa::clone() where we assumed the platform layer
+        is always an AVPlayerLayer if the PlatformCALayer's layer type is LayerTypeAVPlayerLayer.
+        Add a helper method to get an AVPlayerLayer from a PlatformCALayerCocoa (which also handles
+        WebVideoContainerLayer case) and use it in PlatformCALayerCocoa::clone().
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Add VideoFullscreenLayerManager to the project.
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC):
+        Create m_videoFullscreenLayerManager. The video inline layer, video fullscreen layer,
+        and the video fullscreen frame are now managed by that class.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayerLayer):
+        Just call VideoFullscreenLayerManager::setVideoLayer() to handle adding the video
+        layer in either the inline or fullscreen layer.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer):
+        Call VideoFullscreenLayerManager::didDestroyVideoLayer().
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::platformLayer):
+        Get the video inline layer from VideoFullscreenLayerManager.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer):
+        Call VideoFullscreenLayerManager::setVideoFullscreenLayer().
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenFrame):
+        Call VideoFullscreenLayerManager::setVideoFullscreenFrame().
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenMode):
+        Guard the iOS specific code properly.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::updateVideoLayerGravity):
+        Get the video fullscreen layer from VideoFullscreenLayerManager.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::requiresTextTrackRepresentation):
+        Ditto.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::syncTextTrackBounds):
+        Get the video fullscreen layer and video fullscreen frame from VideoFullscreenLayerManager.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setTextTrackRepresentation):
+        Get the video fullscreen layer from VideoFullscreenLayerManager.
+
+        * platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.h: Added.
+        (WebCore::VideoFullscreenLayerManager::videoInlineLayer):
+        (WebCore::VideoFullscreenLayerManager::videoFullscreenLayer):
+        (WebCore::VideoFullscreenLayerManager::videoFullscreenFrame):
+        * platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.mm: Added.
+        (-[WebVideoContainerLayer setBounds:]):
+        (-[WebVideoContainerLayer setPosition:]):
+        WebVideoContainerLayer was moved from MediaPlayerPrivateAVFoundationObjC.mm.
+        (WebCore::VideoFullscreenLayerManager::create):
+        (WebCore::VideoFullscreenLayerManager::VideoFullscreenLayerManager):
+        (WebCore::VideoFullscreenLayerManager::setVideoLayer):
+        Code moved from MediaPlayerPrivateAVFoundationObjC::createAVPlayerLayer().
+        (WebCore::VideoFullscreenLayerManager::setVideoFullscreenLayer):
+        Code moved from MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer().
+        (WebCore::VideoFullscreenLayerManager::setVideoFullscreenFrame):
+        Code moved from MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenFrame().
+        (WebCore::VideoFullscreenLayerManager::didDestroyVideoLayer):
+        Code moved from MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer().
+
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.h:
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
+        (PlatformCALayerCocoa::clone):
+        Use the new PlatformCALayerCocoa::avPlayerLayer() method to get the AVPlayerLayer from both the
+        destination and source PlatformCALayers.
+        (PlatformCALayerCocoa::avPlayerLayer):
+        Return nil if the layer type is not LayerTypeAVPlayerLayer. Otherwise, return the
+        platform layer if it is indeed an AVPlayerLayer. If not, it should be a WebVideoContainerLayer
+        and we should return its sublayer which should be an AVPlayerLayer.
+
 2016-01-26  Chris Dumez  <cdumez@apple.com>
 
         First parameter to window.showModalDialog() should be mandatory
index fc5d1d7..44bf33c 100644 (file)
                52CCA9E815E3F64C0053C77F /* DOMDOMNamedFlowCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 52CCA9E515E3F64C0053C77F /* DOMDOMNamedFlowCollection.h */; };
                52CCA9E915E3F64C0053C77F /* DOMDOMNamedFlowCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 52CCA9E615E3F64C0053C77F /* DOMDOMNamedFlowCollection.mm */; };
                52CCA9EA15E3F64C0053C77F /* DOMDOMNamedFlowCollectionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 52CCA9E715E3F64C0053C77F /* DOMDOMNamedFlowCollectionInternal.h */; };
+               52D5A18F1C54592300DE34A3 /* VideoFullscreenLayerManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 52D5A18D1C54590300DE34A3 /* VideoFullscreenLayerManager.mm */; };
                52E2CAFC19FF0207001EEB4F /* MediaProducer.h in Headers */ = {isa = PBXBuildFile; fileRef = 52E2CAFB19FF0207001EEB4F /* MediaProducer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52F10865162B6DA4009AC81E /* MixedContentChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52F10862162B6D82009AC81E /* MixedContentChecker.cpp */; };
                52F10866162B6DA8009AC81E /* MixedContentChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 52F10863162B6D82009AC81E /* MixedContentChecker.h */; settings = {ATTRIBUTES = (Private, ); }; };
                52CCA9E515E3F64C0053C77F /* DOMDOMNamedFlowCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMDOMNamedFlowCollection.h; sourceTree = "<group>"; };
                52CCA9E615E3F64C0053C77F /* DOMDOMNamedFlowCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMDOMNamedFlowCollection.mm; sourceTree = "<group>"; };
                52CCA9E715E3F64C0053C77F /* DOMDOMNamedFlowCollectionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMDOMNamedFlowCollectionInternal.h; sourceTree = "<group>"; };
+               52D5A18D1C54590300DE34A3 /* VideoFullscreenLayerManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoFullscreenLayerManager.mm; sourceTree = "<group>"; };
+               52D5A18E1C54590300DE34A3 /* VideoFullscreenLayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenLayerManager.h; sourceTree = "<group>"; };
                52E2CAFB19FF0207001EEB4F /* MediaProducer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaProducer.h; sourceTree = "<group>"; };
                52F10862162B6D82009AC81E /* MixedContentChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MixedContentChecker.cpp; sourceTree = "<group>"; };
                52F10863162B6D82009AC81E /* MixedContentChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MixedContentChecker.h; sourceTree = "<group>"; };
                                7A29F57118C69514004D0F81 /* OutOfBandTextTrackPrivateAVF.h */,
                                CDC8B5A918047FF10016E685 /* SourceBufferPrivateAVFObjC.h */,
                                CDC8B5A818047FF10016E685 /* SourceBufferPrivateAVFObjC.mm */,
+                               52D5A18E1C54590300DE34A3 /* VideoFullscreenLayerManager.h */,
+                               52D5A18D1C54590300DE34A3 /* VideoFullscreenLayerManager.mm */,
                                CD336F6517FA0AC600DDDCD0 /* VideoTrackPrivateAVFObjC.cpp */,
                                CD336F6617FA0AC600DDDCD0 /* VideoTrackPrivateAVFObjC.h */,
                                CD8B5A41180D149A008B8E65 /* VideoTrackPrivateMediaSourceAVFObjC.h */,
                                2E3BBF071162DA1100B9409A /* UUID.cpp in Sources */,
                                F5A154271279534D00D0B0C0 /* ValidationMessage.cpp in Sources */,
                                FD3160AE12B026F700C1A359 /* VectorMath.cpp in Sources */,
+                               52D5A18F1C54592300DE34A3 /* VideoFullscreenLayerManager.mm in Sources */,
                                CDE83DB1183C44060031EAA3 /* VideoPlaybackQuality.cpp in Sources */,
                                BE88E0DE1715D2A200658D98 /* VideoTrack.cpp in Sources */,
                                BE88E0E11715D2A200658D98 /* VideoTrackList.cpp in Sources */,
index 0af3ea3..ab91dc5 100644 (file)
@@ -74,6 +74,10 @@ class MediaSelectionGroupAVFObjC;
 class VideoTrackPrivateAVFObjC;
 class WebCoreAVFResourceLoader;
 
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+class VideoFullscreenLayerManager;
+#endif
+
 class MediaPlayerPrivateAVFoundationObjC : public MediaPlayerPrivateAVFoundation {
 public:
     explicit MediaPlayerPrivateAVFoundationObjC(MediaPlayer*);
@@ -160,12 +164,14 @@ private:
     virtual void paint(GraphicsContext&, const FloatRect&) override;
     virtual void paintCurrentFrameInContext(GraphicsContext&, const FloatRect&) override;
     virtual PlatformLayer* platformLayer() const override;
-#if PLATFORM(IOS)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     virtual void setVideoFullscreenLayer(PlatformLayer*) override;
     virtual void setVideoFullscreenFrame(FloatRect) override;
     virtual void setVideoFullscreenGravity(MediaPlayer::VideoGravity) override;
     virtual void setVideoFullscreenMode(MediaPlayer::VideoFullscreenMode) override;
+#endif
 
+#if PLATFORM(IOS)
     virtual NSArray *timedMetadata() const override;
     virtual String accessLog() const override;
     virtual String errorLog() const override;
@@ -315,10 +321,8 @@ private:
     RetainPtr<AVPlayer> m_avPlayer;
     RetainPtr<AVPlayerItem> m_avPlayerItem;
     RetainPtr<AVPlayerLayer> m_videoLayer;
-#if PLATFORM(IOS)
-    RetainPtr<PlatformLayer> m_videoInlineLayer;
-    RetainPtr<PlatformLayer> m_videoFullscreenLayer;
-    FloatRect m_videoFullscreenFrame;
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    std::unique_ptr<VideoFullscreenLayerManager> m_videoFullscreenLayerManager;
     MediaPlayer::VideoGravity m_videoFullscreenGravity;
     RetainPtr<PlatformLayer> m_textTrackRepresentationLayer;
 #endif
index f52db19..7321ca5 100644 (file)
 #endif
 
 #import <AVFoundation/AVFoundation.h>
+
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+#import "VideoFullscreenLayerManager.h"
+#endif
+
 #if PLATFORM(IOS)
 #import "WAKAppKitStubs.h"
 #import <CoreImage/CoreImage.h>
@@ -113,28 +118,6 @@ template <> struct iterator_traits<HashSet<RefPtr<WebCore::MediaSelectionOptionA
 };
 }
 
-@interface WebVideoContainerLayer : CALayer
-@end
-
-@implementation WebVideoContainerLayer
-
-- (void)setBounds:(CGRect)bounds
-{
-    [super setBounds:bounds];
-    for (CALayer* layer in self.sublayers)
-        layer.frame = bounds;
-}
-
-- (void)setPosition:(CGPoint)position
-{
-    if (!CATransform3DIsIdentity(self.transform)) {
-        // Pre-apply the transform added in the WebProcess to fix <rdar://problem/18316542> to the position.
-        position = CGPointApplyAffineTransform(position, CATransform3DGetAffineTransform(self.transform));
-    }
-    [super setPosition:position];
-}
-@end
-
 #if ENABLE(AVF_CAPTIONS)
 // Note: This must be defined before our SOFT_LINK macros:
 @class AVMediaSelectionOption;
@@ -474,7 +457,8 @@ void MediaPlayerPrivateAVFoundationObjC::registerMediaEngine(MediaEngineRegistra
 MediaPlayerPrivateAVFoundationObjC::MediaPlayerPrivateAVFoundationObjC(MediaPlayer* player)
     : MediaPlayerPrivateAVFoundation(player)
     , m_weakPtrFactory(this)
-#if PLATFORM(IOS)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    , m_videoFullscreenLayerManager(VideoFullscreenLayerManager::create())
     , m_videoFullscreenGravity(MediaPlayer::VideoGravityResizeAspect)
 #endif
     , m_objcObserver(adoptNS([[WebCoreAVFMovieObserver alloc] initWithCallback:this]))
@@ -693,22 +677,13 @@ void MediaPlayerPrivateAVFoundationObjC::createAVPlayerLayer()
     IntSize defaultSize = snappedIntRect(player()->client().mediaPlayerContentBoxRect()).size();
     LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning %p", this, m_videoLayer.get());
 
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    m_videoFullscreenLayerManager->setVideoLayer(m_videoLayer.get(), defaultSize);
+
 #if PLATFORM(IOS)
-    [m_videoLayer web_disableAllActions];
-    m_videoInlineLayer = adoptNS([[WebVideoContainerLayer alloc] init]);
-#ifndef NDEBUG
-    [m_videoInlineLayer setName:@"WebVideoContainerLayer"];
-#endif
-    [m_videoInlineLayer setFrame:CGRectMake(0, 0, defaultSize.width(), defaultSize.height())];
-    if (m_videoFullscreenLayer) {
-        [m_videoLayer setFrame:CGRectMake(0, 0, m_videoFullscreenFrame.width(), m_videoFullscreenFrame.height())];
-        [m_videoFullscreenLayer insertSublayer:m_videoLayer.get() atIndex:0];
-    } else {
-        [m_videoInlineLayer insertSublayer:m_videoLayer.get() atIndex:0];
-        [m_videoLayer setFrame:m_videoInlineLayer.get().bounds];
-    }
     if ([m_videoLayer respondsToSelector:@selector(setPIPModeEnabled:)])
         [m_videoLayer setPIPModeEnabled:(player()->fullscreenMode() & MediaPlayer::VideoFullscreenModePictureInPicture)];
+#endif
 #else
     [m_videoLayer setFrame:CGRectMake(0, 0, defaultSize.width(), defaultSize.height())];
 #endif
@@ -724,10 +699,8 @@ void MediaPlayerPrivateAVFoundationObjC::destroyVideoLayer()
     [m_videoLayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"readyForDisplay"];
     [m_videoLayer.get() setPlayer:nil];
 
-#if PLATFORM(IOS)
-    if (m_videoFullscreenLayer)
-        [m_videoLayer removeFromSuperlayer];
-    m_videoInlineLayer = nil;
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    m_videoFullscreenLayerManager->didDestroyVideoLayer();
 #endif
 
     m_videoLayer = nil;
@@ -1114,49 +1087,24 @@ PlatformMedia MediaPlayerPrivateAVFoundationObjC::platformMedia() const
 
 PlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const
 {
-#if PLATFORM(IOS)
-    return m_haveBeenAskedToCreateLayer ? m_videoInlineLayer.get() : nullptr;
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    return m_haveBeenAskedToCreateLayer ? m_videoFullscreenLayerManager->videoInlineLayer() : nullptr;
 #else
     return m_haveBeenAskedToCreateLayer ? m_videoLayer.get() : nullptr;
 #endif
 }
 
-#if PLATFORM(IOS)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
 void MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer(PlatformLayer* videoFullscreenLayer)
 {
-    if (m_videoFullscreenLayer == videoFullscreenLayer)
+    if (m_videoFullscreenLayerManager->videoFullscreenLayer() == videoFullscreenLayer)
         return;
 
-    m_videoFullscreenLayer = videoFullscreenLayer;
+    m_videoFullscreenLayerManager->setVideoFullscreenLayer(videoFullscreenLayer);
 
-    [CATransaction begin];
-    [CATransaction setDisableActions:YES];
-    
-    CAContext *oldContext = [m_videoLayer context];
-    CAContext *newContext = nil;
-    
-    if (m_videoFullscreenLayer && m_videoLayer) {
-        [m_videoFullscreenLayer insertSublayer:m_videoLayer.get() atIndex:0];
-        [m_videoLayer setFrame:CGRectMake(0, 0, m_videoFullscreenFrame.width(), m_videoFullscreenFrame.height())];
-        newContext = [m_videoFullscreenLayer context];
-    } else if (m_videoInlineLayer && m_videoLayer) {
-        [m_videoLayer setFrame:[m_videoInlineLayer bounds]];
-        [m_videoLayer removeFromSuperlayer];
-        [m_videoInlineLayer insertSublayer:m_videoLayer.get() atIndex:0];
-        newContext = [m_videoInlineLayer context];
-    } else if (m_videoLayer)
-        [m_videoLayer removeFromSuperlayer];
-
-    if (oldContext && newContext && oldContext != newContext) {
-        mach_port_t fencePort = [oldContext createFencePort];
-        [newContext setFencePort:fencePort];
-        mach_port_deallocate(mach_task_self(), fencePort);
-    }
-    [CATransaction commit];
-
-    if (m_videoFullscreenLayer && m_textTrackRepresentationLayer) {
+    if (m_videoFullscreenLayerManager->videoFullscreenLayer() && m_textTrackRepresentationLayer) {
         syncTextTrackBounds();
-        [m_videoFullscreenLayer addSublayer:m_textTrackRepresentationLayer.get()];
+        [m_videoFullscreenLayerManager->videoFullscreenLayer() addSublayer:m_textTrackRepresentationLayer.get()];
     }
 
     updateDisableExternalPlayback();
@@ -1164,13 +1112,7 @@ void MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenLayer(PlatformLayer*
 
 void MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenFrame(FloatRect frame)
 {
-    m_videoFullscreenFrame = frame;
-    if (!m_videoFullscreenLayer)
-        return;
-
-    if (m_videoLayer) {
-        [m_videoLayer setFrame:CGRectMake(0, 0, frame.width(), frame.height())];
-    }
+    m_videoFullscreenLayerManager->setVideoFullscreenFrame(frame);
     syncTextTrackBounds();
 }
 
@@ -1199,10 +1141,17 @@ void MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenGravity(MediaPlayer::
 
 void MediaPlayerPrivateAVFoundationObjC::setVideoFullscreenMode(MediaPlayer::VideoFullscreenMode mode)
 {
+#if PLATFORM(IOS)
     if (m_videoLayer && [m_videoLayer respondsToSelector:@selector(setPIPModeEnabled:)])
         [m_videoLayer setPIPModeEnabled:(mode & MediaPlayer::VideoFullscreenModePictureInPicture)];
+#else
+    UNUSED_PARAM(mode);
+#endif
 }
 
+#endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+
+#if PLATFORM(IOS)
 NSArray *MediaPlayerPrivateAVFoundationObjC::timedMetadata() const
 {
     if (m_currentMetaData)
@@ -1828,10 +1777,10 @@ void MediaPlayerPrivateAVFoundationObjC::updateVideoLayerGravity()
     if (!m_videoLayer)
         return;
 
-#if PLATFORM(IOS)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     // Do not attempt to change the video gravity while in full screen mode.
     // See setVideoFullscreenGravity().
-    if (m_videoFullscreenLayer)
+    if (m_videoFullscreenLayerManager->videoFullscreenLayer())
         return;
 #endif
 
@@ -2120,8 +2069,8 @@ void MediaPlayerPrivateAVFoundationObjC::updateVideoTracks()
 
 bool MediaPlayerPrivateAVFoundationObjC::requiresTextTrackRepresentation() const
 {
-#if PLATFORM(IOS)
-    if (m_videoFullscreenLayer)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    if (m_videoFullscreenLayerManager->videoFullscreenLayer())
         return true;
 #endif
     return false;
@@ -2129,18 +2078,19 @@ bool MediaPlayerPrivateAVFoundationObjC::requiresTextTrackRepresentation() const
 
 void MediaPlayerPrivateAVFoundationObjC::syncTextTrackBounds()
 {
-#if PLATFORM(IOS)
-    if (!m_videoFullscreenLayer || !m_textTrackRepresentationLayer)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+    if (!m_videoFullscreenLayerManager->videoFullscreenLayer() || !m_textTrackRepresentationLayer)
         return;
-    
-    CGRect textFrame = m_videoLayer ? [m_videoLayer videoRect] : CGRectMake(0, 0, m_videoFullscreenFrame.width(), m_videoFullscreenFrame.height());
+
+    FloatRect videoFullscreenFrame = m_videoFullscreenLayerManager->videoFullscreenFrame();
+    CGRect textFrame = m_videoLayer ? [m_videoLayer videoRect] : CGRectMake(0, 0, videoFullscreenFrame.width(), videoFullscreenFrame.height());
     [m_textTrackRepresentationLayer setFrame:textFrame];
 #endif
 }
 
 void MediaPlayerPrivateAVFoundationObjC::setTextTrackRepresentation(TextTrackRepresentation* representation)
 {
-#if PLATFORM(IOS)
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     PlatformLayer* representationLayer = representation ? representation->platformLayer() : nil;
     if (representationLayer == m_textTrackRepresentationLayer) {
         syncTextTrackBounds();
@@ -2152,9 +2102,9 @@ void MediaPlayerPrivateAVFoundationObjC::setTextTrackRepresentation(TextTrackRep
 
     m_textTrackRepresentationLayer = representationLayer;
 
-    if (m_videoFullscreenLayer && m_textTrackRepresentationLayer) {
+    if (m_videoFullscreenLayerManager->videoFullscreenLayer() && m_textTrackRepresentationLayer) {
         syncTextTrackBounds();
-        [m_videoFullscreenLayer addSublayer:m_textTrackRepresentationLayer.get()];
+        [m_videoFullscreenLayerManager->videoFullscreenLayer() addSublayer:m_textTrackRepresentationLayer.get()];
     }
 
 #else
@@ -3142,7 +3092,7 @@ void MediaPlayerPrivateAVFoundationObjC::updateDisableExternalPlayback()
         return;
 
 #if PLATFORM(IOS)
-    [m_avPlayer setUsesExternalPlaybackWhileExternalScreenIsActive:m_videoFullscreenLayer != nil];
+    [m_avPlayer setUsesExternalPlaybackWhileExternalScreenIsActive:m_videoFullscreenLayerManager->videoFullscreenLayer() != nil];
 #endif
 }
 #endif
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.h b/Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.h
new file mode 100644 (file)
index 0000000..2d5db60
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef VideoFullscreenLayerManager_h
+#define VideoFullscreenLayerManager_h
+
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+
+#include "FloatRect.h"
+#include "IntSize.h"
+#include "PlatformLayer.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class VideoFullscreenLayerManager {
+    WTF_MAKE_NONCOPYABLE(VideoFullscreenLayerManager);
+public:
+    static std::unique_ptr<VideoFullscreenLayerManager> create();
+
+    PlatformLayer *videoInlineLayer() const { return m_videoInlineLayer.get(); }
+    PlatformLayer *videoFullscreenLayer() const { return m_videoFullscreenLayer.get(); }
+    FloatRect videoFullscreenFrame() const { return m_videoFullscreenFrame; }
+    void setVideoLayer(PlatformLayer *, IntSize contentSize);
+    void setVideoFullscreenLayer(PlatformLayer *);
+    void setVideoFullscreenFrame(FloatRect);
+    void didDestroyVideoLayer();
+
+private:
+    VideoFullscreenLayerManager();
+
+    RetainPtr<PlatformLayer> m_videoInlineLayer;
+    RetainPtr<PlatformLayer> m_videoFullscreenLayer;
+    RetainPtr<PlatformLayer> m_videoLayer;
+    FloatRect m_videoFullscreenFrame;
+};
+
+}
+
+#endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+
+#endif /* VideoFullscreenLayerManager_h */
diff --git a/Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.mm b/Source/WebCore/platform/graphics/avfoundation/objc/VideoFullscreenLayerManager.mm
new file mode 100644 (file)
index 0000000..68b9203
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#import "config.h"
+#import "VideoFullscreenLayerManager.h"
+
+#if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
+
+#import "QuartzCoreSPI.h"
+#import "WebCoreCALayerExtras.h"
+#import <mach/mach_init.h>
+#import <mach/mach_port.h>
+
+@interface WebVideoContainerLayer : CALayer
+@end
+
+@implementation WebVideoContainerLayer
+
+- (void)setBounds:(CGRect)bounds
+{
+    [super setBounds:bounds];
+    for (CALayer* layer in self.sublayers)
+        layer.frame = bounds;
+}
+
+- (void)setPosition:(CGPoint)position
+{
+    if (!CATransform3DIsIdentity(self.transform)) {
+        // Pre-apply the transform added in the WebProcess to fix <rdar://problem/18316542> to the position.
+        position = CGPointApplyAffineTransform(position, CATransform3DGetAffineTransform(self.transform));
+    }
+    [super setPosition:position];
+}
+@end
+
+namespace WebCore {
+
+std::unique_ptr<VideoFullscreenLayerManager> VideoFullscreenLayerManager::create()
+{
+    return std::unique_ptr<VideoFullscreenLayerManager>(new VideoFullscreenLayerManager());
+}
+
+VideoFullscreenLayerManager::VideoFullscreenLayerManager()
+{
+}
+
+void VideoFullscreenLayerManager::setVideoLayer(PlatformLayer *videoLayer, IntSize contentSize)
+{
+    m_videoLayer = videoLayer;
+
+    [m_videoLayer web_disableAllActions];
+    m_videoInlineLayer = adoptNS([[WebVideoContainerLayer alloc] init]);
+#ifndef NDEBUG
+    [m_videoInlineLayer setName:@"WebVideoContainerLayer"];
+#endif
+    [m_videoInlineLayer setFrame:CGRectMake(0, 0, contentSize.width(), contentSize.height())];
+    if (m_videoFullscreenLayer) {
+        [m_videoLayer setFrame:CGRectMake(0, 0, m_videoFullscreenFrame.width(), m_videoFullscreenFrame.height())];
+        [m_videoFullscreenLayer insertSublayer:m_videoLayer.get() atIndex:0];
+    } else {
+        [m_videoInlineLayer insertSublayer:m_videoLayer.get() atIndex:0];
+        [m_videoLayer setFrame:m_videoInlineLayer.get().bounds];
+    }
+}
+
+void VideoFullscreenLayerManager::setVideoFullscreenLayer(PlatformLayer *videoFullscreenLayer)
+{
+    if (m_videoFullscreenLayer == videoFullscreenLayer)
+        return;
+
+    m_videoFullscreenLayer = videoFullscreenLayer;
+
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+
+    CAContext *oldContext = [m_videoLayer context];
+    CAContext *newContext = nil;
+
+    if (m_videoFullscreenLayer && m_videoLayer) {
+        [m_videoFullscreenLayer insertSublayer:m_videoLayer.get() atIndex:0];
+        [m_videoLayer setFrame:CGRectMake(0, 0, m_videoFullscreenFrame.width(), m_videoFullscreenFrame.height())];
+        newContext = [m_videoFullscreenLayer context];
+    } else if (m_videoInlineLayer && m_videoLayer) {
+        [m_videoLayer setFrame:[m_videoInlineLayer bounds]];
+        [m_videoLayer removeFromSuperlayer];
+        [m_videoInlineLayer insertSublayer:m_videoLayer.get() atIndex:0];
+        newContext = [m_videoInlineLayer context];
+    } else if (m_videoLayer)
+        [m_videoLayer removeFromSuperlayer];
+
+    if (oldContext && newContext && oldContext != newContext) {
+        mach_port_t fencePort = [oldContext createFencePort];
+        [newContext setFencePort:fencePort];
+        mach_port_deallocate(mach_task_self(), fencePort);
+    }
+    [CATransaction commit];
+}
+
+void VideoFullscreenLayerManager::setVideoFullscreenFrame(FloatRect videoFullscreenFrame)
+{
+    m_videoFullscreenFrame = videoFullscreenFrame;
+    if (!m_videoFullscreenLayer)
+        return;
+
+    if (m_videoLayer)
+        [m_videoLayer setFrame:CGRectMake(0, 0, videoFullscreenFrame.width(), videoFullscreenFrame.height())];
+}
+
+void VideoFullscreenLayerManager::didDestroyVideoLayer()
+{
+    if (m_videoFullscreenLayer)
+        [m_videoLayer removeFromSuperlayer];
+
+    m_videoInlineLayer = nil;
+    m_videoLayer = nil;
+}
+
+}
+
+#endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
index 2b101da..248a3e7 100644 (file)
@@ -173,6 +173,8 @@ private:
 
     bool requiresCustomAppearanceUpdateOnBoundsChange() const;
 
+    AVPlayerLayer *avPlayerLayer() const;
+
     RetainPtr<NSObject> m_delegate;
     std::unique_ptr<PlatformCALayerList> m_customSublayers;
     GraphicsLayer::CustomAppearance m_customAppearance;
index edaa07d..f665cbf 100644 (file)
@@ -361,10 +361,11 @@ PassRefPtr<PlatformCALayer> PlatformCALayerCocoa::clone(PlatformCALayerClient* o
 
     if (type == LayerTypeAVPlayerLayer) {
         ASSERT([newLayer->platformLayer() isKindOfClass:getAVPlayerLayerClass()]);
-        ASSERT([platformLayer() isKindOfClass:getAVPlayerLayerClass()]);
 
-        AVPlayerLayer* destinationPlayerLayer = static_cast<AVPlayerLayer *>(newLayer->platformLayer());
-        AVPlayerLayer* sourcePlayerLayer = static_cast<AVPlayerLayer *>(platformLayer());
+        AVPlayerLayer *destinationPlayerLayer = static_cast<PlatformCALayerCocoa *>(newLayer.get())->avPlayerLayer();
+        AVPlayerLayer *sourcePlayerLayer = avPlayerLayer();
+        ASSERT(sourcePlayerLayer);
+
         dispatch_async(dispatch_get_main_queue(), ^{
             [destinationPlayerLayer setPlayer:[sourcePlayerLayer player]];
         });
@@ -1110,3 +1111,21 @@ void PlatformCALayerCocoa::enumerateRectsBeingDrawn(CGContextRef context, void (
 {
     wkCALayerEnumerateRectsBeingDrawnWithBlock(m_layer.get(), context, block);
 }
+
+AVPlayerLayer *PlatformCALayerCocoa::avPlayerLayer() const
+{
+    if (layerType() != LayerTypeAVPlayerLayer)
+        return nil;
+
+    if ([platformLayer() isKindOfClass:getAVPlayerLayerClass()])
+        return static_cast<AVPlayerLayer *>(platformLayer());
+
+    if ([platformLayer() isKindOfClass:objc_getClass("WebVideoContainerLayer")]) {
+        ASSERT([platformLayer() sublayers].count == 1);
+        ASSERT([[platformLayer() sublayers][0] isKindOfClass:getAVPlayerLayerClass()]);
+        return static_cast<AVPlayerLayer *>([platformLayer() sublayers][0]);
+    }
+
+    ASSERT_NOT_REACHED();
+    return nil;
+}