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:
Heilig Benedek 2019-08-22 12:17:50 +02:00 коммит произвёл Cheng Zhao
Родитель 46b6bcd99b
Коммит 9ccd6aa0dd
15 изменённых файлов: 318 добавлений и 0 удалений

Просмотреть файл

@ -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'))
})
})
})

51
spec/fixtures/api/picture-in-picture.html поставляемый Normal file
Просмотреть файл

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<video id="video" controls playsinline
src="data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAAMyRFNm3RAO027i1OrhBVJqWZTrIHlTbuMU6uEFlSua1OsggEjTbuMU6uEElTDZ1OsggFvTbuMU6uEHFO7a1Osggys7AEAAAAAAACbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAADIq17GDD0JATYCNTGF2ZjU4LjEyLjEwMFdBjUxhdmY1OC4xMi4xMDBEiYhAPgAAAAAAABZUrmsBAAAAAAAAQK4BAAAAAAAAN9eBAXPFgQGcgQAitZyDdW5khoVWX1ZQOYOBASPjg4QBycOA4AEAAAAAAAALsIIBQLqBtFPAgQESVMNnAQAAAAAAAMNzcwEAAAAAAAAuY8ABAAAAAAAAAGfIAQAAAAAAABpFo4dFTkNPREVSRIeNTGF2ZjU4LjEyLjEwMHNzAQAAAAAAAD1jwAEAAAAAAAAEY8WBAWfIAQAAAAAAACVFo4dFTkNPREVSRIeYTGF2YzU4LjE4LjEwMCBsaWJ2cHgtdnA5c3MBAAAAAAAAOmPAAQAAAAAAAARjxYEBZ8gBAAAAAAAAIkWjiERVUkFUSU9ORIeUMDA6MDA6MDAuMDMwMDAwMDAwAAAfQ7Z1AQAAAAAACmLngQCgAQAAAAAAClahSheBAAAAgkmDQgAT8As2CDgkHBhCAAQAf9XbuMH5fvm/i+5rRHpPb+Efp+N+b4n5uj/G/L2T8nKvTXsfadVX8+V+ndF1gb1oAuGvpb6zqyIjN7nV/1aAAHyLHsPgppNc0RLbJhL3vW2s/jbLQB2Pb3gX7CJ4AQX+CMM01Nu7snACs1K2c9mMK4UpMOJDxT/4PbogoqQBNG25mrCJu3MzMMQ/KKdX91dZsDoE5zCNOgTnMI06BOdkqc9ABGE2yZqifKVprEBmMx6o/wv10D88f9hPIKUx/s8W1bMk73iip28Gr0/aW7vz3X94O17N1Ns3jWIWo4ZEj5k8oyDL5ZTRC7r6F6aucW3ONszeTXDKmirs7OLlCA4bBRHh52HvvM6vqT9uCgNWxGPqxtX7ZteXzkwx9Nhw6raOH1qxhjiQ7t2u0X3skL5joquZb0mOJ9zb7x+1zqZdq/UztuOESRPHLUbtIm+TBKoB7ASpPQXJYFN+ZimhxHkhD8TflhyAOfWwTf8s1cZEGRW7q5VJk3WDRMzOfoakdB26vGuSuR7n1eFb9wvgP0J4w7L/1SGrvSZCCWVrZQv8ynqu8fVPxHUv2i5Qm6L9i9ZdRx7VkTxMPinYIo2GPqktSILhu3aqiu3nefLgeYKvG3sOQckyb+O9BfO0ixAs/ph/buTuu6tvfjJOhhICroW6x/pY0OEuDPfIKF+bXUe4SvWSPuS/5J2cSH0MwQK+BvUWTYdbT3lN7tWuws29IQNNn6Lh+5oRBum72p8rsX5hLXRx3GaK+jQg/xBpqhZzvGYkfUp20EPuQBEtNHcybhOmmXLtebOeEYeznMtVLR5ymOP3fMCT9Nw82QTsJep3h5ehwx+DB1bNFxuu6J5U9V+ehYQNpPOBzbhraogVYUv63YH0TqEnvQpVKSpJXjd1PYlrHhIlCEWHTNAqmH3qZFCIqSYyku/93k0M7WfApo6sHhhus4J909qX3BMdUwbkDaKyC91BDV+Nj97nivSg/3zA9F342n0BvYVAu5apGbha0Ol1dqiU7f0CgcwQxqX57NVudDpcSd7O1/yq/hcRHR9xnOH8mUU+z8+lkfuz8qsAWpNaoGlLY7iDH7nC9/5KwNk9Pc9P9deSxUj4nyk62vBF1bwCUmRdo9Znw1JTA6CeXdaOQgpAZDSxSNG8SolkeO/KtFSXLrQpz3EUMks/tjFKUDiFhnkt8AtVPuF/p0WMiTm7CviTcGssaTgmVjRO454i40k3MGTVSS8Y9PLvvYgLUPU6Or6wprf7EWG/GVBVSd6BnRYBds3zLShO1/jLBOiKQXLnDVlxmon044n+7tPnSdQclIOi7MewgBAXHmvJXkPWnlz6zzgXLjqnDgbQK+S7n5ILmuqMiinCQeSRfZl7xphKulRngCRJ395yztVilXQZOTkND7U8t4dJqeleGVHaOlwzTqdiFsr7WG1dljH7V5Z5E93TBPP+XGS/p3RpWJMSlNBS2e5FR4iBeVDerDvpBzZZxlH5zUJVZD7N7FUIHQW/RZgNA1Z4QGTdkdnIvxo6vtQHtRWj+hL7UxxK6PYfYU8jErM+QyIZHcn891thegOC65lSUS0nxHU4Yyz0fXOKQhm5mN5ce/hdeiDtNZHe0EWkHY31yEmkJWbKiqq5geg93VHwbjdGJDVsR8KDgX+/JUz8+kezDZR0Jvqt848qIyfQng6Pg3wteU2+qLJn9NmUUTm3ES6SAk5vwLkHZCQjJ5cA9E+0zejHoO9/bYOA1V5MM/vIVKYAhEqm64ENX4BiZe0JI6K/MZiTz7u5u6QcUB0bT7CA1RN0kFhCDONznvnXYVK514CyK0Hmhq7QmdSWsYOsdHpDqOkDnvd7yIhgJ4hFGLL6Gjj7CHAXlLHtfM02ZSUDT21O3Y0OkhrTjwHrYZn88uZ8ZiE2BJ//CqUFygfExWe3QQkMhimJz4vsB5yjHLcDJccWrF1XE2f8QIhJLSG1GtarGM6KnllhHJyaxNNjQMDzY6SpyAKtsWN7+x50E+nuDUUD6fzked8ckY2E+M2vJD9ii83BtcuKWz9K672EvW5bi8zCRbVmAdUjxCnKB/3hDvdf+tphpuAf6uAdLMl4ZmGYmci0bG3XgxKn8K4fcMX3an01kLOE2k4f7McITPHwoGJxhEyL2JI/uzPM3+dCvbfqCwxj201bHv/QUxWMOOkI4txk3iBiGKlDpKqZNT28JlEaUUj2U1GcRXubTfwauhcE8SWkrqqwCYTd3bySPE39v7q42nZgur8pSRRcwKGbCJvEyJyA+HprMs37sSgSAKkEh1R+RZC1ANFvdCrq7Flrju7sTmfM/2+RADQiE2yb1UJ0sSRrejZHEWkGa3eKQ+T1b3I+lnoYnNWh1vbIhkNdXmzQedn3t0W10KF3ofmCOMujPzDyh4I0taibapJvomvG327ndWGZUBe8Owwg9X5x+hUPYAIfSQXF+/+p1421ti9bLl9foKz5CmuZkMuG4aXe/cJhOOh2c/PyHWlh7pT5soNlLKOfC8/P4BQ4kszYOoAGgVg228z43mKGYCZBD2pLmyRGu7H+Qvpz2OBU3Y3iy2yWqUVfe+4huFwruzqezGemz2PpvIjRfKdOrXUWB3kXqScDb5lfthGDs1oz8ounFMyPB+7/QGbiVPBl2kHc53DTHtIaUwxHRTrHtbnFOgYkqFD98rVjdxapeRsqJ1+D+DnbWw2QLIwscVGN8XPRWIYMqWu/QDBBVWZhCtXBTkb6FzpEg2Z0SKzSZz7lPO53pGvHKw1tG1j1ZiTPYM0VBGq653VVMa9OvPKA6M0tj/kHZ6JbnTR+TEbW9kx1LGKS5uSEFY3+eUcZLoISWwUU0Lp60S1/npJ1nB3FR99O5jRmk+ap8Y/lRbqHv4rHtkZepBq0m3ppBPu3mBUTheEVD9d+A2JPYiMcgV1g+wQE447JSD2qqSIe9j1q01yxZXeLKO+K5MNNEsGHNibI6cawo8KXxaVWvKGxjfuKvgmC7YCIN8+nGXR/3dfFaZqGeIMxoEhAOH4SetsRgXeplq4RGFE1LyLX3sa9gd5A+3fT02/Qs0g1RgLLZUmRLxsOcBdyvKKXTTzXQ80bnbQjKC5V0IBSanXzTZ6434+cNR5WzbWFm1n1xXVwdtBYzlMhGjU4OUbRkIEH/7miIDNqJx5gc4lKwbUn7txTHthcFoUdYxisIMaCt/Nh+b9g3+lxhG96C4QtSyQTLZ87Dpw/wLIuWrcQGbQ+iGrtLzjrsZIlZFbC8EyqRtsRZG2ZYo3K7GnNSFBDYccinT/iz8QRhiPTTVHPiupktO2OESqJdOQ0QNx9p7PfP1mDt2HbO2eCl69eFjpu/sMmVxmldnGDjkjiZE4bZZeH7F3si9CERG/cOJh0RJ7zK4NhSnqdwQSsqCcAaBQpiFJDJJBvGe/cvtLE/luIiDw2cJT/oAB1oQEAAAAAAAAypgEAAAAAAAAp7oEBpaSCSYNCABPwCzYAOCQcGEIAAFBh9jAAAGcb2Rwndxam67fTRAAcU7trAQAAAAAAABG7j7OBALeK94EB8YICPvCBAw==">
</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>

1
typings/internal-ambient.d.ts поставляемый
Просмотреть файл

@ -10,6 +10,7 @@ declare namespace NodeJS {
isViewApiEnabled(): boolean;
isTtsEnabled(): boolean;
isPrintingEnabled(): boolean;
isPictureInPictureEnabled(): boolean;
isExtensionsEnabled(): boolean;
isComponentBuild(): boolean;
}