Implementation for feature policy - fullscreen
Disable fullscreen API unless enabled through feature policy.

BUG=666761

Review-Url: https://codereview.chromium.org/2499373002
Cr-Commit-Position: refs/heads/master@{#436651}
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled-expected.txt
new file mode 100644
index 0000000..b3040c2a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS Fullscreen disabled on URL: resources/feature-policy-fullscreen.html with allowfullscreen = false 
+PASS Fullscreen disabled on URL: http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html with allowfullscreen = false 
+FAIL Fullscreen disabled on URL: resources/feature-policy-fullscreen.html with allowfullscreen = true assert_false: Document.fullscreenEnabled: expected false got true
+FAIL Fullscreen disabled on URL: http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html with allowfullscreen = true assert_false: Document.fullscreenEnabled: expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php
new file mode 100644
index 0000000..fade4c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-disabled.php
@@ -0,0 +1,43 @@
+<?php
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test ensures that fullscreen feature when disabled may not be called by
+// any iframe even when allowfullscreen is set.
+
+Header("Feature-Policy: {\"fullscreen\": []}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<iframe id="f1"></iframe>
+<iframe id="f2" allowfullscreen></iframe>
+<script>
+var srcs = [
+  "resources/feature-policy-fullscreen.html",
+  "http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html"
+];
+var f1 = document.getElementById('f1');
+var f2 = document.getElementById('f2');
+
+function loadFrames(iframe) {
+  for (var src of srcs) {
+    promise_test(function() {
+      iframe.src = src;
+      return new Promise(function(resolve, reject) {
+        window.addEventListener('message', function(e) {
+          resolve(e.data);
+        }, { once: true });
+      }).then(function(data) {
+        assert_false(data.enabled, 'Document.fullscreenEnabled:');
+        assert_equals(data.type, 'error', 'Document.requestFullscreen():');
+      });
+    }, 'Fullscreen disabled on URL: ' + src + ' with allowfullscreen = ' + iframe.allowFullscreen);
+  }
+}
+
+loadFrames(f1);
+loadFrames(f2);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php
new file mode 100644
index 0000000..18f970a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforall.php
@@ -0,0 +1,49 @@
+<?php
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test ensures that fullscreen feature when enabled for all works across
+// origins when allowfullscreen is set. No iframe may call it when
+// allowfullscreen is not set.
+
+Header("Feature-Policy: {\"fullscreen\": [\"*\"]}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<iframe id="f1"></iframe>
+<iframe id="f2" allowfullscreen></iframe>
+<script>
+var srcs = [
+  "resources/feature-policy-fullscreen.html",
+  "http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html"
+];
+var f1 = document.getElementById('f1');
+var f2 = document.getElementById('f2');
+
+function loadFrames(iframe) {
+  for (var src of srcs) {
+    promise_test(function(t) {
+      iframe.src = src;
+      return new Promise(function(resolve, reject) {
+        window.addEventListener('message', function(e) {
+          resolve(e.data);
+        }, { once: true });
+      }).then(function(data) {
+        if (iframe.id === "f2") {
+          assert_true(data.enabled, 'Document.fullscreenEnabled:');
+          assert_equals(data.type, 'change', 'Document.requestFullscreen():');
+        } else {
+          assert_false(data.enabled, 'Document.fullscreenEnabled:');
+          assert_equals(data.type, 'error', 'Document.requestFullscreen():');
+        }
+      });
+    }, 'Fullscreen enabled for all on URL: ' + src + ' with allowfullscreen = ' + iframe.allowFullscreen);
+  }
+}
+
+loadFrames(f1);
+loadFrames(f2);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php
new file mode 100644
index 0000000..42296132
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/fullscreen-enabledforself.php
@@ -0,0 +1,49 @@
+<?php
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test ensures that fullscreen feature when enabled for self only works
+// in the same orgin but not cross origins when allowfullscreen is set. No
+// iframe may call it when allowfullscreen is not set.
+
+Header("Feature-Policy: {\"fullscreen\": [\"self\"]}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<iframe id="f1"></iframe>
+<iframe id="f2" allowfullscreen></iframe>
+<script>
+var srcs = [
+  "resources/feature-policy-fullscreen.html",
+  "http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html"
+];
+var f1 = document.getElementById('f1');
+var f2 = document.getElementById('f2');
+
+function loadFrames(iframe) {
+  for (var src of srcs) {
+    promise_test(function(t) {
+      iframe.src = src;
+      return new Promise(function(resolve, reject) {
+        window.addEventListener('message', function(e) {
+          resolve(e.data);
+        }, { once: true });
+      }).then(function(data) {
+        if (src === srcs[0] || iframe.id === "f2") {
+          assert_true(data.enabled, 'Document.fullscreenEnabled:');
+          assert_equals(data.type, 'change', 'Document.requestFullscreen():');
+        } else {
+          assert_false(data.enabled, 'Document.fullscreenEnabled:');
+          assert_equals(data.type, 'error', 'Document.requestFullscreen():');
+        }
+      });
+    }, 'Fullscreen enabled for self on URL: ' + src + ' with allowfullscreen = ' + iframe.allowFullscreen);
+  }
+}
+
+loadFrames(f1);
+loadFrames(f2);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-fullscreen.html b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-fullscreen.html
new file mode 100644
index 0000000..1fe1b74
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-fullscreen.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Feature-Policy Fullscreen</title>
+<div>Fullscreen</div>
+<script>
+document.onwebkitfullscreenerror = function() {
+  parent.postMessage({ type: 'error', enabled: document.webkitFullscreenEnabled }, '*');
+};
+
+document.onwebkitfullscreenchange = function() {
+  document.webkitExitFullscreen();
+  parent.postMessage({ type: 'change', enabled: document.webkitFullscreenEnabled }, '*');
+};
+
+document.addEventListener('keypress', function() {
+  document.querySelector('div').webkitRequestFullscreen();
+});
+
+window.onload = function() {
+  focus();
+  eventSender.keyDown('a', []);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/fullscreen-disabled-expected.txt b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/fullscreen-disabled-expected.txt
new file mode 100644
index 0000000..ca7eb48
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/fullscreen-disabled-expected.txt
@@ -0,0 +1,11 @@
+CONSOLE WARNING: line 15: Fullscreen API is disabled by feature policy for this frame
+CONSOLE WARNING: line 6: Fullscreen API is disabled by feature policy for this frame
+CONSOLE WARNING: line 15: Fullscreen API is disabled by feature policy for this frame
+CONSOLE WARNING: line 6: Fullscreen API is disabled by feature policy for this frame
+This is a testharness.js-based test.
+PASS Fullscreen disabled on URL: resources/feature-policy-fullscreen.html with allowfullscreen = false 
+PASS Fullscreen disabled on URL: http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html with allowfullscreen = false 
+PASS Fullscreen disabled on URL: resources/feature-policy-fullscreen.html with allowfullscreen = true 
+PASS Fullscreen disabled on URL: http://localhost:8000/feature-policy/resources/feature-policy-fullscreen.html with allowfullscreen = true 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
index 5ff6e9a..c168a417 100644
--- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -29,6 +29,7 @@
 
 #include "core/dom/Fullscreen.h"
 
+#include "bindings/core/v8/ConditionalFeatures.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/dom/StyleEngine.h"
@@ -99,10 +100,43 @@
 }
 
 // https://fullscreen.spec.whatwg.org/#fullscreen-is-supported
-bool fullscreenIsSupported(const Document& document) {
+// TODO(lunalu): update the placement of the feature policy code once it is in
+// https://fullscreen.spec.whatwg.org/.
+bool fullscreenIsSupported(Document& document) {
+  LocalFrame* frame = document.frame();
+  if (!frame)
+    return false;
+
   // Fullscreen is supported if there is no previously-established user
   // preference, security risk, or platform limitation.
-  return !document.settings() || document.settings()->fullscreenSupported();
+  bool fullscreenSupported =
+      !document.settings() || document.settings()->fullscreenSupported();
+
+  if (!RuntimeEnabledFeatures::featurePolicyEnabled()) {
+    return fullscreenSupported;
+  }
+
+  // TODO(lunalu): clean all of this up once iframe attributes are supported
+  // for feature policy.
+  if (Frame* parent = frame->tree().parent()) {
+    // If FeaturePolicy is enabled, check the fullscreen is not disabled by
+    // policy in the parent frame.
+    if (fullscreenSupported &&
+        parent->securityContext()->getFeaturePolicy()->isFeatureEnabled(
+            kFullscreenFeature)) {
+      return true;
+    }
+  }
+  // Even if the iframe allowfullscreen attribute is not present, allow
+  // fullscreen to be enabled by feature policy.
+  else if (isFeatureEnabledInFrame(kFullscreenFeature, frame)) {
+    return true;
+  }
+
+  document.addConsoleMessage(ConsoleMessage::create(
+      JSMessageSource, WarningMessageLevel,
+      "Fullscreen API is disabled by feature policy for this frame"));
+  return false;
 }
 
 // https://fullscreen.spec.whatwg.org/#fullscreen-element-ready-check
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
index be49368..31b3967 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
@@ -36,6 +36,8 @@
     "domain", FeaturePolicy::FeatureDefault::EnableForAll};
 const FeaturePolicy::Feature kDocumentWrite{
     "docwrite", FeaturePolicy::FeatureDefault::EnableForAll};
+const FeaturePolicy::Feature kFullscreenFeature{
+    "fullscreen", FeaturePolicy::FeatureDefault::EnableForSelf};
 const FeaturePolicy::Feature kGeolocationFeature{
     "geolocation", FeaturePolicy::FeatureDefault::EnableForSelf};
 const FeaturePolicy::Feature kMidiFeature{
@@ -112,9 +114,9 @@
   DEFINE_STATIC_LOCAL(
       Vector<const FeaturePolicy::Feature*>, defaultFeatureList,
       ({&kDocumentCookie, &kDocumentDomain, &kDocumentWrite,
-        &kGeolocationFeature, &kMidiFeature, &kNotificationsFeature,
-        &kPaymentFeature, &kPushFeature, &kSyncScript, &kSyncXHR, &kUsermedia,
-        &kVibrateFeature, &kWebRTC}));
+        &kGeolocationFeature, &kFullscreenFeature, &kMidiFeature,
+        &kNotificationsFeature, &kPaymentFeature, &kPushFeature, &kSyncScript,
+        &kSyncXHR, &kUsermedia, &kVibrateFeature, &kWebRTC}));
   return defaultFeatureList;
 }
 
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
index 062d6e5..47b22e6b7 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
@@ -191,6 +191,7 @@
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kDocumentDomain;
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kDocumentWrite;
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kGeolocationFeature;
+extern const PLATFORM_EXPORT FeaturePolicy::Feature kFullscreenFeature;
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kMidiFeature;
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kNotificationsFeature;
 extern const PLATFORM_EXPORT FeaturePolicy::Feature kPaymentFeature;