Skip to content

Commit

Permalink
In in-window mode, missing PIP when minimizing safari
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=275182
rdar://124376686

Reviewed by Jer Noble.

Currently when a window is in in-window mode and the safari window
is minimized, safari asks webkit to toggle PIP, but this does
not successfully occur. This is because currently we return early
from HTMLMediaElement::enterFullscreen if the document hidden.
This check has been changed to not return early if the document is
the new mode is PIP.

The above change revealed that we do not successfully return to
in-window mode when the window is maximized again, or when the
PIP return button is clicked.

To fix the case where the window is maximized but the video
does not return to in-window, this patch has us no longer return early
from FullscreenManager::requestFullscreenForElement when the document
is hidden but the new mode is in-window.

To fix the case where the the return button is clicked on the PIP
window and the video does not return to in-window, this patch has
VideoPresentationInterfaceMac wait for the document to become
visible before beginning to exit PIP. To facilitate this,
VideoPresentationModelVideoElement now listens to
visibilitychangeEvent from Document and propagates the information
to VideoPresentationInterfaceMac.

* Source/WebCore/dom/FullscreenManager.cpp:
(WebCore::FullscreenManager::requestFullscreenForElement):
* Source/WebCore/html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::enterFullscreen):
* Source/WebCore/platform/cocoa/VideoPresentationModel.h:
(WebCore::VideoPresentationModelClient::documentVisibilityChanged):
* Source/WebCore/platform/cocoa/VideoPresentationModelVideoElement.h:
* Source/WebCore/platform/cocoa/VideoPresentationModelVideoElement.mm:
(WebCore::VideoPresentationModelVideoElement::setVideoElement):
(WebCore::VideoPresentationModelVideoElement::updateForEventName):
(WebCore::VideoPresentationModelVideoElement::documentVisibilityChanged):
(WebCore::VideoPresentationModelVideoElement::documentObservedEventNames):
* Source/WebCore/platform/mac/VideoPresentationInterfaceMac.h:
* Source/WebCore/platform/mac/VideoPresentationInterfaceMac.mm:
(WebCore::VideoPresentationInterfaceMac::requestHideAndExitPiP):
(WebCore::VideoPresentationInterfaceMac::documentVisibilityChanged):
* Source/WebKit/UIProcess/Cocoa/VideoPresentationManagerProxy.h:
* Source/WebKit/UIProcess/Cocoa/VideoPresentationManagerProxy.messages.in:
* Source/WebKit/UIProcess/Cocoa/VideoPresentationManagerProxy.mm:
(WebKit::VideoPresentationManagerProxy::setDocumentVisibility):
* Source/WebKit/WebProcess/cocoa/VideoPresentationManager.h:
* Source/WebKit/WebProcess/cocoa/VideoPresentationManager.mm:
(WebKit::VideoPresentationInterfaceContext::documentVisibilityChanged):
(WebKit::VideoPresentationManager::documentVisibilityChanged):

Canonical link: https://commits.webkit.org/279877@main
  • Loading branch information
danae404 committed Jun 10, 2024
1 parent 1b56b01 commit 2cc2b7b
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Source/WebCore/dom/FullscreenManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ void FullscreenManager::requestFullscreenForElement(Ref<Element>&& element, RefP

// Don't allow fullscreen if document is hidden.
auto document = protectedDocument();
if (document->hidden()) {
if (document->hidden() && mode != HTMLMediaElementEnums::VideoFullscreenModeInWindow) {
ERROR_LOG(identifier, "task - document hidden; failing.");
failedPreflights(WTFMove(element), WTFMove(promise));
completionHandler(false);
Expand Down Expand Up @@ -272,7 +272,7 @@ void FullscreenManager::requestFullscreenForElement(Ref<Element>&& element, RefP
}

auto page = this->page();
if (!page || this->document().hidden() || m_pendingFullscreenElement != element.ptr() || !element->isConnected()) {
if (!page || (this->document().hidden() && mode != HTMLMediaElementEnums::VideoFullscreenModeInWindow) || m_pendingFullscreenElement != element.ptr() || !element->isConnected()) {
ERROR_LOG(identifier, "task - page, document, or element mismatch; failing.");
failedPreflights(WTFMove(element), WTFMove(promise));
completionHandler(false);
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/html/HTMLMediaElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7171,7 +7171,7 @@ void HTMLMediaElement::enterFullscreen(VideoFullscreenMode mode)
if (isContextStopped())
return;

if (document().hidden()) {
if (document().hidden() && mode != HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
ALWAYS_LOG(logIdentifier, " returning because document is hidden");
m_changingVideoFullscreenMode = false;
return;
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/platform/cocoa/VideoPresentationModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class VideoPresentationModelClient : public CanMakeWeakPtr<VideoPresentationMode
virtual void willExitPictureInPicture() { }
virtual void didExitPictureInPicture() { }
virtual void setPlayerIdentifier(std::optional<MediaPlayerIdentifier>) { }
virtual void documentVisibilityChanged(bool) { }
};

} // namespace WebCore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,20 @@ class VideoPresentationModelVideoElement final : public VideoPresentationModel {
void didExitPictureInPicture() final;

static std::span<const AtomString> observedEventNames();
static std::span<const AtomString> documentObservedEventNames();
const AtomString& eventNameAll();
friend class VideoListener;
void updateForEventName(const AtomString&);
void cleanVideoListeners();
void documentVisibilityChanged();

Ref<VideoListener> m_videoListener;
RefPtr<HTMLVideoElement> m_videoElement;
RetainPtr<PlatformLayer> m_videoFullscreenLayer;
bool m_isListening { false };
HashSet<CheckedPtr<VideoPresentationModelClient>> m_clients;
bool m_hasVideo { false };
bool m_documentIsVisible { true };
FloatSize m_videoDimensions;
FloatRect m_videoFrame;
Vector<RefPtr<TextTrack>> m_legibleTracksForMenu;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
return;
for (auto& eventName : observedEventNames())
m_videoElement->removeEventListener(eventName, m_videoListener, false);
for (auto& eventName : documentObservedEventNames())
m_videoElement->document().removeEventListener(eventName, m_videoListener, false);
}

void VideoPresentationModelVideoElement::setVideoElement(HTMLVideoElement* videoElement)
Expand All @@ -101,6 +103,8 @@
if (m_videoElement) {
for (auto& eventName : observedEventNames())
m_videoElement->addEventListener(eventName, m_videoListener, false);
for (auto& eventName : documentObservedEventNames())
m_videoElement->document().addEventListener(eventName, m_videoListener, false);
m_isListening = true;
}

Expand All @@ -120,6 +124,9 @@
setVideoDimensions(m_videoElement ? FloatSize(m_videoElement->videoWidth(), m_videoElement->videoHeight()) : FloatSize());
}

if (all || eventName == eventNames().visibilitychangeEvent)
documentVisibilityChanged();

if (all
|| eventName == eventNames().loadedmetadataEvent || eventName == eventNames().loadstartEvent) {
setPlayerIdentifier([&]() -> std::optional<MediaPlayerIdentifier> {
Expand All @@ -141,6 +148,21 @@
}
}

void VideoPresentationModelVideoElement::documentVisibilityChanged()
{
if (!m_videoElement)
return;

bool isDocumentVisible = !m_videoElement->document().hidden();

if (isDocumentVisible == m_documentIsVisible)
return;

m_documentIsVisible = isDocumentVisible;
for (auto& client : copyToVector(m_clients))
client->documentVisibilityChanged(m_documentIsVisible);
}

void VideoPresentationModelVideoElement::willExitFullscreen()
{
ALWAYS_LOG_IF_POSSIBLE(LOGIDENTIFIER);
Expand Down Expand Up @@ -245,6 +267,12 @@
return names.get();
}

std::span<const AtomString> VideoPresentationModelVideoElement::documentObservedEventNames()
{
static NeverDestroyed names = std::array { eventNames().visibilitychangeEvent };
return names.get();
}

const AtomString& VideoPresentationModelVideoElement::eventNameAll()
{
static MainThreadNeverDestroyed<const AtomString> sEventNameAll = "allEvents"_s;
Expand Down
4 changes: 4 additions & 0 deletions Source/WebCore/platform/mac/VideoPresentationInterfaceMac.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class VideoPresentationInterfaceMac final
WEBCORE_EXPORT void requestHideAndExitPiP();

std::optional<MediaPlayerIdentifier> playerIdentifier() const { return m_playerIdentifier; }
WEBCORE_EXPORT void documentVisibilityChanged(bool) final;

#if !RELEASE_LOG_DISABLED
const void* logIdentifier() const;
Expand All @@ -120,12 +121,15 @@ class VideoPresentationInterfaceMac final
uint32_t ptrCountWithoutThreadCheck() const final { return CanMakeCheckedPtr::ptrCountWithoutThreadCheck(); }
void incrementPtrCount() const final { CanMakeCheckedPtr::incrementPtrCount(); }
void decrementPtrCount() const final { CanMakeCheckedPtr::decrementPtrCount(); }
void setDocumentBecameVisibleCallback(Function<void()>&& callback) { m_documentBecameVisibleCallback = WTFMove(callback); }

Ref<PlaybackSessionInterfaceMac> m_playbackSessionInterface;
std::optional<MediaPlayerIdentifier> m_playerIdentifier;
ThreadSafeWeakPtr<VideoPresentationModel> m_videoPresentationModel;
HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
RetainPtr<WebVideoPresentationInterfaceMacObjC> m_webVideoPresentationInterfaceObjC;
bool m_documentIsVisible { true };
Function<void()> m_documentBecameVisibleCallback;
};

} // namespace WebCore
Expand Down
24 changes: 22 additions & 2 deletions Source/WebCore/platform/mac/VideoPresentationInterfaceMac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,28 @@ - (void)pipActionStop:(PIPViewController *)pip
if (!model)
return;

model->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
model->willExitPictureInPicture();
if (m_documentIsVisible) {
model->requestFullscreenMode(m_mode & ~HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
model->willExitPictureInPicture();
} else {
auto callback = [this, model] () {
model->requestFullscreenMode(m_mode & ~HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
model->willExitPictureInPicture();
};
setDocumentBecameVisibleCallback(WTFMove(callback));
}

}

void VideoPresentationInterfaceMac::documentVisibilityChanged(bool isDocumentVisible)
{
bool documentWasVisible = m_documentIsVisible;
m_documentIsVisible = isDocumentVisible;

if (!documentWasVisible && m_documentIsVisible && m_documentBecameVisibleCallback) {
m_documentBecameVisibleCallback();
m_documentBecameVisibleCallback = nullptr;
}
}

#if !LOG_DISABLED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class VideoPresentationManagerProxy
void setInlineRect(PlaybackSessionContextIdentifier, const WebCore::FloatRect& inlineRect, bool visible);
void setHasVideoContentLayer(PlaybackSessionContextIdentifier, bool value);
void setHasVideo(PlaybackSessionContextIdentifier, bool);
void setDocumentVisibility(PlaybackSessionContextIdentifier, bool);
void setVideoDimensions(PlaybackSessionContextIdentifier, const WebCore::FloatSize&);
void enterFullscreen(PlaybackSessionContextIdentifier);
void exitFullscreen(PlaybackSessionContextIdentifier, WebCore::FloatRect finalRect, CompletionHandler<void(bool)>&&);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#if ENABLE(VIDEO_PRESENTATION_MODE)
messages -> VideoPresentationManagerProxy {
SetHasVideo(WebKit::PlaybackSessionContextIdentifier contextId, bool hasVideo)
SetDocumentVisibility(WebKit::PlaybackSessionContextIdentifier contextId, bool isDocumentVisible)
SetVideoDimensions(WebKit::PlaybackSessionContextIdentifier contextId, WebCore::FloatSize videoDimensions)
SetupFullscreenWithID(WebKit::PlaybackSessionContextIdentifier contextId, WebKit::LayerHostingContextID videoLayerID, WebCore::FloatRect screenRect, WebCore::FloatSize initialSize, WebCore::FloatSize videoDimensions, float hostingScaleFactor, WebCore::MediaPlayerEnums::VideoFullscreenMode videoFullscreenMode, bool allowsPictureInPicture, bool standby, bool blocksReturnToFullscreenFromPictureInPicture)
SetPlayerIdentifier(WebKit::PlaybackSessionContextIdentifier contextId, std::optional<WebCore::MediaPlayerIdentifier> playerIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,15 @@ - (BOOL)prefersStatusBarHidden
interface->hasVideoChanged(hasVideo);
}

void VideoPresentationManagerProxy::setDocumentVisibility(PlaybackSessionContextIdentifier contextId, bool isDocumentVisible)
{
if (m_mockVideoPresentationModeEnabled)
return;

if (auto* interface = findInterface(contextId))
interface->documentVisibilityChanged(isDocumentVisible);
}

void VideoPresentationManagerProxy::setVideoDimensions(PlaybackSessionContextIdentifier contextId, const FloatSize& videoDimensions)
{
auto& [model, interface] = ensureModelAndInterface(contextId);
Expand Down
2 changes: 2 additions & 0 deletions Source/WebKit/WebProcess/cocoa/VideoPresentationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class VideoPresentationInterfaceContext final
private:
// VideoPresentationModelClient
void hasVideoChanged(bool) override;
void documentVisibilityChanged(bool) override;

// CheckedPtr interface
uint32_t ptrCount() const final { return CanMakeCheckedPtr::ptrCount(); }
Expand Down Expand Up @@ -178,6 +179,7 @@ class VideoPresentationManager

// Interface to VideoPresentationInterfaceContext
void hasVideoChanged(PlaybackSessionContextIdentifier, bool hasVideo);
void documentVisibilityChanged(PlaybackSessionContextIdentifier, bool isDocumentVisible);
void videoDimensionsChanged(PlaybackSessionContextIdentifier, const WebCore::FloatSize&);
void setPlayerIdentifier(PlaybackSessionContextIdentifier, std::optional<WebCore::MediaPlayerIdentifier>);

Expand Down
12 changes: 12 additions & 0 deletions Source/WebKit/WebProcess/cocoa/VideoPresentationManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ static FloatRect inlineVideoFrame(HTMLVideoElement& element)
m_manager->hasVideoChanged(m_contextId, hasVideo);
}

void VideoPresentationInterfaceContext::documentVisibilityChanged(bool isDocumentVisible)
{
if (m_manager)
m_manager->documentVisibilityChanged(m_contextId, isDocumentVisible);
}

void VideoPresentationInterfaceContext::videoDimensionsChanged(const FloatSize& videoDimensions)
{
if (m_manager)
Expand Down Expand Up @@ -521,6 +527,12 @@ static FloatRect inlineVideoFrame(HTMLVideoElement& element)
m_page->send(Messages::VideoPresentationManagerProxy::SetHasVideo(contextId, hasVideo));
}

void VideoPresentationManager::documentVisibilityChanged(PlaybackSessionContextIdentifier contextId, bool isDocumentVisibile)
{
if (m_page)
m_page->send(Messages::VideoPresentationManagerProxy::SetDocumentVisibility(contextId, isDocumentVisibile));
}

void VideoPresentationManager::videoDimensionsChanged(PlaybackSessionContextIdentifier contextId, const FloatSize& videoDimensions)
{
if (m_page)
Expand Down

0 comments on commit 2cc2b7b

Please sign in to comment.