Skip to content

Commit

Permalink
feat: enable picture-in-picture mode for video tags (#17686)
Browse files Browse the repository at this point in the history
* feat: enable picture in picture mode for video tags

* test: add test to verify picture in picture support

* lint: fix indent

* fix: clean up after rebase

* test: update test with 16:9 test video

* fix: .paches after rebase
  • Loading branch information
brenca authored and zcbenz committed Aug 22, 2019
1 parent 46b6bcd commit 9ccd6aa
Show file tree
Hide file tree
Showing 15 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions buildflags/BUILD.gn
Expand Up @@ -18,6 +18,7 @@ buildflag_header("buildflags") {
"ENABLE_TTS=$enable_tts",
"ENABLE_COLOR_CHOOSER=$enable_color_chooser",
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
]
}
2 changes: 2 additions & 0 deletions buildflags/buildflags.gni
Expand Up @@ -18,6 +18,8 @@ declare_args() {

enable_color_chooser = true

enable_picture_in_picture = true

# Provide a fake location provider for mocking
# the geolocation responses. Disable it if you
# need to test with chromium's location provider.
Expand Down
28 changes: 28 additions & 0 deletions chromium_src/BUILD.gn
Expand Up @@ -184,4 +184,32 @@ static_library("chrome") {
]
}
}

if (enable_picture_in_picture) {
sources += [
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc",
"//chrome/browser/picture_in_picture/picture_in_picture_window_manager.h",
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.cc",
"//chrome/browser/ui/views/overlay/back_to_tab_image_button.h",
"//chrome/browser/ui/views/overlay/close_image_button.cc",
"//chrome/browser/ui/views/overlay/close_image_button.h",
"//chrome/browser/ui/views/overlay/mute_image_button.cc",
"//chrome/browser/ui/views/overlay/mute_image_button.h",
"//chrome/browser/ui/views/overlay/overlay_window_views.cc",
"//chrome/browser/ui/views/overlay/overlay_window_views.h",
"//chrome/browser/ui/views/overlay/playback_image_button.cc",
"//chrome/browser/ui/views/overlay/playback_image_button.h",
"//chrome/browser/ui/views/overlay/resize_handle_button.cc",
"//chrome/browser/ui/views/overlay/resize_handle_button.h",
"//chrome/browser/ui/views/overlay/skip_ad_label_button.cc",
"//chrome/browser/ui/views/overlay/skip_ad_label_button.h",
"//chrome/browser/ui/views/overlay/track_image_button.cc",
"//chrome/browser/ui/views/overlay/track_image_button.h",
]

deps += [
"//chrome/app/vector_icons",
"//components/vector_icons:vector_icons",
]
}
}
51 changes: 51 additions & 0 deletions electron_strings.grdp
Expand Up @@ -18,4 +18,55 @@
<message name="IDS_DESKTOP_MEDIA_PICKER_MULTIPLE_SCREEN_NAME" desc="Name for screens in the desktop media picker UI when there are multiple monitors.">
{SCREEN_INDEX, plural, =1{Screen #} other{Screen #}}
</message>

<!-- Picture-in-Picture -->
<if expr="is_macosx">
<message name="IDS_PICTURE_IN_PICTURE_TITLE_TEXT" desc="Title of the Picture-in-Picture window. This appears in the system tray and window header.">
Picture in Picture
</message>
</if>
<if expr="not is_macosx">
<message name="IDS_PICTURE_IN_PICTURE_TITLE_TEXT" desc="Title of the Picture-in-Picture window. This appears in the system tray and window header.">
Picture in picture
</message>
</if>
<message name="IDS_PICTURE_IN_PICTURE_PAUSE_CONTROL_TEXT" desc="Text label of the pause control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently playing.">
Pause
</message>
<message name="IDS_PICTURE_IN_PICTURE_PLAY_CONTROL_TEXT" desc="Text label of the play control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently paused.">
Play
</message>
<message name="IDS_PICTURE_IN_PICTURE_REPLAY_CONTROL_TEXT" desc="Text label of the replay control button. The button appears when the user hovers over the Picture-in-Picture window and the video is ended.">
Play from the beginning
</message>
<message name="IDS_PICTURE_IN_PICTURE_BACK_TO_TAB_CONTROL_TEXT" desc="Text label of the back to tab control button. The button appears when the user hovers over the Picture-in-Picture window.">
Back to video player
</message>
<message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_TEXT" desc="Text label of the mute control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently unmuted.">
Mute
</message>
<message name="IDS_PICTURE_IN_PICTURE_UNMUTE_CONTROL_TEXT" desc="Text label of the mute control button. The button appears when the user hovers over the Picture-in-Picture window and the video is currently muted.">
Unmute
</message>
<message name="IDS_PICTURE_IN_PICTURE_SKIP_AD_CONTROL_TEXT" desc="Text label of the skip ad control button. The button appears when the user hovers over the Picture-in-Picture window.">
Skip Ad
</message>
<message name="IDS_PICTURE_IN_PICTURE_CLOSE_CONTROL_TEXT" desc="Text label of the close control button. The button appears when the user hovers over the Picture-in-Picture window.">
Close
</message>
<message name="IDS_PICTURE_IN_PICTURE_RESIZE_HANDLE_TEXT" desc="Text label of the resize handle. The button appears when the user hovers over the Picture-in-Picture window.">
Resize
</message>
<message name="IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles between play and pause controls.">
Toggle video to play or pause
</message>
<message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles mute state.">
Toggle mute
</message>
<message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action.">
Next track
</message>
<message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action.">
Previous track
</message>
</grit-part>
1 change: 1 addition & 0 deletions patches/chromium/.patches
Expand Up @@ -74,3 +74,4 @@ build_win_disable_zc_twophase.patch
disable_color_correct_rendering.patch
add_contentgpuclient_precreatemessageloop_callback.patch
fix_vc_incompatible_inline_calls.patch
picture-in-picture.patch
110 changes: 110 additions & 0 deletions patches/chromium/picture-in-picture.patch
@@ -0,0 +1,110 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Heilig Benedek <benecene@gmail.com>
Date: Sat, 10 Aug 2019 00:41:50 +0200
Subject: feat: enable picture in picture mode for video players


diff --git a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
index 8e4deafa1746eeb48802a0503fefb37bedb33d04..127c62efd2327e1f3f09e9b93a0b8344e2714f80 100644
--- a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
+++ b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
@@ -4,7 +4,7 @@

#include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h"

-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc
index 0aca25164dcad26cc000e289d6eb9010e336e6fc..70114b5aa865b96d3ace898d1faf515b9098abd9 100644
--- a/chrome/browser/ui/views/overlay/close_image_button.cc
+++ b/chrome/browser/ui/views/overlay/close_image_button.cc
@@ -4,7 +4,7 @@

#include "chrome/browser/ui/views/overlay/close_image_button.h"

-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.cc b/chrome/browser/ui/views/overlay/mute_image_button.cc
index 8c88ef08dd5165c0429dd90e8a76b711ac15a4df..ebdb06a6391b8108fa51796a4ad5f3a8ca489b60 100644
--- a/chrome/browser/ui/views/overlay/mute_image_button.cc
+++ b/chrome/browser/ui/views/overlay/mute_image_button.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/ui/views/overlay/mute_image_button.h"

#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 780863193ca12ec1295752969dfc47ac06a9ae64..e2947b893cfcdb1beaa27beac80a1885ed011ce4 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/ui/views/overlay/resize_handle_button.h"
#include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
#include "chrome/browser/ui/views/overlay/track_image_button.h"
-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/picture_in_picture_window_controller.h"
#include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/views/overlay/playback_image_button.cc b/chrome/browser/ui/views/overlay/playback_image_button.cc
index d9e5174ed622fb030bc37d32fbb40b132d7c4c23..1bf19c344721e74bb29c11a4c5c762a75e5cd821 100644
--- a/chrome/browser/ui/views/overlay/playback_image_button.cc
+++ b/chrome/browser/ui/views/overlay/playback_image_button.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/ui/views/overlay/playback_image_button.h"

#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.cc b/chrome/browser/ui/views/overlay/resize_handle_button.cc
index ee6b3612d7bdda591e05e5af338a80167ce6cd53..af093f14f1ef49c6de7228b296c32532203ca568 100644
--- a/chrome/browser/ui/views/overlay/resize_handle_button.cc
+++ b/chrome/browser/ui/views/overlay/resize_handle_button.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/ui/views/overlay/resize_handle_button.h"

#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
index da780c96bb757d7382df5f419e2c0fd644ac72b0..ae520bcf73cf6c39ca428c03975746e20b23c3ee 100644
--- a/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
+++ b/chrome/browser/ui/views/overlay/skip_ad_label_button.cc
@@ -4,7 +4,7 @@

#include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"

-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
#include "ui/views/background.h"
diff --git a/chrome/browser/ui/views/overlay/track_image_button.cc b/chrome/browser/ui/views/overlay/track_image_button.cc
index 8f42277409a216f81d21723eb03045ac54525b0e..f7a15bfde9a43c15b18e8afbd60a0b19960f2c93 100644
--- a/chrome/browser/ui/views/overlay/track_image_button.cc
+++ b/chrome/browser/ui/views/overlay/track_image_button.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/ui/views/overlay/track_image_button.h"

#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/grit/generated_resources.h"
+#include "electron/grit/electron_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
11 changes: 11 additions & 0 deletions shell/browser/atom_browser_client.cc
Expand Up @@ -402,6 +402,9 @@ void AtomBrowserClient::OverrideWebkitPrefs(content::RenderViewHost* host,
prefs->default_minimum_page_scale_factor = 1.f;
prefs->default_maximum_page_scale_factor = 1.f;
prefs->navigate_on_drag_drop = false;
#if !BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
prefs->picture_in_picture_enabled = false;
#endif

ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
prefs->preferred_color_scheme = native_theme->ShouldUseDarkColors()
Expand Down Expand Up @@ -684,6 +687,14 @@ bool AtomBrowserClient::CanCreateWindow(
return false;
}

#if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
std::unique_ptr<content::OverlayWindow>
AtomBrowserClient::CreateWindowForPictureInPicture(
content::PictureInPictureWindowController* controller) {
return content::OverlayWindow::Create(controller);
}
#endif

void AtomBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_schemes) {
auto schemes_list = api::GetStandardSchemes();
Expand Down
5 changes: 5 additions & 0 deletions shell/browser/atom_browser_client.h
Expand Up @@ -14,6 +14,7 @@
#include "base/synchronization/lock.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host_observer.h"
#include "electron/buildflags/buildflags.h"
#include "net/ssl/client_cert_identity.h"

namespace content {
Expand Down Expand Up @@ -127,6 +128,10 @@ class AtomBrowserClient : public content::ContentBrowserClient,
bool user_gesture,
bool opener_suppressed,
bool* no_javascript_access) override;
#if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
std::unique_ptr<content::OverlayWindow> CreateWindowForPictureInPicture(
content::PictureInPictureWindowController* controller) override;
#endif
void GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_schemes) override;
void GetAdditionalWebUISchemes(
Expand Down
23 changes: 23 additions & 0 deletions shell/browser/common_web_contents_delegate.cc
Expand Up @@ -55,6 +55,10 @@
#include "shell/browser/printing/print_preview_message_handler.h"
#endif

#if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
#endif

using content::BrowserThread;

namespace electron {
Expand Down Expand Up @@ -636,4 +640,23 @@ void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
native_fullscreen_ = false;
}

content::PictureInPictureResult
CommonWebContentsDelegate::EnterPictureInPicture(
content::WebContents* web_contents,
const viz::SurfaceId& surface_id,
const gfx::Size& natural_size) {
#if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
return PictureInPictureWindowManager::GetInstance()->EnterPictureInPicture(
web_contents, surface_id, natural_size);
#else
return content::PictureInPictureResult::kNotSupported;
#endif
}

void CommonWebContentsDelegate::ExitPictureInPicture() {
#if BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture();
#endif
}

} // namespace electron
5 changes: 5 additions & 0 deletions shell/browser/common_web_contents_delegate.h
Expand Up @@ -102,6 +102,11 @@ class CommonWebContentsDelegate : public content::WebContentsDelegate,
bool HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
content::PictureInPictureResult EnterPictureInPicture(
content::WebContents* web_contents,
const viz::SurfaceId&,
const gfx::Size& natural_size) override;
void ExitPictureInPicture() override;

// InspectableWebContentsDelegate:
void DevToolsSaveToFile(const std::string& url,
Expand Down
5 changes: 5 additions & 0 deletions shell/browser/feature_list.cc
Expand Up @@ -10,6 +10,8 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "content/public/common/content_features.h"
#include "electron/buildflags/buildflags.h"
#include "media/base/media_switches.h"

namespace electron {

Expand All @@ -25,6 +27,9 @@ void InitializeFeatureList() {
// when node integration is enabled.
disable_features +=
std::string(",") + features::kSpareRendererForSitePerProcess.name;
#if !BUILDFLAG(ENABLE_PICTURE_IN_PICTURE)
disable_features += std::string(",") + media::kPictureInPicture.name;
#endif
base::FeatureList::InitializeInstance(enable_features, disable_features);
}

Expand Down
5 changes: 5 additions & 0 deletions shell/common/api/features.cc
Expand Up @@ -45,6 +45,10 @@ bool IsExtensionsEnabled() {
return BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS);
}

bool IsPictureInPictureEnabled() {
return BUILDFLAG(ENABLE_PICTURE_IN_PICTURE);
}

bool IsComponentBuild() {
#if defined(COMPONENT_BUILD)
return true;
Expand All @@ -67,6 +71,7 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("isViewApiEnabled", &IsViewApiEnabled);
dict.SetMethod("isTtsEnabled", &IsTtsEnabled);
dict.SetMethod("isPrintingEnabled", &IsPrintingEnabled);
dict.SetMethod("isPictureInPictureEnabled", &IsPictureInPictureEnabled);
dict.SetMethod("isComponentBuild", &IsComponentBuild);
dict.SetMethod("isExtensionsEnabled", &IsExtensionsEnabled);
}
Expand Down
19 changes: 19 additions & 0 deletions spec/api-web-contents-spec.js
Expand Up @@ -1273,4 +1273,23 @@ describe('webContents module', () => {
expect(data).to.be.an.instanceof(Buffer).that.is.not.empty()
})
})

describe('PictureInPicture video', () => {
it('works as expected', (done) => {
w.destroy()
w = new BrowserWindow({
show: false,
webPreferences: {
sandbox: true
}
})
w.webContents.once('did-finish-load', async () => {
const result = await w.webContents.executeJavaScript(
`runTest(${features.isPictureInPictureEnabled()})`, true)
expect(result).to.be.true()
done()
})
w.loadFile(path.join(fixtures, 'api', 'picture-in-picture.html'))
})
})
})

0 comments on commit 9ccd6aa

Please sign in to comment.