blob: b0b53ac13f4075c3ebbb9f2fd5722d335f2ac88f [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/picture_in_picture/overlay_surface_embedder.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/media/media_player_delegate_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/overlay_window.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
namespace content {
DEFINE_WEB_CONTENTS_USER_DATA_KEY(PictureInPictureWindowControllerImpl);
// static
PictureInPictureWindowController*
PictureInPictureWindowController::GetOrCreateForWebContents(
WebContents* web_contents) {
return PictureInPictureWindowControllerImpl::GetOrCreateForWebContents(
web_contents);
}
// static
PictureInPictureWindowControllerImpl*
PictureInPictureWindowControllerImpl::GetOrCreateForWebContents(
WebContents* web_contents) {
DCHECK(web_contents);
// This is a no-op if the controller already exists.
CreateForWebContents(web_contents);
return FromWebContents(web_contents);
}
PictureInPictureWindowControllerImpl::~PictureInPictureWindowControllerImpl() {
if (window_)
window_->Close();
// If the initiator WebContents is being destroyed, there is no need to put
// the video's media player in a post-Picture-in-Picture mode. In fact, some
// things, such as the MediaWebContentsObserver, may already been torn down.
if (initiator_->IsBeingDestroyed())
return;
OnLeavingPictureInPicture();
}
PictureInPictureWindowControllerImpl::PictureInPictureWindowControllerImpl(
WebContents* initiator)
: initiator_(initiator) {
DCHECK(initiator_);
media_web_contents_observer_ = static_cast<WebContentsImpl* const>(initiator_)
->media_web_contents_observer();
window_ =
GetContentClient()->browser()->CreateWindowForPictureInPicture(this);
DCHECK(window_) << "Picture in Picture requires a valid window.";
}
gfx::Size PictureInPictureWindowControllerImpl::Show() {
DCHECK(window_);
DCHECK(surface_id_.is_valid());
window_->Show();
return window_->GetBounds().size();
}
void PictureInPictureWindowControllerImpl::Close() {
DCHECK(window_);
window_->Hide();
surface_id_ = viz::SurfaceId();
OnLeavingPictureInPicture();
}
void PictureInPictureWindowControllerImpl::EmbedSurface(
const viz::SurfaceId& surface_id,
const gfx::Size& natural_size) {
DCHECK(window_);
DCHECK(surface_id.is_valid());
surface_id_ = surface_id;
// Update the media player id in step with the video surface id. If the
// surface id was updated for the same video, this is a no-op. This could
// be updated for a different video if another media player on the same
// |initiator_| enters Picture-in-Picture mode.
media_player_id_ =
media_web_contents_observer_->GetPictureInPictureVideoMediaPlayerId();
window_->UpdateVideoSize(natural_size);
if (!embedder_)
embedder_.reset(new OverlaySurfaceEmbedder(window_.get()));
embedder_->SetPrimarySurfaceId(surface_id_);
}
OverlayWindow* PictureInPictureWindowControllerImpl::GetWindowForTesting() {
return window_.get();
}
void PictureInPictureWindowControllerImpl::UpdateLayerBounds() {
if (window_) {
media_web_contents_observer_->OnPictureInPictureWindowResize(
window_->GetBounds().size());
}
if (embedder_)
embedder_->UpdateLayerBounds();
}
bool PictureInPictureWindowControllerImpl::IsPlayerActive() {
if (!media_player_id_.has_value())
media_web_contents_observer_->GetPictureInPictureVideoMediaPlayerId();
return media_player_id_.has_value() &&
media_web_contents_observer_->IsPlayerActive(*media_player_id_);
}
WebContents* PictureInPictureWindowControllerImpl::GetInitiatorWebContents() {
return initiator_;
}
bool PictureInPictureWindowControllerImpl::TogglePlayPause() {
DCHECK(window_ && window_->IsActive());
if (IsPlayerActive()) {
media_player_id_->first->Send(new MediaPlayerDelegateMsg_Pause(
media_player_id_->first->GetRoutingID(), media_player_id_->second));
return false;
}
media_player_id_->first->Send(new MediaPlayerDelegateMsg_Play(
media_player_id_->first->GetRoutingID(), media_player_id_->second));
return true;
}
void PictureInPictureWindowControllerImpl::OnLeavingPictureInPicture() {
if (IsPlayerActive()) {
// Pause the current video so there is only one video playing at a time.
media_player_id_->first->Send(new MediaPlayerDelegateMsg_Pause(
media_player_id_->first->GetRoutingID(), media_player_id_->second));
media_player_id_->first->Send(
new MediaPlayerDelegateMsg_EndPictureInPictureMode(
media_player_id_->first->GetRoutingID(), media_player_id_->second));
}
}
} // namespace content