0

Remove DocumentOverlayWindowViews

This class used to support Document Picture in Picture, but has
been replaced by a custom browser frame instead.

This CL removes it.

Change-Id: Ib89044c96dba403f3e87a09071425300e98c1a85
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3988524
Reviewed-by: Fr <beaufort.francois@gmail.com>
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Frank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1064874}
This commit is contained in:
Frank Liberato
2022-10-28 16:27:37 +00:00
committed by Chromium LUCI CQ
parent f0690e8201
commit db9980ce11
13 changed files with 7 additions and 1255 deletions

@ -6019,18 +6019,6 @@ ChromeContentBrowserClient::CreateWindowForVideoPictureInPicture(
return content::VideoOverlayWindow::Create(controller);
}
std::unique_ptr<content::DocumentOverlayWindow>
ChromeContentBrowserClient::CreateWindowForDocumentPictureInPicture(
content::DocumentPictureInPictureWindowController* controller) {
// Note: content::DocumentOverlayWindow::Create() is defined by
// platform-specific implementation in chrome/browser/ui/views. This layering
// hack, which goes through //content and ContentBrowserClient, allows us to
// work around the dependency constraints that disallow directly calling
// chrome/browser/ui/views code either from here or from other code in
// chrome/browser.
return content::DocumentOverlayWindow::Create(controller);
}
void ChromeContentBrowserClient::RegisterRendererPreferenceWatcher(
content::BrowserContext* browser_context,
mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher) {

@ -654,9 +654,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
std::unique_ptr<content::VideoOverlayWindow>
CreateWindowForVideoPictureInPicture(
content::VideoPictureInPictureWindowController* controller) override;
std::unique_ptr<content::DocumentOverlayWindow>
CreateWindowForDocumentPictureInPicture(
content::DocumentPictureInPictureWindowController* controller) override;
void RegisterRendererPreferenceWatcher(
content::BrowserContext* browser_context,
mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher)

@ -1,7 +1,4 @@
specific_include_rules = {
"document_picture_in_picture_window_controller_browsertest\.cc": [
"+chrome/browser/ui/views/overlay/document_overlay_window_views.h",
],
"video_picture_in_picture_window_controller_browsertest\.cc": [
"+chrome/browser/ui/views/overlay/hang_up_button.h",
"+chrome/browser/ui/views/overlay/overlay_window_views.h",

@ -20,7 +20,6 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/overlay/document_overlay_window_views.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"

@ -4688,8 +4688,6 @@ static_library("ui") {
"views/overlay/close_image_button.cc",
"views/overlay/close_image_button.h",
"views/overlay/constants.h",
"views/overlay/document_overlay_window_views.cc",
"views/overlay/document_overlay_window_views.h",
"views/overlay/hang_up_button.cc",
"views/overlay/hang_up_button.h",
"views/overlay/overlay_window_image_button.cc",

@ -1,640 +0,0 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/overlay/document_overlay_window_views.h"
#include <memory>
#include <string>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/command_updater_delegate.h"
#include "chrome/browser/command_updater_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h"
#include "chrome/browser/ui/views/overlay/close_image_button.h"
#include "chrome/browser/ui/views/overlay/resize_handle_button.h"
#include "chrome/grit/generated_resources.h"
#include "components/omnibox/browser/location_bar_model_impl.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/document_picture_in_picture_window_controller.h"
#include "content/public/browser/picture_in_picture_window_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_constants.h"
#include "media/base/media_switches.h"
#include "media/base/video_util.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/resize_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/vector_icons.h"
#include "ui/views/widget/widget_delegate.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/rounded_corner_utils.h"
#include "ash/public/cpp/window_properties.h" // nogncheck
#include "ui/aura/window.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "chrome/browser/shell_integration_win.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/win/shell.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "ui/aura/window_tree_host.h"
#include "ui/platform_window/extensions/wayland_extension.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
#endif
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// The opacity of the resize handle control.
constexpr double kResizeHandleOpacity = 0.38;
#endif
// The height of the controls bar at the top of the window.
// This includes the location bar and the close/back-to-tab buttons.
constexpr int kTopControlsHeight = 30;
template <typename T>
T* AddChildView(std::vector<std::unique_ptr<views::View>>* views,
std::unique_ptr<T> child) {
views->push_back(std::move(child));
return static_cast<T*>(views->back().get());
}
class WindowBackgroundView : public views::View {
public:
METADATA_HEADER(WindowBackgroundView);
WindowBackgroundView() = default;
WindowBackgroundView(const WindowBackgroundView&) = delete;
WindowBackgroundView& operator=(const WindowBackgroundView&) = delete;
~WindowBackgroundView() override = default;
void OnThemeChanged() override {
views::View::OnThemeChanged();
layer()->SetColor(GetColorProvider()->GetColor(kColorPipWindowBackground));
}
};
BEGIN_METADATA(WindowBackgroundView, views::View)
END_METADATA
} // namespace
OverlayLocationBarViewProxy::~OverlayLocationBarViewProxy() = default;
class OverlayLocationBarViewImpl : public OverlayLocationBarViewProxy,
public ChromeLocationBarModelDelegate,
public LocationBarView::Delegate,
public CommandUpdaterDelegate {
public:
OverlayLocationBarViewImpl(Profile* profile,
content::WebContents* web_contents)
: web_contents_(web_contents),
location_bar_model_(std::make_unique<LocationBarModelImpl>(
this,
content::kMaxURLDisplayChars)),
command_updater_(this) {
view_holder_ = std::make_unique<LocationBarView>(
/*browser=*/nullptr, profile, &command_updater_, this, true);
view_ = view_holder_.get();
}
~OverlayLocationBarViewImpl() override = default;
void Init() override { view_->Init(); }
std::unique_ptr<views::View> ReleaseView() override {
return std::move(view_holder_);
}
// CommandUpdaterDelegate
void ExecuteCommandWithDisposition(int id, WindowOpenDisposition disposition)
override {
NOTREACHED();
}
// ChromeLocationBarModelDelegate
content::WebContents* GetActiveWebContents() const final {
return web_contents_;
}
// LocationBarView::Delegate
content::WebContents* GetWebContents() override { return web_contents_; }
LocationBarModel* GetLocationBarModel() override {
return location_bar_model_.get();
}
const LocationBarModel* GetLocationBarModel() const override {
return location_bar_model_.get();
}
ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
override {
NOTREACHED();
return nullptr;
}
private:
raw_ptr<content::WebContents> web_contents_;
std::unique_ptr<LocationBarView> view_holder_;
raw_ptr<LocationBarView> view_;
#if 0
raw_ptr<DocumentOverlayWindowViews> overlay_;
#endif
const std::unique_ptr<LocationBarModelImpl> location_bar_model_;
CommandUpdaterImpl command_updater_;
};
// static
std::unique_ptr<DocumentOverlayWindowViews> DocumentOverlayWindowViews::Create(
content::DocumentPictureInPictureWindowController* controller,
std::unique_ptr<OverlayLocationBarViewProxy>
location_bar_view_proxy_for_testing) {
DVLOG(1) << __func__ << ": DocumentOverlayWindowViews::Create";
// Can't use make_unique(), which doesn't have access to the private
// constructor. It's important that the constructor be private, because it
// doesn't initialize the object fully.
auto overlay_window =
base::WrapUnique(new DocumentOverlayWindowViews(controller));
if (location_bar_view_proxy_for_testing) {
overlay_window->set_location_bar_view_proxy(
std::move(location_bar_view_proxy_for_testing));
}
overlay_window->CalculateAndUpdateWindowBounds();
overlay_window->SetUpViews();
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
// Just to have any non-empty bounds as required by Init(). The window is
// resized to fit the WebView that is embedded right afterwards, anyway.
params.bounds = gfx::Rect(overlay_window->GetMinimumSize());
params.z_order = ui::ZOrderLevel::kFloatingWindow;
params.visible_on_all_workspaces = true;
params.remove_standard_frame = true;
params.name = "PictureInPictureWindow";
params.layer_type = ui::LAYER_NOT_DRAWN;
params.delegate = OverlayWindowViews::CreateDelegate();
overlay_window->Init(std::move(params));
overlay_window->OnRootViewReady();
#if BUILDFLAG(IS_WIN)
std::wstring app_user_model_id;
Browser* browser =
chrome::FindBrowserWithWebContents(controller->GetWebContents());
if (browser) {
const base::FilePath& profile_path = browser->profile()->GetPath();
// Set the window app id to GetAppUserModelIdForApp if the original window
// is an app window, GetAppUserModelIdForBrowser if it's a browser window.
app_user_model_id =
browser->is_type_app()
? shell_integration::win::GetAppUserModelIdForApp(
base::UTF8ToWide(browser->app_name()), profile_path)
: shell_integration::win::GetAppUserModelIdForBrowser(profile_path);
if (!app_user_model_id.empty()) {
ui::win::SetAppIdForWindow(
app_user_model_id,
overlay_window->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
}
}
#endif // BUILDFLAG(IS_WIN)
// Set the controls to be permanently visible. This means that calls such as
// UpdateControlsVisibility(false) will have no effect, the controls remain
// visible.
overlay_window->ForceControlsVisible(true);
return overlay_window;
}
// static
std::unique_ptr<content::DocumentOverlayWindow>
content::DocumentOverlayWindow::Create(
content::DocumentPictureInPictureWindowController* controller) {
return DocumentOverlayWindowViews::Create(controller);
}
DocumentOverlayWindowViews::DocumentOverlayWindowViews(
content::DocumentPictureInPictureWindowController* controller)
: controller_(controller) {}
DocumentOverlayWindowViews::~DocumentOverlayWindowViews() = default;
bool DocumentOverlayWindowViews::ControlsHitTestContainsPoint(
const gfx::Point& point) {
if (web_view_->GetMirroredBounds().Contains(point)) {
// Always allow interactions with the WebView
return true;
}
if (!AreControlsVisible())
return false;
if (GetBackToTabControlsBounds().Contains(point) ||
GetCloseControlsBounds().Contains(point)) {
return true;
}
return false;
}
content::PictureInPictureWindowController*
DocumentOverlayWindowViews::GetController() const {
return controller_;
}
void DocumentOverlayWindowViews::set_location_bar_view_proxy(
std::unique_ptr<OverlayLocationBarViewProxy> proxy) {
location_bar_view_proxy_ = std::move(proxy);
}
views::View* DocumentOverlayWindowViews::GetWindowBackgroundView() const {
return window_background_view_;
}
views::View* DocumentOverlayWindowViews::GetControlsContainerView() const {
return controls_container_view_;
}
const ui::ThemeProvider* DocumentOverlayWindowViews::GetThemeProvider() const {
// FIXME: is there a way to use a dark theme just for this window?
DCHECK(profile_for_theme_);
return &ThemeService::GetThemeProviderForProfile(profile_for_theme_);
}
void DocumentOverlayWindowViews::SetUpViews() {
// The window content consists of the fixed-height controls_container_view at
// the top which is a box layout, and the remainder of the view is filled with
// the content web view. ChromeOS adds a resize handle and changes the order,
// see UpdateResizeHandleBounds(quadrant) for more information.
//
// +----------------------+------+-------+
// | location bar | back | close |
// +----------------------+------+-------+
// | |
// | web view |
// | |
// +-------------------------------------+
content::WebContents* pip_contents = controller_->GetChildWebContents();
auto* profile =
Profile::FromBrowserContext(pip_contents->GetBrowserContext());
profile_for_theme_ = profile;
// In testing, the location bar view proxy is provided via Create.
// In production, it's created here.
if (!location_bar_view_proxy_) {
location_bar_view_proxy_ = std::make_unique<OverlayLocationBarViewImpl>(
profile, controller_->GetWebContents());
}
auto web_view = std::make_unique<views::WebView>(profile);
DVLOG(2) << __func__ << ": content WebView=" << web_view.get();
web_view->SetWebContents(pip_contents);
// View that is displayed when WebView is hidden. ----------------------------
// Adding an extra pixel to width/height makes sure controls background cover
// entirely window when platform has fractional scale applied.
auto window_background_view = std::make_unique<WindowBackgroundView>();
auto controls_container_view = std::make_unique<views::View>();
auto controls_box_owner = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal);
controls_box_owner->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
auto* controls_box =
controls_container_view->SetLayoutManager(std::move(controls_box_owner));
auto close_controls_view =
std::make_unique<CloseImageButton>(base::BindRepeating(
[](DocumentOverlayWindowViews* overlay) {
const bool should_pause = true;
overlay->controller_->Close(should_pause);
},
base::Unretained(this)));
std::unique_ptr<BackToTabImageButton> back_to_tab_image_button;
auto back_to_tab_callback = base::BindRepeating(
[](DocumentOverlayWindowViews* overlay) {
overlay->controller_->CloseAndFocusInitiator();
},
base::Unretained(this));
back_to_tab_image_button =
std::make_unique<BackToTabImageButton>(std::move(back_to_tab_callback));
#if BUILDFLAG(IS_CHROMEOS_ASH)
auto resize_handle_view =
std::make_unique<ResizeHandleButton>(views::Button::PressedCallback());
#endif
window_background_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
window_background_view->layer()->SetName("WindowBackgroundView");
// view::View that holds the WebView. ---------------------------------------
web_view->SetPaintToLayer(ui::LAYER_TEXTURED);
web_view->layer()->SetMasksToBounds(true);
web_view->layer()->SetFillsBoundsOpaquely(false);
web_view->layer()->SetName("WebView");
// views::View that is a parent of all the controls. Makes hiding and showing
// all the controls at once easier.
controls_container_view->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
controls_container_view->layer()->SetFillsBoundsOpaquely(false);
controls_container_view->layer()->SetName("ControlsContainerView");
// views::View that closes the window. --------------------------------------
close_controls_view->SetPaintToLayer(ui::LAYER_TEXTURED);
close_controls_view->layer()->SetFillsBoundsOpaquely(false);
close_controls_view->layer()->SetName("CloseControlsView");
// views::View that closes the window and focuses initiator tab. ------------
back_to_tab_image_button->SetPaintToLayer(ui::LAYER_TEXTURED);
back_to_tab_image_button->layer()->SetFillsBoundsOpaquely(false);
back_to_tab_image_button->layer()->SetName("BackToTabControlsView");
#if BUILDFLAG(IS_CHROMEOS_ASH)
// views::View that shows the affordance that the window can be resized. ----
resize_handle_view->SetPaintToLayer(ui::LAYER_TEXTURED);
resize_handle_view->layer()->SetFillsBoundsOpaquely(false);
resize_handle_view->layer()->SetName("ResizeHandleView");
resize_handle_view->layer()->SetOpacity(kResizeHandleOpacity);
#endif
// Set up view::Views hierarchy. --------------------------------------------
window_background_view_ =
AddChildView(&view_holder_, std::move(window_background_view));
web_view_ = AddChildView(&view_holder_, std::move(web_view));
location_bar_view_ = controls_container_view->AddChildView(
location_bar_view_proxy_->ReleaseView());
controls_box->SetFlexForView(location_bar_view_, 1);
back_to_tab_image_button_ = controls_container_view->AddChildView(
std::move(back_to_tab_image_button));
controls_box->SetFlexForView(back_to_tab_image_button_, 0);
close_controls_view_ =
controls_container_view->AddChildView(std::move(close_controls_view));
controls_box->SetFlexForView(close_controls_view_, 0);
#if BUILDFLAG(IS_CHROMEOS_ASH)
resize_handle_view_ =
controls_container_view->AddChildView(std::move(resize_handle_view));
controls_box->SetFlexForView(resize_handle_view_, 0);
#endif
controls_container_view_ =
AddChildView(&view_holder_, std::move(controls_container_view));
}
void DocumentOverlayWindowViews::OnRootViewReady() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
GetNativeWindow()->SetProperty(ash::kWindowPipTypeKey, true);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
GetRootView()->SetPaintToLayer(ui::LAYER_TEXTURED);
GetRootView()->layer()->SetName("RootView");
GetRootView()->layer()->SetMasksToBounds(true);
views::View* const contents_view = GetContentsView();
for (std::unique_ptr<views::View>& child : view_holder_)
contents_view->AddChildView(std::move(child));
view_holder_.clear();
location_bar_view_proxy_->Init();
location_bar_view_->SetVisible(true);
// Don't show the controls until the mouse hovers over the window.
UpdateControlsVisibility(false);
// FIXME, get aspect/size via PiP API
UpdateNaturalSize({400, 300});
}
void DocumentOverlayWindowViews::UpdateLayerBoundsWithLetterboxing(
gfx::Size window_size) {
// This is the case when the window is initially created or the video surface
// id has not been embedded.
if (!native_widget() || GetBounds().IsEmpty() || GetNaturalSize().IsEmpty())
return;
gfx::Rect letterbox_region = media::ComputeLetterboxRegion(
gfx::Rect(gfx::Point(0, 0), window_size), GetNaturalSize());
if (letterbox_region.IsEmpty())
return;
// To avoid black stripes in the window when integer window dimensions don't
// correspond to the content aspect ratio exactly (e.g. 854x480 for 16:9
// video) force the letterbox region size to be equal to the window size.
const float aspect_ratio =
static_cast<float>(GetNaturalSize().width()) / GetNaturalSize().height();
if (aspect_ratio > 1 && window_size.height() == letterbox_region.height()) {
const int height_from_width =
base::ClampRound(window_size.width() / aspect_ratio);
if (height_from_width == window_size.height())
letterbox_region.set_width(window_size.width());
} else if (aspect_ratio <= 1 &&
window_size.width() == letterbox_region.width()) {
const int width_from_height =
base::ClampRound(window_size.height() * aspect_ratio);
if (width_from_height == window_size.width())
letterbox_region.set_height(window_size.height());
}
const gfx::Rect content_bounds(
gfx::Point((window_size.width() - letterbox_region.size().width()) / 2,
(window_size.height() - letterbox_region.size().height()) / 2),
letterbox_region.size());
// Update the layout of the controls. (Do this immediately, bypassing
// UpdateControlsBounds from the parent class.)
OnUpdateControlsBounds();
// Update the surface layer bounds to scale with window size changes.
window_background_view_->SetBoundsRect(
gfx::Rect(gfx::Point(0, 0), GetBounds().size()));
gfx::Rect webview_bounds(
content_bounds.x(), content_bounds.y() + kTopControlsHeight,
content_bounds.width(), content_bounds.height() - kTopControlsHeight);
web_view_->SetBoundsRect(webview_bounds);
if (web_view_->layer()->has_external_content())
web_view_->layer()->SetSurfaceSize(webview_bounds.size());
}
void DocumentOverlayWindowViews::OnUpdateControlsBounds() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
OverlayWindowViews::WindowQuadrant quadrant =
OverlayWindowViews::GetCurrentWindowQuadrant(GetBounds(), controller_);
UpdateResizeHandleBounds(quadrant);
#endif
controls_container_view_->SetSize(
{GetBounds().size().width(), kTopControlsHeight});
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void DocumentOverlayWindowViews::UpdateResizeHandleBounds(
OverlayWindowViews::WindowQuadrant quadrant) {
//
if (quadrant == WindowQuadrant::kBottomLeft ||
quadrant == WindowQuadrant::kTopLeft) {
// Controls layout when the window is in the left half of the screen:
//
// +-------+------+-------------------+--------+
// | close | back | location bar | resize |
// +-------+------+-------------------+--------+
// | web view |
// +-------------------------------------------+
if (controls_container_view_->GetIndexOf(close_controls_view_) != 0u) {
resize_handle_view_->SetQuadrant(quadrant);
controls_container_view_->ReorderChildView(close_controls_view_, 0);
controls_container_view_->ReorderChildView(back_to_tab_image_button_, 1);
controls_container_view_->ReorderChildView(
resize_handle_view_, controls_container_view_->children().size());
// FIXME: controls_container_view_->InvalidateLayout() isn't sufficient?
controls_container_view_->Layout();
}
} else {
// Controls layout when the window is in the right half of the screen:
//
// +--------+-------------------+------+-------+
// | resize | location bar | back | close |
// +--------+-------------------+------+-------+
// | web view |
// +-------------------------------------------+
if (controls_container_view_->GetIndexOf(resize_handle_view_) != 0u) {
resize_handle_view_->SetQuadrant(quadrant);
controls_container_view_->ReorderChildView(
back_to_tab_image_button_,
controls_container_view_->children().size());
controls_container_view_->ReorderChildView(
close_controls_view_, controls_container_view_->children().size());
controls_container_view_->ReorderChildView(resize_handle_view_, 0);
// FIXME: controls_container_view_->InvalidateLayout() isn't sufficient?
controls_container_view_->Layout();
}
}
GetNativeWindow()->SetProperty(
ash::kWindowPipResizeHandleBoundsKey,
new gfx::Rect(GetResizeHandleControlsBounds()));
}
#endif
bool DocumentOverlayWindowViews::IsActive() {
return views::Widget::IsActive();
}
bool DocumentOverlayWindowViews::IsActive() const {
return views::Widget::IsActive();
}
void DocumentOverlayWindowViews::Close() {
views::Widget::Close();
}
void DocumentOverlayWindowViews::ShowInactive() {
DoShowInactive();
}
void DocumentOverlayWindowViews::Hide() {
views::Widget::Hide();
}
bool DocumentOverlayWindowViews::IsVisible() {
return views::Widget::IsVisible();
}
bool DocumentOverlayWindowViews::IsVisible() const {
return views::Widget::IsVisible();
}
bool DocumentOverlayWindowViews::IsAlwaysOnTop() {
return true;
}
gfx::Rect DocumentOverlayWindowViews::GetBounds() {
return views::Widget::GetRestoredBounds();
}
void DocumentOverlayWindowViews::UpdateNaturalSize(
const gfx::Size& natural_size) {
DoUpdateNaturalSize(natural_size);
}
void DocumentOverlayWindowViews::OnNativeWidgetMove() {
OverlayWindowViews::OnNativeWidgetMove();
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Update the positioning of some icons when the window is moved.
WindowQuadrant quadrant =
GetCurrentWindowQuadrant(GetRestoredBounds(), GetController());
UpdateResizeHandleBounds(quadrant);
#endif
}
void DocumentOverlayWindowViews::OnNativeWidgetDestroyed() {
views::Widget::OnNativeWidgetDestroyed();
controller_->OnWindowDestroyed(
/*should_pause_video=*/true);
}
void DocumentOverlayWindowViews::OnGestureEvent(ui::GestureEvent* event) {
if (OverlayWindowViews::OnGestureEventHandledOrIgnored(event))
return;
if (GetBackToTabControlsBounds().Contains(event->location())) {
controller_->CloseAndFocusInitiator();
event->SetHandled();
} else if (GetCloseControlsBounds().Contains(event->location())) {
controller_->Close(/*should_pause_video=*/true);
event->SetHandled();
}
}
gfx::Rect DocumentOverlayWindowViews::GetBackToTabControlsBounds() {
return back_to_tab_image_button_->GetMirroredBounds();
}
gfx::Rect DocumentOverlayWindowViews::GetCloseControlsBounds() {
return close_controls_view_->GetMirroredBounds();
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
gfx::Rect DocumentOverlayWindowViews::GetResizeHandleControlsBounds() {
return resize_handle_view_->GetMirroredBounds();
}
int DocumentOverlayWindowViews::GetResizeHTComponent() const {
return resize_handle_view_->GetHTComponent();
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
CloseImageButton* DocumentOverlayWindowViews::close_button_for_testing() const {
return close_controls_view_;
}
ui::Layer* DocumentOverlayWindowViews::document_layer_for_testing() const {
return web_view_->layer();
}

@ -1,119 +0,0 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_DOCUMENT_OVERLAY_WINDOW_VIEWS_H_
#define CHROME_BROWSER_UI_VIEWS_OVERLAY_DOCUMENT_OVERLAY_WINDOW_VIEWS_H_
#include "build/chromeos_buildflags.h"
#include "chrome/browser/ui/views/overlay/overlay_window_views.h"
class BackToTabImageButton;
class CloseImageButton;
class Profile;
class ResizeHandleButton;
class OverlayLocationBarViewProxy {
public:
OverlayLocationBarViewProxy() = default;
OverlayLocationBarViewProxy(const OverlayLocationBarViewProxy&) = delete;
OverlayLocationBarViewProxy& operator=(const OverlayLocationBarViewProxy&) =
delete;
virtual ~OverlayLocationBarViewProxy();
virtual void Init() = 0;
virtual std::unique_ptr<views::View> ReleaseView() = 0;
};
class DocumentOverlayWindowViews : public OverlayWindowViews,
public content::DocumentOverlayWindow {
public:
// Constructs and initializes an instance. Since it includes a location bar
// view which is rather testing hostile due to its many dependencies, the
// optional argument supports supplying a fake implementation.
static std::unique_ptr<DocumentOverlayWindowViews> Create(
content::DocumentPictureInPictureWindowController* controller,
std::unique_ptr<OverlayLocationBarViewProxy>
location_bar_view_proxy_for_testing = nullptr);
DocumentOverlayWindowViews(const DocumentOverlayWindowViews&) = delete;
DocumentOverlayWindowViews& operator=(const DocumentOverlayWindowViews&) =
delete;
~DocumentOverlayWindowViews() override;
// OverlayWindow:
bool IsActive() override;
void Close() override;
void ShowInactive() override;
void Hide() override;
bool IsVisible() override;
bool IsAlwaysOnTop() override;
gfx::Rect GetBounds() override;
void UpdateNaturalSize(const gfx::Size& natural_size) override;
// views::Widget:
bool IsActive() const override;
bool IsVisible() const override;
void OnNativeWidgetMove() override;
void OnNativeWidgetDestroyed() override;
const ui::ThemeProvider* GetThemeProvider() const override;
// OverlayWindowViews
bool ControlsHitTestContainsPoint(const gfx::Point& point) override;
#if BUILDFLAG(IS_CHROMEOS_ASH)
int GetResizeHTComponent() const override;
gfx::Rect GetResizeHandleControlsBounds() override;
void UpdateResizeHandleBounds(WindowQuadrant quadrant) override;
#endif
void OnUpdateControlsBounds() override;
void OnGestureEvent(ui::GestureEvent* event) override;
void SetUpViews() override;
void OnRootViewReady() override;
void UpdateLayerBoundsWithLetterboxing(gfx::Size window_size) override;
content::PictureInPictureWindowController* GetController() const override;
views::View* GetWindowBackgroundView() const override;
views::View* GetControlsContainerView() const override;
// Gets the bounds of the controls.
gfx::Rect GetBackToTabControlsBounds();
gfx::Rect GetCloseControlsBounds();
// Unit test support.
CloseImageButton* close_button_for_testing() const;
ui::Layer* document_layer_for_testing() const;
void set_location_bar_view_proxy(
std::unique_ptr<OverlayLocationBarViewProxy> proxy);
private:
explicit DocumentOverlayWindowViews(
content::DocumentPictureInPictureWindowController* controller);
// Calculate and set the bounds of the controls.
gfx::Rect CalculateControlsBounds(int x, const gfx::Size& size);
// Not owned; |controller_| owns |this|.
raw_ptr<content::DocumentPictureInPictureWindowController> controller_ =
nullptr;
std::unique_ptr<OverlayLocationBarViewProxy> location_bar_view_proxy_;
raw_ptr<Profile> profile_for_theme_ = nullptr;
// Temporary storage for child Views. Used during the time between
// construction and initialization, when the views::View pointer members must
// already be initialized, but there is no root view to add them to yet.
std::vector<std::unique_ptr<views::View>> view_holder_;
// Views to be shown. The views are first temporarily owned by view_holder_,
// then passed to this widget's ContentsView which takes ownership.
raw_ptr<views::View> window_background_view_ = nullptr;
raw_ptr<views::View> web_view_ = nullptr;
raw_ptr<views::View> controls_container_view_ = nullptr;
raw_ptr<views::View> location_bar_view_ = nullptr;
raw_ptr<CloseImageButton> close_controls_view_ = nullptr;
raw_ptr<BackToTabImageButton> back_to_tab_image_button_ = nullptr;
raw_ptr<ResizeHandleButton> resize_handle_view_ = nullptr;
};
#endif // CHROME_BROWSER_UI_VIEWS_OVERLAY_DOCUMENT_OVERLAY_WINDOW_VIEWS_H_

@ -1,450 +0,0 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/overlay/document_overlay_window_views.h"
#include <memory>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/ui/views/overlay/close_image_button.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "content/public/browser/document_picture_in_picture_window_controller.h"
#include "content/public/browser/overlay_window.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_web_contents_factory.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer.h"
#include "ui/display/test/scoped_screen_override.h"
#include "ui/display/test/test_screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/views/test/button_test_api.h"
namespace {
constexpr gfx::Size kMinWindowSize(200, 100);
} // namespace
class FakeOverlayLocationBarView : public OverlayLocationBarViewProxy {
public:
FakeOverlayLocationBarView() {
view_holder_ = std::make_unique<views::View>();
}
~FakeOverlayLocationBarView() override = default;
void Init() override {}
std::unique_ptr<views::View> ReleaseView() override {
return std::move(view_holder_);
}
private:
std::unique_ptr<views::View> view_holder_;
};
class TestDocumentPictureInPictureWindowController
: public content::DocumentPictureInPictureWindowController {
public:
TestDocumentPictureInPictureWindowController() = default;
// PictureInPictureWindowController:
void Show() override {}
void FocusInitiator() override {}
MOCK_METHOD(void, Close, (bool));
void CloseAndFocusInitiator() override {}
MOCK_METHOD(void, OnWindowDestroyed, (bool));
content::WebContents* GetWebContents() override { return web_contents_; }
content::WebContents* GetChildWebContents() override {
return child_web_contents_;
}
// DocumentPictureInPictureWindowController
void SetChildWebContents(content::WebContents* child) override {
child_web_contents_ = child;
}
void set_web_contents(content::WebContents* web_contents) {
web_contents_ = web_contents;
}
void destroy() { child_web_contents_ = nullptr; }
absl::optional<gfx::Rect> GetWindowBounds() override { return absl::nullopt; }
private:
raw_ptr<content::WebContents> web_contents_;
raw_ptr<content::WebContents> child_web_contents_;
};
class DocumentOverlayWindowViewsTest : public ChromeViewsTestBase {
public:
DocumentOverlayWindowViewsTest() = default;
// ChromeViewsTestBase:
void SetUp() override {
// Purposely skip ChromeViewsTestBase::SetUp() as that creates ash::Shell
// on ChromeOS, which we don't want.
ViewsTestBase::SetUp();
// web_contents_ needs to be created after the constructor, so that
// |feature_list_| can be initialized before other threads check if a
// feature is enabled.
web_contents_ = web_contents_factory_.CreateWebContents(&profile_);
pip_window_controller_.set_web_contents(web_contents_);
// The child web contents will be owned by the WebView, so create them
// separately. (WebContentsFactory owns its created WebContents which isn't
// compatible with this usage.)
auto child =
content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
pip_window_controller_.SetChildWebContents(child.get());
#if BUILDFLAG(IS_CHROMEOS)
test_views_delegate()->set_context(GetContext());
#endif
test_views_delegate()->set_use_desktop_native_widgets(true);
// The default work area must be big enough to fit the minimum
// DocumentOverlayWindowViews size.
SetDisplayWorkArea({0, 0, 1000, 1000});
auto fake_location_bar = std::make_unique<FakeOverlayLocationBarView>();
overlay_window_ = DocumentOverlayWindowViews::Create(
&pip_window_controller_, std::move(fake_location_bar));
overlay_window_->set_minimum_size_for_testing(kMinWindowSize);
}
void TearDown() override {
// AutocompleteClassifierFactory::GetInstance()->Disassociate(&profile_);
base::RunLoop().RunUntilIdle();
pip_window_controller_.destroy();
overlay_window_.reset();
ViewsTestBase::TearDown();
}
void SetDisplayWorkArea(const gfx::Rect& work_area) {
display::Display display = test_screen_.GetPrimaryDisplay();
display.set_work_area(work_area);
test_screen_.display_list().UpdateDisplay(display);
}
DocumentOverlayWindowViews& overlay_window() { return *overlay_window_; }
content::WebContents* web_contents() { return web_contents_; }
TestDocumentPictureInPictureWindowController& pip_window_controller() {
return pip_window_controller_;
}
private:
TestingProfile profile_;
content::TestWebContentsFactory web_contents_factory_;
raw_ptr<content::WebContents> web_contents_;
TestDocumentPictureInPictureWindowController pip_window_controller_;
display::test::TestScreen test_screen_;
display::test::ScopedScreenOverride scoped_screen_override_{&test_screen_};
std::unique_ptr<DocumentOverlayWindowViews> overlay_window_;
};
TEST_F(DocumentOverlayWindowViewsTest, InitialWindowSize_Square) {
// Fit the window taking 1/5 (both dimensions) of the work area as the
// starting size, and applying the size and aspect ratio constraints.
overlay_window().UpdateNaturalSize({400, 400});
EXPECT_EQ(gfx::Size(200, 200), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(200, 170),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, InitialWindowSize_Horizontal) {
// Set an arbitrary starting position in the top left corner. Otherwise, since
// OnRootViewReady has already set a content size, the default window position
// would be at the bottom right which results in a ResizeEdge::kTopLeft that
// is considered a horizontal resize which shrinks the window. If it starts
// out at the top left, we get ResizeEdge::kBottomRight which is a vertical
// resize that enlarges the window.
overlay_window().SetBounds({0, 0, 200, 200});
// Fit the window taking 1/5 (both dimensions) of the work area as the
// starting size, and applying the size and aspect ratio constraints.
overlay_window().UpdateNaturalSize({400, 200});
EXPECT_EQ(gfx::Size(400, 200), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(400, 170),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, InitialWindowSize_Vertical) {
// Fit the window taking 1/5 (both dimensions) of the work area as the
// starting size, and applying the size and aspect ratio constraints.
overlay_window().UpdateNaturalSize({400, 500});
EXPECT_EQ(gfx::Size(200, 250), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(200, 220),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, Letterboxing) {
overlay_window().UpdateNaturalSize({400, 10});
// Must fit within the minimum height of 146. But with the aspect ratio of
// 40:1 the width gets exceedingly big and must be limited to the maximum of
// 800. Thus, letterboxing is unavoidable.
EXPECT_EQ(gfx::Size(800, 100), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(800, 0),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, Pillarboxing) {
overlay_window().UpdateNaturalSize({10, 400});
// Must fit within the minimum width of 260. But with the aspect ratio of
// 1:40 the height gets exceedingly big and must be limited to the maximum of
// 800. Thus, pillarboxing is unavoidable.
EXPECT_EQ(gfx::Size(200, 800), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(20, 770),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, Pillarboxing_Square) {
overlay_window().UpdateNaturalSize({100, 100});
// Pillarboxing also occurs on Linux even with the square aspect ratio,
// because the user is allowed to size the window to the rectangular minimum
// size.
overlay_window().SetSize({200, 100});
EXPECT_EQ(gfx::Size(100, 70),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, ApproximateAspectRatio_Horizontal) {
// "Horizontal" video.
overlay_window().UpdateNaturalSize({320, 240});
// The user drags the window resizer horizontally and now the integer window
// dimensions can't reproduce the video aspect ratio exactly. The video
// should still fill the entire window area.
overlay_window().SetSize({320, 240});
EXPECT_EQ(gfx::Size(320, 210),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({321, 241});
EXPECT_EQ(gfx::Size(321, 211),
overlay_window().document_layer_for_testing()->size());
// Wide video.
overlay_window().UpdateNaturalSize({1600, 900});
overlay_window().SetSize({444, 250});
EXPECT_EQ(gfx::Size(444, 220),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({445, 250});
EXPECT_EQ(gfx::Size(445, 220),
overlay_window().document_layer_for_testing()->size());
// Very wide video.
overlay_window().UpdateNaturalSize({400, 100});
overlay_window().SetSize({478, 120});
EXPECT_EQ(gfx::Size(478, 90),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({481, 120});
EXPECT_EQ(gfx::Size(481, 90),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, ApproximateAspectRatio_Vertical) {
// "Vertical" video.
overlay_window().UpdateNaturalSize({240, 320});
// The user dragged the window resizer vertically and now the integer window
// dimensions can't reproduce the video aspect ratio exactly. The video
// should still fill the entire window area.
overlay_window().SetSize({240, 320});
EXPECT_EQ(gfx::Size(240, 290),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({239, 319});
EXPECT_EQ(gfx::Size(239, 289),
overlay_window().document_layer_for_testing()->size());
// Narrow video.
overlay_window().UpdateNaturalSize({900, 1600});
overlay_window().SetSize({250, 444});
EXPECT_EQ(gfx::Size(250, 414),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({250, 445});
EXPECT_EQ(gfx::Size(250, 415),
overlay_window().document_layer_for_testing()->size());
// Very narrow video.
// NOTE: Window width is bounded by the minimum size.
overlay_window().UpdateNaturalSize({100, 400});
overlay_window().SetSize({200, 478});
EXPECT_EQ(gfx::Size(120, 448),
overlay_window().document_layer_for_testing()->size());
overlay_window().SetSize({200, 481});
EXPECT_EQ(gfx::Size(120, 451),
overlay_window().document_layer_for_testing()->size());
}
TEST_F(DocumentOverlayWindowViewsTest, UpdateMaximumSize) {
SetDisplayWorkArea({0, 0, 4000, 4000});
overlay_window().UpdateNaturalSize({480, 320});
// The initial size is determined by the work area and the video natural size
// (aspect ratio).
EXPECT_EQ(gfx::Size(1200, 800), overlay_window().GetBounds().size());
// The initial maximum size is 80% of the work area.
EXPECT_EQ(gfx::Size(3200, 3200), overlay_window().GetMaximumSize());
// If the maximum size increases then we should keep the existing window size.
SetDisplayWorkArea({0, 0, 8000, 8000});
EXPECT_EQ(gfx::Size(1200, 800), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(6400, 6400), overlay_window().GetMaximumSize());
// If the maximum size decreases then we should shrink to fit.
SetDisplayWorkArea({0, 0, 1000, 2000});
EXPECT_EQ(gfx::Size(800, 800), overlay_window().GetBounds().size());
EXPECT_EQ(gfx::Size(800, 1600), overlay_window().GetMaximumSize());
}
TEST_F(DocumentOverlayWindowViewsTest, IgnoreInvalidMaximumSize) {
ASSERT_EQ(gfx::Size(800, 800), overlay_window().GetMaximumSize());
SetDisplayWorkArea({0, 0, 0, 0});
EXPECT_EQ(gfx::Size(800, 800), overlay_window().GetMaximumSize());
}
TEST_F(DocumentOverlayWindowViewsTest, UpdateNaturalSizeDoesNotMoveWindow) {
// Enter PiP.
overlay_window().UpdateNaturalSize({300, 200});
overlay_window().ShowInactive();
// Resize the window and move it toward the top-left corner of the work area.
// In production, resizing preserves the aspect ratio if possible, so we
// preserve it here too.
overlay_window().SetBounds({100, 100, 450, 300});
// Simulate a new surface layer and a change in the aspect ratio.
overlay_window().UpdateNaturalSize({400, 200});
// The window should not move.
// The window size will be adjusted according to the new aspect ratio, and
// clamped to 600x300 to fit within the maximum size for the work area of
// 1000x1000.
EXPECT_EQ(gfx::Rect(100, 100, 600, 300), overlay_window().GetBounds());
}
// Tests that the OverlayWindowFrameView does not accept events so they can
// propagate to the overlay.
TEST_F(DocumentOverlayWindowViewsTest, HitTestFrameView) {
// Since the NonClientFrameView is the only non-custom direct descendent of
// the NonClientView, we can assume that if the frame does not accept the
// point but the NonClientView does, then it will be handled by one of the
// custom overlay views.
auto point = gfx::Point(50, 50);
views::NonClientView* non_client_view = overlay_window().non_client_view();
EXPECT_EQ(non_client_view->frame_view()->HitTestPoint(point), false);
EXPECT_EQ(non_client_view->HitTestPoint(point), true);
}
// Tests that hit tests on various areas of the window have the expected
// hit test type.
TEST_F(DocumentOverlayWindowViewsTest, HitTestTypesByLocation) {
views::NonClientView* view = overlay_window().non_client_view();
overlay_window().UpdateNaturalSize({200, 200});
// The corners and edges of the frame support resizing.
EXPECT_EQ(view->NonClientHitTest({1, 1}), HTTOPLEFT);
EXPECT_EQ(view->NonClientHitTest({198, 1}), HTTOPRIGHT);
EXPECT_EQ(view->NonClientHitTest({1, 100}), HTLEFT);
EXPECT_EQ(view->NonClientHitTest({198, 100}), HTRIGHT);
EXPECT_EQ(view->NonClientHitTest({1, 198}), HTBOTTOMLEFT);
EXPECT_EQ(view->NonClientHitTest({198, 198}), HTBOTTOMRIGHT);
// The middle of the controls bar allows dragging the window.
EXPECT_EQ(view->NonClientHitTest({100, 15}), HTCAPTION);
// The right side of the control bar contains the close button
// which is interactive.
EXPECT_EQ(view->NonClientHitTest({185, 15}), HTNOWHERE);
// Clicks on the web content area must not be intercepted so that
// interactions remain possible.
EXPECT_EQ(view->NonClientHitTest({100, 100}), HTNOWHERE);
}
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// With pillarboxing, the close button doesn't cover the video area. Make sure
// hovering the button doesn't get handled like normal mouse exit events
// causing the controls to hide.
TEST_F(DocumentOverlayWindowViewsTest, NoMouseExitWithinWindowBounds) {
overlay_window().UpdateNaturalSize({10, 400});
const auto close_button_bounds = overlay_window().GetCloseControlsBounds();
const auto video_bounds =
overlay_window().document_layer_for_testing()->bounds();
ASSERT_FALSE(video_bounds.Contains(close_button_bounds));
const gfx::Point moved_location(video_bounds.origin() + gfx::Vector2d(5, 5));
ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, moved_location, moved_location,
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
overlay_window().OnMouseEvent(&moved_event);
ASSERT_TRUE(overlay_window().AreControlsVisible());
const gfx::Point exited_location(close_button_bounds.CenterPoint());
ui::MouseEvent exited_event(ui::ET_MOUSE_EXITED, exited_location,
exited_location, ui::EventTimeForNow(),
ui::EF_NONE, ui::EF_NONE);
overlay_window().OnMouseEvent(&exited_event);
EXPECT_TRUE(overlay_window().AreControlsVisible());
}
#endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_F(DocumentOverlayWindowViewsTest, PauseOnCloseButton) {
views::test::ButtonTestApi close_button_clicker(
overlay_window().close_button_for_testing());
ui::MouseEvent dummy_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
// Closing via the close button should pause the content.
EXPECT_CALL(pip_window_controller(), Close(true));
close_button_clicker.NotifyClick(dummy_event);
testing::Mock::VerifyAndClearExpectations(&pip_window_controller());
}
TEST_F(DocumentOverlayWindowViewsTest, PauseOnWidgetClose) {
// When the native widget is destroyed we should pause the underlying content.
EXPECT_CALL(pip_window_controller(), OnWindowDestroyed(true));
overlay_window().CloseNow();
testing::Mock::VerifyAndClearExpectations(&pip_window_controller());
}
TEST_F(DocumentOverlayWindowViewsTest, SmallDisplayWorkAreaDoesNotCrash) {
SetDisplayWorkArea({0, 0, 240, 120});
overlay_window().UpdateNaturalSize({400, 300});
// Since the work area would force a max size smaller than the minimum size,
// the size is fixed at the minimum size.
EXPECT_EQ(kMinWindowSize, overlay_window().GetBounds().size());
EXPECT_EQ(kMinWindowSize, overlay_window().GetMaximumSize());
// The video should still be letterboxed to the correct aspect ratio.
EXPECT_EQ(gfx::Size(133, 70),
overlay_window().document_layer_for_testing()->size());
}

@ -455,10 +455,6 @@ void OverlayWindowViews::RecordButtonPressed(
}
void OverlayWindowViews::ForceControlsVisibleForTesting(bool visible) {
ForceControlsVisible(visible);
}
void OverlayWindowViews::ForceControlsVisible(bool visible) {
force_controls_visible_ = visible;
UpdateControlsVisibility(visible);
}

@ -16,9 +16,9 @@
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget.h"
// Base class for the Chrome desktop implementation of VideoOverlayWindow and
// DocumentOverlayWindow. This will only be implemented in views, which will
// support all desktop platforms.
// Base class for the Chrome desktop implementation of VideoOverlayWindow.
// This will only be implemented in views, which will support all desktop
// platforms.
//
// This class is a views::Widget. The subclasses implement the needed
// methods for their corresponding OverlayWindow subclass.
@ -89,9 +89,7 @@ class OverlayWindowViews : public views::Widget,
// Updates the controls view::Views to reflect |is_visible|.
void UpdateControlsVisibility(bool is_visible);
// DocumentOverlayWindowViews currently always forces the controls
// to be visible. VideoOverlayWindowViews does so for testing.
void ForceControlsVisible(bool visible);
// VideoOverlayWindowViews does this for testing.
void ForceControlsVisibleForTesting(bool visible);
// Determines whether a layout of the window controls has been scheduled but

@ -8835,7 +8835,6 @@ test("unit_tests") {
"../browser/ui/views/omnibox/omnibox_match_cell_view_unittest.cc",
"../browser/ui/views/omnibox/omnibox_result_view_unittest.cc",
"../browser/ui/views/omnibox/omnibox_view_views_unittest.cc",
"../browser/ui/views/overlay/document_overlay_window_views_unittest.cc",
"../browser/ui/views/overlay/video_overlay_window_views_unittest.cc",
"../browser/ui/views/page_action/page_action_icon_view_unittest.cc",
"../browser/ui/views/page_info/page_info_bubble_view_unittest.cc",

@ -1109,12 +1109,6 @@ ContentBrowserClient::CreateWindowForVideoPictureInPicture(
return nullptr;
}
std::unique_ptr<DocumentOverlayWindow>
ContentBrowserClient::CreateWindowForDocumentPictureInPicture(
DocumentPictureInPictureWindowController* controller) {
return nullptr;
}
void ContentBrowserClient::RegisterRendererPreferenceWatcher(
BrowserContext* browser_context,
mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher) {

@ -205,8 +205,6 @@ class ClientCertificateDelegate;
class ControllerPresentationServiceDelegate;
class DevToolsManagerDelegate;
class DirectSocketsDelegate;
class DocumentOverlayWindow;
class DocumentPictureInPictureWindowController;
class FeatureObserverClient;
class FontAccessDelegate;
class HidDelegate;
@ -1964,18 +1962,15 @@ class CONTENT_EXPORT ContentBrowserClient {
RenderFrameHost* initiator_document,
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory);
// Creates an OverlayWindow to be used for video or document
// Picture-in-Picture respectively. This window will house the content shown
// when in Picture-in-Picture mode. This will return a new OverlayWindow.
// Creates an OverlayWindow to be used for video or Picture-in-Picture.
// This window will house the content shown when in Picture-in-Picture mode.
// This will return a new OverlayWindow.
//
// May return nullptr if embedder does not support this functionality. The
// default implementation provides nullptr OverlayWindow.
virtual std::unique_ptr<VideoOverlayWindow>
CreateWindowForVideoPictureInPicture(
VideoPictureInPictureWindowController* controller);
virtual std::unique_ptr<DocumentOverlayWindow>
CreateWindowForDocumentPictureInPicture(
DocumentPictureInPictureWindowController* controller);
// Registers the watcher to observe updates in RendererPreferences.
virtual void RegisterRendererPreferenceWatcher(