Navigaor.vrEnabled
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index ea4bb0d..5defc72 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -7355,6 +7355,99 @@
EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0)->child_at(0)));
}
+// Check that out-of-process frames correctly calculate their ability to enter
+// VR. A frame is allowed enter VR if the allowVR attribute is present in all of
+// its ancestor <iframe> elements. For OOPIF, when a parent frame changes this
+// attribute, the change is replicated to the child frame and its proxies.
+//
+// The test checks the following cases:
+//
+// 1. Static attribute (<iframe allowvr>)
+// 2. Attribute injected dynamically via JavaScript
+// 3. Multiple levels of nesting (A-embed-B-embed-C)
+// 4. Cross-site subframe navigation
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, AllowVR) {
+ // Load a page with a cross-site <iframe allowvr>.
+ GURL url_1(embedded_test_server()->GetURL(
+ "a.com", "/page_with_allowvr_frame.html"));
+ EXPECT_TRUE(NavigateToURL(shell(), url_1));
+
+ WebContentsImpl* contents = web_contents();
+ FrameTreeNode* root = contents->GetFrameTree()->root();
+
+ // Helper to check if a frame is allowed to go VR on the renderer
+ // side.
+ auto is_vr_allowed = [](FrameTreeNode* ftn) {
+ bool vr_allowed = false;
+ EXPECT_TRUE(ExecuteScriptAndExtractBool(
+ ftn,
+ "window.domAutomationController.send(navigator.vrEnabled)",
+ &vr_allowed));
+ return vr_allowed;
+ };
+
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_TRUE(is_vr_allowed(root->child_at(0)));
+ EXPECT_TRUE(root->child_at(0)->frame_owner_properties().allow_vr);
+
+ // Now navigate to a page with two <iframe>'s, both without allowvr.
+ GURL url_2(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
+ EXPECT_TRUE(NavigateToURL(shell(), url_2));
+ EXPECT_FALSE(root->child_at(0)->frame_owner_properties().allow_vr);
+ EXPECT_FALSE(root->child_at(1)->frame_owner_properties().allow_vr);
+
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(0)));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(1)));
+
+ // Dynamically enable VR for first subframe and check that the
+ // VR property was updated on the FrameTreeNode.
+ EXPECT_TRUE(ExecuteScript(
+ root, "document.getElementById('child-0').allowVR='true'"));
+ EXPECT_TRUE(root->child_at(0)->frame_owner_properties().allow_vr);
+
+ // Check that the first subframe is now allowed to go VR. Other
+ // frames shouldn't be affected.
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_TRUE(is_vr_allowed(root->child_at(0)));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(1)));
+
+ // Now navigate to a page with two levels of nesting.
+ GURL url_3(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
+ EXPECT_TRUE(NavigateToURL(shell(), url_3));
+
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(0)));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(0)->child_at(0)));
+
+ // Dynamically enable vr for bottom subframe.
+ EXPECT_TRUE(ExecuteScript(
+ root->child_at(0),
+ "document.getElementById('child-0').allowVR='true'"));
+
+ // This still shouldn't allow the bottom child to go VR, since the
+ // top frame hasn't allowed VR for the middle frame.
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(0)));
+ EXPECT_FALSE(is_vr_allowed(root->child_at(0)->child_at(0)));
+
+ // Now allow vr for the middle frame.
+ EXPECT_TRUE(ExecuteScript(
+ root, "document.getElementById('child-0').allowVR='true'"));
+
+ // All frames should be allowed to go VR now.
+ EXPECT_TRUE(is_vr_allowed(root));
+ EXPECT_TRUE(is_vr_allowed(root->child_at(0)));
+ EXPECT_TRUE(is_vr_allowed(root->child_at(0)->child_at(0)));
+
+ // Cross-site navigation should preserve the VR flags.
+ NavigateFrameToURL(root->child_at(0)->child_at(0),
+ embedded_test_server()->GetURL("d.com", "/title1.html"));
+ EXPECT_TRUE(is_vr_allowed(root->child_at(0)->child_at(0)));
+}
+
// Test for https://crbug.com/615575. It ensures that file chooser triggered
// by a document in an out-of-process subframe works properly.
IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, FileChooserInSubframe) {
diff --git a/content/test/data/page_with_allowvr_frame.html b/content/test/data/page_with_allowvr_frame.html
new file mode 100644
index 0000000..2a100e6
--- /dev/null
+++ b/content/test/data/page_with_allowvr_frame.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+ This page has one cross-site iframe with permission to enter VR.
+ <iframe id="child-0" src="/cross-site/b.com/title1.html" allowvr></iframe>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp b/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
index 203cfde..be6f067 100644
--- a/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
+++ b/third_party/WebKit/Source/modules/vr/NavigatorVR.cpp
@@ -98,6 +98,16 @@
return promise;
}
+bool NavigatorVR::vrEnabled(Navigator& navigator)
+{
+ return NavigatorVR::from(navigator).vrEnabled();
+}
+
+bool NavigatorVR::vrEnabled()
+{
+ return allowedToUseVR(m_frame);
+}
+
VRController* NavigatorVR::controller()
{
if (!frame())
diff --git a/third_party/WebKit/Source/modules/vr/NavigatorVR.h b/third_party/WebKit/Source/modules/vr/NavigatorVR.h
index 30d5f67..dd2c5f8 100644
--- a/third_party/WebKit/Source/modules/vr/NavigatorVR.h
+++ b/third_party/WebKit/Source/modules/vr/NavigatorVR.h
@@ -27,11 +27,15 @@
public:
static NavigatorVR* from(Document&);
static NavigatorVR& from(Navigator&);
+
virtual ~NavigatorVR();
static ScriptPromise getVRDisplays(ScriptState*, Navigator&);
ScriptPromise getVRDisplays(ScriptState*);
+ static bool vrEnabled(Navigator&);
+ bool vrEnabled();
+
VRController* controller();
Document* document();
diff --git a/third_party/WebKit/Source/modules/vr/NavigatorVR.idl b/third_party/WebKit/Source/modules/vr/NavigatorVR.idl
index 4e999ba..e6b2a77 100644
--- a/third_party/WebKit/Source/modules/vr/NavigatorVR.idl
+++ b/third_party/WebKit/Source/modules/vr/NavigatorVR.idl
@@ -7,4 +7,5 @@
RuntimeEnabled=WebVR,
] partial interface Navigator {
[CallWith=ScriptState] Promise getVRDisplays();
+ readonly attribute boolean vrEnabled;
};