Commit 9c0b79c1 authored by Francois Beaufort's avatar Francois Beaufort Committed by Commit Bot

[PTZ] Setting pan, tilt, and zoom is allowed only if page is visible

This CL makes sure pan, tilt, and zoom can only be set when page is
visible.  When page is hidden, applyConstraints will reject with a
SecurityError for pan, tilt, and zoom only.

Spec: https://github.com/w3c/mediacapture-image/issues/236

Bug: 934063
Change-Id: I442985fabe7337093e336cfd804e405f4c965a12
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2302691Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Commit-Queue: François Beaufort <beaufort.francois@gmail.com>
Cr-Commit-Position: refs/heads/master@{#791211}
parent e2e073d4
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "media/base/media_switches.h"
namespace { namespace {
...@@ -563,3 +564,78 @@ IN_PROC_BROWSER_TEST_F(WebRtcPanTiltZoomCameraDevicesBrowserTest, ...@@ -563,3 +564,78 @@ IN_PROC_BROWSER_TEST_F(WebRtcPanTiltZoomCameraDevicesBrowserTest,
tab->GetMainFrame(), "getPanTiltZoomPermission();", &pan_tilt_zoom)); tab->GetMainFrame(), "getPanTiltZoomPermission();", &pan_tilt_zoom));
EXPECT_EQ(pan_tilt_zoom, "granted"); EXPECT_EQ(pan_tilt_zoom, "granted");
} }
class WebRtcPanTiltZoomFakeCameraDevicesBrowserTest : public WebRtcTestBase {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
}
void SetUpInProcessBrowserTestFixture() override {
DetectErrorsInJavaScript();
}
};
IN_PROC_BROWSER_TEST_F(WebRtcPanTiltZoomFakeCameraDevicesBrowserTest,
TestPageVisible) {
ASSERT_TRUE(embedded_test_server()->Start());
content::WebContents* tab = OpenTestPageInNewTab(kMainHtmlPage);
// Access PTZ camera.
std::string result;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(),
"runGetUserMedia({ video: { pan: true, tilt: true, zoom: true } });",
&result));
EXPECT_EQ(result, "runGetUserMedia-success");
// Hide page.
tab->WasHidden();
base::string16 expected_title = base::ASCIIToUTF16("hidden");
EXPECT_EQ(expected_title,
content::TitleWatcher(tab, expected_title).WaitAndGetTitle());
// Pan can't be set when page is hidden.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ pan: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-failure-SecurityError");
// Tilt can't be set when page is hidden.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ tilt: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-failure-SecurityError");
// Zoom can't be set when page is hidden.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ zoom: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-failure-SecurityError");
// Show page.
tab->WasShown();
expected_title = base::ASCIIToUTF16("visible");
EXPECT_EQ(expected_title,
content::TitleWatcher(tab, expected_title).WaitAndGetTitle());
// Pan can be set when page is shown again.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ pan: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-success");
// Tilt can be set when page is shown again.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ tilt: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-success");
// Zoom can be set when page is shown again.
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
tab->GetMainFrame(), "applyConstraints({ advanced: [{ zoom: 102 }] });",
&result));
EXPECT_EQ(result, "applyConstraints-success");
}
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
await videoTrack.applyConstraints(constraints); await videoTrack.applyConstraints(constraints);
returnToTest("applyConstraints-success"); returnToTest("applyConstraints-success");
} catch (error) { } catch (error) {
returnToTest("applyConstraints-failure"); returnToTest(`applyConstraints-failure-${error.name}`);
} }
} }
...@@ -90,6 +90,10 @@ ...@@ -90,6 +90,10 @@
function getPanTiltZoomPermission() { function getPanTiltZoomPermission() {
returnToTest(panTiltZoomPermissionStatus.state); returnToTest(panTiltZoomPermissionStatus.state);
} }
document.addEventListener('visibilitychange', () => {
document.title = document.visibilityState;
});
</script> </script>
</head> </head>
<body> <body>
......
...@@ -633,6 +633,11 @@ void ImageCapture::SetMediaTrackConstraints( ...@@ -633,6 +633,11 @@ void ImageCapture::SetMediaTrackConstraints(
settings->has_pan = constraints->hasPan() && constraints->pan().IsDouble(); settings->has_pan = constraints->hasPan() && constraints->pan().IsDouble();
if (settings->has_pan) { if (settings->has_pan) {
if (!IsPageVisible()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kSecurityError, "the page is not visible"));
return;
}
const auto pan = constraints->pan().GetAsDouble(); const auto pan = constraints->pan().GetAsDouble();
if (pan < capabilities_->pan()->min() || if (pan < capabilities_->pan()->min() ||
pan > capabilities_->pan()->max()) { pan > capabilities_->pan()->max()) {
...@@ -646,6 +651,11 @@ void ImageCapture::SetMediaTrackConstraints( ...@@ -646,6 +651,11 @@ void ImageCapture::SetMediaTrackConstraints(
settings->has_tilt = constraints->hasTilt() && constraints->tilt().IsDouble(); settings->has_tilt = constraints->hasTilt() && constraints->tilt().IsDouble();
if (settings->has_tilt) { if (settings->has_tilt) {
if (!IsPageVisible()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kSecurityError, "the page is not visible"));
return;
}
const auto tilt = constraints->tilt().GetAsDouble(); const auto tilt = constraints->tilt().GetAsDouble();
if (tilt < capabilities_->tilt()->min() || if (tilt < capabilities_->tilt()->min() ||
tilt > capabilities_->tilt()->max()) { tilt > capabilities_->tilt()->max()) {
...@@ -659,6 +669,11 @@ void ImageCapture::SetMediaTrackConstraints( ...@@ -659,6 +669,11 @@ void ImageCapture::SetMediaTrackConstraints(
settings->has_zoom = constraints->hasZoom() && constraints->zoom().IsDouble(); settings->has_zoom = constraints->hasZoom() && constraints->zoom().IsDouble();
if (settings->has_zoom) { if (settings->has_zoom) {
if (!IsPageVisible()) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kSecurityError, "the page is not visible"));
return;
}
const auto zoom = constraints->zoom().GetAsDouble(); const auto zoom = constraints->zoom().GetAsDouble();
if (zoom < capabilities_->zoom()->min() || if (zoom < capabilities_->zoom()->min() ||
zoom > capabilities_->zoom()->max()) { zoom > capabilities_->zoom()->max()) {
...@@ -1139,6 +1154,12 @@ void ImageCapture::ResolveWithPhotoCapabilities( ...@@ -1139,6 +1154,12 @@ void ImageCapture::ResolveWithPhotoCapabilities(
resolver->Resolve(photo_capabilities_); resolver->Resolve(photo_capabilities_);
} }
bool ImageCapture::IsPageVisible() {
LocalFrame* frame = GetFrame();
Document* doc = frame ? frame->GetDocument() : nullptr;
return doc ? doc->IsPageVisible() : false;
}
void ImageCapture::Trace(Visitor* visitor) const { void ImageCapture::Trace(Visitor* visitor) const {
visitor->Trace(stream_track_); visitor->Trace(stream_track_);
visitor->Trace(service_); visitor->Trace(service_);
......
...@@ -129,6 +129,9 @@ class MODULES_EXPORT ImageCapture final ...@@ -129,6 +129,9 @@ class MODULES_EXPORT ImageCapture final
void ResolveWithPhotoSettings(ScriptPromiseResolver*); void ResolveWithPhotoSettings(ScriptPromiseResolver*);
void ResolveWithPhotoCapabilities(ScriptPromiseResolver*); void ResolveWithPhotoCapabilities(ScriptPromiseResolver*);
// Returns true if page is visible. Otherwise returns false.
bool IsPageVisible();
Member<MediaStreamTrack> stream_track_; Member<MediaStreamTrack> stream_track_;
std::unique_ptr<ImageCaptureFrameGrabber> frame_grabber_; std::unique_ptr<ImageCaptureFrameGrabber> frame_grabber_;
HeapMojoRemote<media::mojom::blink::ImageCapture, HeapMojoRemote<media::mojom::blink::ImageCapture,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment