зеркало из https://github.com/electron/electron.git
feat: enable picture-in-picture mode for video tags (#17686)
* 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
This commit is contained in:
Родитель
46b6bcd99b
Коммит
9ccd6aa0dd
|
@ -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",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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()
|
||||
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<video id="video" controls playsinline
|
||||
src="data:video/webm;base64,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">
|
||||
</video>
|
||||
|
||||
<script>
|
||||
const togglePIP = async () => {
|
||||
if (video !== document.pictureInPictureElement)
|
||||
await video.requestPictureInPicture()
|
||||
else
|
||||
await document.exitPictureInPicture()
|
||||
}
|
||||
|
||||
window.runTest = (shouldBeEnabled) => new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
if (document.pictureInPictureEnabled) {
|
||||
if (!shouldBeEnabled) {
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
|
||||
let windowSizeOk = false
|
||||
video.addEventListener('enterpictureinpicture', (event) => {
|
||||
const pipWindow = event.pictureInPictureWindow
|
||||
if (pipWindow.width > 0 && pipWindow.height > 0) {
|
||||
windowSizeOk = true
|
||||
}
|
||||
})
|
||||
|
||||
video.addEventListener('leavepictureinpicture', (event) => {
|
||||
resolve(windowSizeOk)
|
||||
})
|
||||
|
||||
await togglePIP()
|
||||
setTimeout(async () => {
|
||||
await togglePIP()
|
||||
}, 500)
|
||||
} else {
|
||||
resolve(!shouldBeEnabled)
|
||||
}
|
||||
} catch (e) {
|
||||
resolve(false)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -10,6 +10,7 @@ declare namespace NodeJS {
|
|||
isViewApiEnabled(): boolean;
|
||||
isTtsEnabled(): boolean;
|
||||
isPrintingEnabled(): boolean;
|
||||
isPictureInPictureEnabled(): boolean;
|
||||
isExtensionsEnabled(): boolean;
|
||||
isComponentBuild(): boolean;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче