Bug 691583 - Dispatch showfullscreenwarning chrome event when restricted key pressed in DOM full-screen mode. r=smaug
authorChris Pearce <chris@pearce.org.nz>
Tue, 01 Nov 2011 18:11:40 +1300
changeset 79500 e269b5ec522ab66f582525017579e2ad1ae78a9a
parent 79499 ddad75e027ab1e450db0af4aa83fa3a9bfabb122
child 79501 ad6054dd6e087f2f537afee1c78374999a167b48
push id21408
push userkhuey@mozilla.com
push dateTue, 01 Nov 2011 14:32:20 +0000
treeherdermozilla-central@cd9add22f090 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs691583
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 691583 - Dispatch showfullscreenwarning chrome event when restricted key pressed in DOM full-screen mode. r=smaug
content/html/content/test/file_fullscreen-api-keys.html
dom/tests/mochitest/chrome/Makefile.in
dom/tests/mochitest/chrome/dom_fullscreen_warning.xul
dom/tests/mochitest/chrome/test_dom_fullscreen_warning.xul
layout/base/nsPresShell.cpp
--- a/content/html/content/test/file_fullscreen-api-keys.html
+++ b/content/html/content/test/file_fullscreen-api-keys.html
@@ -16,202 +16,60 @@ Test that restricted key pressed drop do
   </style>
 </head>
 <body onload="document.body.mozRequestFullScreen();">
 
 <script type="application/javascript">
 
 /** Test for Bug 545812 **/
 
-// List of key codes, and whether they're restricted in full-screen mode.
+// List of key codes which should exit full-screen mode.
 var keyList = [
-  // Allowed: DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive
-  { code: "VK_CANCEL",        allowed: true},
-  { code: "VK_HELP",          allowed: true},
-  { code: "VK_BACK_SPACE",    allowed: true},
-  { code: "VK_TAB",           allowed: true},
-  { code: "VK_CLEAR",         allowed: true},
-  { code: "VK_RETURN",        allowed: true},
-  { code: "VK_ENTER",         allowed: true},
-  { code: "VK_SHIFT",         allowed: true},
-  { code: "VK_CONTROL",       allowed: true},
-  { code: "VK_ALT",           allowed: true},
-  { code: "VK_PAUSE",         allowed: true},
-  { code: "VK_CAPS_LOCK",     allowed: true},
-
-  { code: "VK_KANA",          allowed: false},
-  { code: "VK_HANGUL",        allowed: false},
-  { code: "VK_JUNJA",         allowed: false},
-  { code: "VK_FINAL",         allowed: false},
-  { code: "VK_HANJA",         allowed: false},
-  { code: "VK_KANJI",         allowed: false},
-  { code: "VK_ESCAPE",        allowed: false, suppressed: true},
-  { code: "VK_CONVERT",       allowed: false},
-  { code: "VK_NONCONVERT",    allowed: false},
-  { code: "VK_ACCEPT",        allowed: false},
-  { code: "VK_MODECHANGE",    allowed: false},
-
-  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
-  { code: "VK_SPACE",         allowed: true},
-  { code: "VK_PAGE_UP",       allowed: true},
-  { code: "VK_PAGE_DOWN",     allowed: true},
-  { code: "VK_END",           allowed: true},
-  { code: "VK_HOME",          allowed: true},
-  { code: "VK_LEFT",          allowed: true},
-  { code: "VK_UP",            allowed: true},
-  { code: "VK_RIGHT",         allowed: true},
-  { code: "VK_DOWN",          allowed: true},
-  { code: "VK_SELECT",        allowed: true},
-  { code: "VK_PRINT",         allowed: true},
-  { code: "VK_EXECUTE",       allowed: true},
-  { code: "VK_PRINTSCREEN",   allowed: true},
-  { code: "VK_INSERT",        allowed: true},
-  { code: "VK_DELETE",        allowed: true},
-
-  { code: "VK_0",             allowed: false},
-  { code: "VK_1",             allowed: false},
-  { code: "VK_2",             allowed: false},
-  { code: "VK_3",             allowed: false},
-  { code: "VK_4",             allowed: false},
-  { code: "VK_5",             allowed: false},
-  { code: "VK_6",             allowed: false},
-  { code: "VK_7",             allowed: false},
-  { code: "VK_8",             allowed: false},
-  { code: "VK_9",             allowed: false},
-
-  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
-  { code: "VK_SEMICOLON",     allowed: true},
-  { code: "VK_EQUALS",        allowed: true},
-
-  { code: "VK_A",             allowed: false},
-  { code: "VK_B",             allowed: false},
-  { code: "VK_C",             allowed: false},
-  { code: "VK_D",             allowed: false},
-  { code: "VK_E",             allowed: false},
-  { code: "VK_F",             allowed: false},
-  { code: "VK_G",             allowed: false},
-  { code: "VK_H",             allowed: false},
-  { code: "VK_I",             allowed: false},
-  { code: "VK_J",             allowed: false},
-  { code: "VK_K",             allowed: false},
-  { code: "VK_L",             allowed: false},
-  { code: "VK_M",             allowed: false},
-  { code: "VK_N",             allowed: false},
-  { code: "VK_O",             allowed: false},
-  { code: "VK_P",             allowed: false},
-  { code: "VK_Q",             allowed: false},
-  { code: "VK_R",             allowed: false},
-  { code: "VK_S",             allowed: false},
-  { code: "VK_T",             allowed: false},
-  { code: "VK_U",             allowed: false},
-  { code: "VK_V",             allowed: false},
-  { code: "VK_W",             allowed: false},
-  { code: "VK_X",             allowed: false},
-  { code: "VK_Y",             allowed: false},
-  { code: "VK_Z",             allowed: false},
-  { code: "VK_CONTEXT_MENU",  allowed: false},
-  { code: "VK_SLEEP",         allowed: false},
-  { code: "VK_NUMPAD0",       allowed: false},
-  { code: "VK_NUMPAD1",       allowed: false},
-  { code: "VK_NUMPAD2",       allowed: false},
-  { code: "VK_NUMPAD3",       allowed: false},
-  { code: "VK_NUMPAD4",       allowed: false},
-  { code: "VK_NUMPAD5",       allowed: false},
-  { code: "VK_NUMPAD6",       allowed: false},
-  { code: "VK_NUMPAD7",       allowed: false},
-  { code: "VK_NUMPAD8",       allowed: false},
-  { code: "VK_NUMPAD9",       allowed: false},
-
-  // Allowed: DOM_VK_MULTIPLY to DOM_VK_META, inclusive
-  { code: "VK_MULTIPLY",      allowed: true},
-  { code: "VK_ADD",           allowed: true},
-  { code: "VK_SEPARATOR",     allowed: true},
-  { code: "VK_SUBTRACT",      allowed: true},
-  { code: "VK_DECIMAL",       allowed: true},
-  { code: "VK_DIVIDE",        allowed: true},
-  { code: "VK_F1",            allowed: true},
-  { code: "VK_F2",            allowed: true},
-  { code: "VK_F3",            allowed: true},
-  { code: "VK_F4",            allowed: true},
-  { code: "VK_F5",            allowed: true},
-  { code: "VK_F6",            allowed: true},
-  { code: "VK_F7",            allowed: true},
-  { code: "VK_F8",            allowed: true},
-  { code: "VK_F9",            allowed: true},
-  { code: "VK_F10",           allowed: true},
-  { code: "VK_F11",           allowed: true},
-  { code: "VK_F12",           allowed: true},
-  { code: "VK_F13",           allowed: true},
-  { code: "VK_F14",           allowed: true},
-  { code: "VK_F15",           allowed: true},
-  { code: "VK_F16",           allowed: true},
-  { code: "VK_F17",           allowed: true},
-  { code: "VK_F18",           allowed: true},
-  { code: "VK_F19",           allowed: true},
-  { code: "VK_F20",           allowed: true},
-  { code: "VK_F21",           allowed: true},
-  { code: "VK_F22",           allowed: true},
-  { code: "VK_F23",           allowed: true},
-  { code: "VK_F24",           allowed: true},
-  { code: "VK_NUM_LOCK",      allowed: true},
-  { code: "VK_SCROLL_LOCK",   allowed: true},
-  { code: "VK_COMMA",         allowed: true},
-  { code: "VK_PERIOD",        allowed: true},
-  { code: "VK_SLASH",         allowed: true},
-  { code: "VK_BACK_QUOTE",    allowed: true},
-  { code: "VK_OPEN_BRACKET",  allowed: true},
-  { code: "VK_BACK_SLASH",    allowed: true},
-  { code: "VK_CLOSE_BRACKET", allowed: true},
-  { code: "VK_QUOTE",         allowed: true},
-  { code: "VK_META",          allowed: true},
+  { code: "VK_ESCAPE", suppressed: true},
+  { code: "VK_F11",    suppressed: false},
 ];
 
 function ok(condition, msg) {
   opener.ok(condition, msg);
 }
 
 function is(a, b, msg) {
   opener.is(a, b, msg);
 }
 
 var gKeyTestIndex = 0;
 var gKeyName;
 var gKeyCode;
-var gKeyAllowed;
 var gKeySuppressed;
 var gKeyReceived = false;
 
 function keyHandler(event) {
-  event.preventDefault();
   gKeyReceived = true;
 }
 
 function checkKeyEffect() {
-  is(gKeySuppressed, !gKeyReceived, "Should not receive suppressed key events");
-  is(document.mozFullScreen, gKeyAllowed,
-     (gKeyAllowed ? ("Should remain in full-screen mode for allowed key press " + gKeyName)
-                  : ("Should drop out of full-screen mode for restricted key press " + gKeyName)));
-
+  is(gKeySuppressed, !gKeyReceived, "Should not receive key events for " + gKeyName);
+  is(document.mozFullScreen, false, "Should exit full-screen mode for " + gKeyName + " press");
   if (gKeyTestIndex < keyList.length) {
     setTimeout(testNextKey, 0);
   } else {
     document.mozCancelFullScreen();
     opener.nextTest();
   }
 }
 
 function testTrustedKeyEvents() {
   document.body.focus();
   gKeyReceived = false;
   synthesizeKey(gKeyName, {});
   setTimeout(checkKeyEffect, 0);
 }
 
 function testScriptInitiatedKeyEvents() {
-  // Script initiated untrusted key events should not be blocked.
+  // Script initiated untrusted key events should not cause full-screen exit.
   document.body.focus();
   gKeyReceived = false;
   var evt = document.createEvent("KeyEvents");
   evt.initKeyEvent("keydown", true, true, window,
                    false, false, false, false,
                    gKeyCode, 0);
   document.body.dispatchEvent(evt);
 
@@ -235,19 +93,17 @@ function testScriptInitiatedKeyEvents() 
 function testNextKey() {
   if (!document.mozFullScreen) {
     document.body.mozRequestFullScreen();
   }
   ok(document.mozFullScreen, "Must be in full-screen mode");
 
   gKeyName = keyList[gKeyTestIndex].code;
   gKeyCode = KeyEvent["DOM_" + gKeyName];
-  gKeyAllowed = keyList[gKeyTestIndex].allowed;
-  gKeySuppressed = (keyList[gKeyTestIndex].suppressed != undefined) ?
-                    keyList[gKeyTestIndex].suppressed : false;
+  gKeySuppressed = keyList[gKeyTestIndex].suppressed;
   gKeyTestIndex++;
 
   testScriptInitiatedKeyEvents();
   testTrustedKeyEvents();
 }
 
 window.addEventListener("keydown", keyHandler, true);
 window.addEventListener("keyup", keyHandler, true);
--- a/dom/tests/mochitest/chrome/Makefile.in
+++ b/dom/tests/mochitest/chrome/Makefile.in
@@ -40,16 +40,18 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = dom/tests/mochitest/chrome
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
+		test_dom_fullscreen_warning.xul \
+		dom_fullscreen_warning.xul \
 		test_fullscreen.xul \
 		fullscreen.xul \
 		test_fullscreen_preventdefault.xul \
 		fullscreen_preventdefault.xul \
 		test_domstorage.xul \
 		domstorage_global.xul \
 		domstorage_global.js \
 		focus_window2.xul \
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/dom_fullscreen_warning.xul
@@ -0,0 +1,267 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+  Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
+-->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
+
+<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+<script type="application/javascript"><![CDATA[
+
+// List of key codes, and whether they should cause a warning in full-screen mode.
+var keyList = [
+  // Allowed: DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive
+  { code: "VK_CANCEL",        warn: false},
+  { code: "VK_HELP",          warn: false},
+  { code: "VK_BACK_SPACE",    warn: false},
+  { code: "VK_TAB",           warn: false},
+  { code: "VK_CLEAR",         warn: false},
+  { code: "VK_RETURN",        warn: false},
+  { code: "VK_ENTER",         warn: false},
+  { code: "VK_SHIFT",         warn: false},
+  { code: "VK_CONTROL",       warn: false},
+  { code: "VK_ALT",           warn: false},
+  { code: "VK_PAUSE",         warn: false},
+  { code: "VK_CAPS_LOCK",     warn: false},
+
+  { code: "VK_KANA",          warn: true},
+  { code: "VK_HANGUL",        warn: true},
+  { code: "VK_JUNJA",         warn: true},
+  { code: "VK_FINAL",         warn: true},
+  { code: "VK_HANJA",         warn: true},
+  { code: "VK_KANJI",         warn: true},
+  { code: "VK_ESCAPE",        warn: false, exit: true},
+  { code: "VK_CONVERT",       warn: true},
+  { code: "VK_NONCONVERT",    warn: true},
+  { code: "VK_ACCEPT",        warn: true},
+  { code: "VK_MODECHANGE",    warn: true},
+
+  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
+  { code: "VK_SPACE",         warn: false},
+  { code: "VK_PAGE_UP",       warn: false},
+  { code: "VK_PAGE_DOWN",     warn: false},
+  { code: "VK_END",           warn: false},
+  { code: "VK_HOME",          warn: false},
+  { code: "VK_LEFT",          warn: false},
+  { code: "VK_UP",            warn: false},
+  { code: "VK_RIGHT",         warn: false},
+  { code: "VK_DOWN",          warn: false},
+  { code: "VK_SELECT",        warn: false},
+  { code: "VK_PRINT",         warn: false},
+  { code: "VK_EXECUTE",       warn: false},
+  { code: "VK_PRINTSCREEN",   warn: false},
+  { code: "VK_INSERT",        warn: false},
+  { code: "VK_DELETE",        warn: false},
+
+  { code: "VK_0",             warn: true},
+  { code: "VK_1",             warn: true},
+  { code: "VK_2",             warn: true},
+  { code: "VK_3",             warn: true},
+  { code: "VK_4",             warn: true},
+  { code: "VK_5",             warn: true},
+  { code: "VK_6",             warn: true},
+  { code: "VK_7",             warn: true},
+  { code: "VK_8",             warn: true},
+  { code: "VK_9",             warn: true},
+
+  // Allowed: DOM_VK_SPACE to DOM_VK_DELETE, inclusive
+  { code: "VK_SEMICOLON",     warn: false},
+  { code: "VK_EQUALS",        warn: false},
+
+  { code: "VK_A",             warn: true},
+  { code: "VK_B",             warn: true},
+  { code: "VK_C",             warn: true},
+  { code: "VK_D",             warn: true},
+  { code: "VK_E",             warn: true},
+  { code: "VK_F",             warn: true},
+  { code: "VK_G",             warn: true},
+  { code: "VK_H",             warn: true},
+  { code: "VK_I",             warn: true},
+  { code: "VK_J",             warn: true},
+  { code: "VK_K",             warn: true},
+  { code: "VK_L",             warn: true},
+  { code: "VK_M",             warn: true},
+  { code: "VK_N",             warn: true},
+  { code: "VK_O",             warn: true},
+  { code: "VK_P",             warn: true},
+  { code: "VK_Q",             warn: true},
+  { code: "VK_R",             warn: true},
+  { code: "VK_S",             warn: true},
+  { code: "VK_T",             warn: true},
+  { code: "VK_U",             warn: true},
+  { code: "VK_V",             warn: true},
+  { code: "VK_W",             warn: true},
+  { code: "VK_X",             warn: true},
+  { code: "VK_Y",             warn: true},
+  { code: "VK_Z",             warn: true},
+  { code: "VK_CONTEXT_MENU",  warn: true},
+  { code: "VK_SLEEP",         warn: true},
+  { code: "VK_NUMPAD0",       warn: true},
+  { code: "VK_NUMPAD1",       warn: true},
+  { code: "VK_NUMPAD2",       warn: true},
+  { code: "VK_NUMPAD3",       warn: true},
+  { code: "VK_NUMPAD4",       warn: true},
+  { code: "VK_NUMPAD5",       warn: true},
+  { code: "VK_NUMPAD6",       warn: true},
+  { code: "VK_NUMPAD7",       warn: true},
+  { code: "VK_NUMPAD8",       warn: true},
+  { code: "VK_NUMPAD9",       warn: true},
+
+  // Allowed: DOM_VK_MULTIPLY to DOM_VK_META, inclusive
+  { code: "VK_MULTIPLY",      warn: false},
+  { code: "VK_ADD",           warn: false},
+  { code: "VK_SEPARATOR",     warn: false},
+  { code: "VK_SUBTRACT",      warn: false},
+  { code: "VK_DECIMAL",       warn: false},
+  { code: "VK_DIVIDE",        warn: false},
+  { code: "VK_F1",            warn: false},
+  { code: "VK_F2",            warn: false},
+  { code: "VK_F3",            warn: false},
+  { code: "VK_F4",            warn: false},
+  { code: "VK_F5",            warn: false},
+  { code: "VK_F6",            warn: false},
+  { code: "VK_F7",            warn: false},
+  { code: "VK_F8",            warn: false},
+  { code: "VK_F9",            warn: false},
+  { code: "VK_F10",           warn: false},
+  { code: "VK_F11",           warn: false}, // F11 exit full-screen handler is in browser.js, so won't cause exit here.
+  { code: "VK_F12",           warn: false},
+  { code: "VK_F13",           warn: false},
+  { code: "VK_F14",           warn: false},
+  { code: "VK_F15",           warn: false},
+  { code: "VK_F16",           warn: false},
+  { code: "VK_F17",           warn: false},
+  { code: "VK_F18",           warn: false},
+  { code: "VK_F19",           warn: false},
+  { code: "VK_F20",           warn: false},
+  { code: "VK_F21",           warn: false},
+  { code: "VK_F22",           warn: false},
+  { code: "VK_F23",           warn: false},
+  { code: "VK_F24",           warn: false},
+  { code: "VK_NUM_LOCK",      warn: false},
+  { code: "VK_SCROLL_LOCK",   warn: false},
+  { code: "VK_COMMA",         warn: false},
+  { code: "VK_PERIOD",        warn: false},
+  { code: "VK_SLASH",         warn: false},
+  { code: "VK_BACK_QUOTE",    warn: false},
+  { code: "VK_OPEN_BRACKET",  warn: false},
+  { code: "VK_BACK_SLASH",    warn: false},
+  { code: "VK_CLOSE_BRACKET", warn: false},
+  { code: "VK_QUOTE",         warn: false},
+  { code: "VK_META",          warn: false},
+];
+
+function ok(condition, msg) {
+  window.opener.wrappedJSObject.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  window.opener.wrappedJSObject.is(a, b, msg);
+}
+
+var gKeyTestIndex = 0;
+var gKeyName;
+var gKeyCode;
+var gWarningEventReceived = false;
+var gExpectWarning;
+var gExpectExit;
+var gBrowser;
+
+function checkKeyEffect() {
+  is(gBrowser.contentDocument.mozFullScreen, !gExpectExit,
+     (gExpectExit ? ("Should exit full-screen for " + gKeyName + " press ")
+                  : ("Should remain in full-screen for " + gKeyName + " press")));
+  is(gWarningEventReceived, gExpectWarning, "Should " + (gExpectWarning ? "" : "not ") +
+     "receive MozShowFullScreenWarning for " + gKeyName + " press");
+  if (gKeyTestIndex < keyList.length) {
+    setTimeout(startNextTest, 0);
+  } else {
+    gBrowser.contentDocument.mozCancelFullScreen();
+    window.opener.wrappedJSObject.done();
+  }
+}
+
+function testTrustedKeyEvents() {
+  gBrowser.contentWindow.focus();
+  gWarningEventReceived = false;
+  synthesizeKey(gKeyName, {});
+  setTimeout(checkKeyEffect, 0);
+}
+
+function testScriptInitiatedKeyEvents() {
+  // Script initiated untrusted key events should not cause the warning to show.
+  gBrowser.contentWindow.focus();
+  gWarningEventReceived = false;
+  var evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keydown", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+
+  evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keypress", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+
+  evt = gBrowser.contentDocument.createEvent("KeyEvents");
+  evt.initKeyEvent("keyup", true, true, window,
+                   false, false, false, false,
+                   gKeyCode, 0);
+  gBrowser.contentDocument.body.dispatchEvent(evt);
+  
+  setTimeout(checkScriptInitiatedEvents, 0);
+}
+
+function checkScriptInitiatedEvents() {
+  is(gWarningEventReceived, false, "Should not receive MozShowFullScreenWarning on synthesized key events.");
+  ok(gBrowser.contentDocument.mozFullScreen,
+     "Should remain in full-screen mode for script initiated key events for " + gKeyName);
+  testTrustedKeyEvents();
+}
+
+function testNextKey() {
+  ok(gBrowser.contentDocument.mozFullScreen, "Must be in full-screen mode");
+
+  gKeyName = keyList[gKeyTestIndex].code;
+  gKeyCode = KeyEvent["DOM_" + gKeyName];
+  gExpectWarning = keyList[gKeyTestIndex].warn;
+  gExpectExit = (keyList[gKeyTestIndex].exit != undefined) ?
+                 keyList[gKeyTestIndex].exit : false;
+  gKeyTestIndex++;
+
+  testScriptInitiatedKeyEvents();
+}
+
+function startNextTest() {
+  if (!gBrowser.contentDocument.mozFullScreen) {
+    gBrowser.contentDocument.body.mozRequestFullScreen();
+  }
+  // mozRequestFullScreen is async...
+  setTimeout(testNextKey, 0);
+}
+
+function keyHandler(event) {
+  event.preventDefault();
+}
+
+window.addEventListener("MozShowFullScreenWarning", function(){ gWarningEventReceived = true; }, true);
+
+window.addEventListener("keydown", keyHandler, true);
+window.addEventListener("keyup", keyHandler, true);
+window.addEventListener("keypress", keyHandler, true);
+
+function start() {
+  gBrowser = document.getElementById("browser");
+  gBrowser.contentDocument.body.mozRequestFullScreen();
+  setTimeout(startNextTest, 0);
+}
+
+]]>
+</script>
+
+<browser type="content" id="browser" width="400" height="400"/>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_dom_fullscreen_warning.xul
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<!--
+  Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
+  -->
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="400" height="400">
+
+  <script type="application/javascript" 
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
+
+<script>
+SimpleTest.waitForExplicitFinish();
+
+// Ensure the full-screen api is enabled, and will be disabled on test exit.
+var gPrevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
+SpecialPowers.setBoolPref("full-screen-api.enabled", true);
+
+var gPrevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
+SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
+
+
+newwindow = window.open("dom_fullscreen_warning.xul", "_blank","chrome,resizable=yes,width=400,height=400");
+
+function done()
+{
+  newwindow.close();
+  SpecialPowers.setBoolPref("full-screen-api.enabled", gPrevEnabled);
+  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", gPrevTrusted);
+  SimpleTest.finish();
+}
+
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
+
+</window>
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -197,16 +197,17 @@
 #include "imgIEncoder.h"
 #include "gfxPlatform.h"
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "Layers.h"
+#include "nsPLDOMEvent.h"
 
 #ifdef NS_FUNCTION_TIMER
 #define NS_TIME_FUNCTION_DECLARE_DOCURL                \
   nsCAutoString docURL__("N/A");                       \
   nsIURI *uri__ = mDocument->GetDocumentURI();         \
   if (uri__) uri__->GetSpec(docURL__);
 #define NS_TIME_FUNCTION_WITH_DOCURL                   \
   NS_TIME_FUNCTION_DECLARE_DOCURL                      \
@@ -6340,35 +6341,43 @@ PresShell::HandleEventInternal(nsEvent* 
     bool isHandlingUserInput = false;
 
     // XXX How about IME events and input events for plugins?
     if (NS_IS_TRUSTED_EVENT(aEvent)) {
       switch (aEvent->message) {
       case NS_KEY_PRESS:
       case NS_KEY_DOWN:
       case NS_KEY_UP: {
-        if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent) &&
-            aEvent->message == NS_KEY_UP) {
-          // We're in DOM full-screen mode, and a key with a restricted key
-          // code has been pressed. Exit full-screen mode.
-          NS_DispatchToCurrentThread(
-            NS_NewRunnableMethod(mCurrentEventContent->OwnerDoc(),
-                                 &nsIDocument::CancelFullScreen));
-        }
         nsIDocument *doc = mCurrentEventContent ?
                            mCurrentEventContent->OwnerDoc() : nsnull;
-        if (doc &&
-            doc->IsFullScreenDoc() &&
-            static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE) {
-          // Prevent default action on ESC key press when exiting
-          // DOM full-screen mode. This prevents the browser ESC key
-          // handler from stopping all loads in the document, which
-          // would cause <video> loads to stop.
-          aEvent->flags |= (NS_EVENT_FLAG_NO_DEFAULT |
-                            NS_EVENT_FLAG_ONLY_CHROME_DISPATCH);
+        if (doc &&
+            doc->IsFullScreenDoc() &&
+            static_cast<const nsKeyEvent*>(aEvent)->keyCode == NS_VK_ESCAPE) {
+          // Prevent default action on ESC key press when exiting
+          // DOM full-screen mode. This prevents the browser ESC key
+          // handler from stopping all loads in the document, which
+          // would cause <video> loads to stop.
+          aEvent->flags |= (NS_EVENT_FLAG_NO_DEFAULT |
+                            NS_EVENT_FLAG_ONLY_CHROME_DISPATCH);
+
+          if (aEvent->message == NS_KEY_UP) {
+           // ESC key released while in DOM full-screen mode.
+           // Exit full-screen mode.
+           NS_DispatchToCurrentThread(
+             NS_NewRunnableMethod(mCurrentEventContent->OwnerDoc(),
+                                  &nsIDocument::CancelFullScreen));
+          }
+        } else if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent)) {
+          // Restricted key press while in DOM full-screen mode. Dispatch
+          // an event to chrome so it knows to show a warning message
+          // informing the user how to exit full-screen.
+          nsRefPtr<nsPLDOMEvent> e =
+            new nsPLDOMEvent(doc, NS_LITERAL_STRING("MozShowFullScreenWarning"),
+                             true, true);
+          e->PostDOMEvent();
         }
         // Else not full-screen mode or key code is unrestricted, fall
         // through to normal handling.
       }
       case NS_MOUSE_BUTTON_DOWN:
       case NS_MOUSE_BUTTON_UP:
         isHandlingUserInput = true;
         break;