widget/tests/window_imestate_iframes.html

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 <html>
     2 <head>
     3   <title>Test for IME state controling and focus moving for iframes</title>
     4   <script type="text/javascript"
     5           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
     6   <link rel="stylesheet" type="text/css"
     7           href="chrome://mochikit/content/tests/SimpleTest/test.css" />
     8   <style type="text/css">
     9     iframe {
    10       border: none;
    11       height: 100px;
    12     }
    13   </style>
    14 </head>
    15 <body onunload="onUnload();">
    16 <p id="display">
    17   <!-- Use input[readonly] because it isn't affected by the partial focus
    18        movement on Mac -->
    19   <input id="prev" readonly><br>
    20   <iframe id="iframe_not_editable"
    21           src="data:text/html,&lt;html&gt;&lt;body&gt;&lt;input id='editor'&gt;&lt;/body&gt;&lt;/html&gt;"></iframe><br>
    23   <!-- Testing IME state and focus movement, the anchor elements cannot get focus -->
    24   <iframe id="iframe_html"
    25           src="data:text/html,&lt;html id='editor' contenteditable='true'&gt;&lt;body&gt;&lt;a href='about:blank'&gt;about:blank;&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;"></iframe><br>
    26   <iframe id="iframe_designMode"
    27           src="data:text/html,&lt;body id='editor' onload='document.designMode=&quot;on&quot;;'&gt;&lt;a href='about:blank'&gt;about:blank;&lt;/a&gt;&lt;/body&gt;"></iframe><br>
    28   <iframe id="iframe_body"
    29           src="data:text/html,&lt;body id='editor' contenteditable='true'&gt;&lt;a href='about:blank'&gt;about:blank;&lt;/a&gt;&lt;/body&gt;"></iframe><br>
    30   <iframe id="iframe_p"
    31           src="data:text/html,&lt;body&gt;&lt;p id='editor' contenteditable='true'&gt;&lt;a href='about:blank'&gt;about:blank;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;"></iframe><br>
    33   <input id="next" readonly><br>
    34 </p>
    35 <script class="testbody" type="application/javascript">
    37 window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTests, window);
    39 function ok(aCondition, aMessage)
    40 {
    41   window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
    42 }
    44 function is(aLeft, aRight, aMessage)
    45 {
    46   window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
    47 }
    49 function onUnload()
    50 {
    51   window.opener.wrappedJSObject.onFinish();
    52 }
    54 var gFocusObservingElement = null;
    55 var gBlurObservingElement = null;
    57 function onFocus(aEvent)
    58 {
    59   if (aEvent.target != gFocusObservingElement) {
    60     return;
    61   }
    62   ok(gFocusObservingElement.willFocus,
    63      "focus event is fired on unexpected element");
    64   gFocusObservingElement.willFocus = false;
    65 }
    67 function onBlur(aEvent)
    68 {
    69   if (aEvent.target != gBlurObservingElement) {
    70     return;
    71   }
    72   ok(gBlurObservingElement.willBlur,
    73      "blur event is fired on unexpected element");
    74   gBlurObservingElement.willBlur = false;
    75 }
    77 function observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
    78                           aNextBlurredNode, aWillFireBlurEvent)
    79 {
    80   if (gFocusObservingElement) {
    81     if (gFocusObservingElement.willFocus) {
    82       ok(false, "focus event was never fired on " + gFocusObservingElement);
    83     }
    84     gFocusObservingElement.removeEventListener("focus", onFocus, true);
    85     gFocusObservingElement.willFocus = NaN;
    86     gFocusObservingElement = null;
    87   }
    88   if (gBlurObservingElement) {
    89     if (gBlurObservingElement.willBlur) {
    90       ok(false, "blur event was never fired on " + gBlurObservingElement);
    91     }
    92     gBlurObservingElement.removeEventListener("blur", onBlur, true);
    93     gBlurObservingElement.willBlur = NaN;
    94     gBlurObservingElement = null;
    95   }
    96   if (aNextFocusedNode) {
    97     gFocusObservingElement = aNextFocusedNode;
    98     gFocusObservingElement.willFocus = aWillFireFocusEvent;
    99     gFocusObservingElement.addEventListener("focus", onFocus, true);
   100   }
   101   if (aNextBlurredNode) {
   102     gBlurObservingElement = aNextBlurredNode;
   103     gBlurObservingElement.willBlur = aWillFireBlurEvent;
   104     gBlurObservingElement.addEventListener("blur", onBlur, true);
   105   }
   106 }
   108 function runTests()
   109 {
   110   var utils =
   111     window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
   112           .getInterface(Components.interfaces.nsIDOMWindowUtils);
   113   var fm =
   114     Components.classes["@mozilla.org/focus-manager;1"]
   115               .getService(Components.interfaces.nsIFocusManager);
   117   var iframe, editor, root, input;
   118   var prev = document.getElementById("prev");
   119   var next = document.getElementById("next");
   120   var html = document.documentElement;
   122   function resetFocusToInput(aDescription)
   123   {
   124     observeFocusBlur(null, false, null, false);
   125     prev.focus();
   126     is(fm.focusedElement, prev,
   127        "input#prev[readonly] element didn't get focus: " + aDescription);
   128     is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
   129        "IME enabled on input#prev[readonly]: " + aDescription);
   130   }
   132   function resetFocusToParentHTML(aDescription)
   133   {
   134     observeFocusBlur(null, false, null, false);
   135     html.focus();
   136     is(fm.focusedElement, html,
   137        "Parent html element didn't get focus: " + aDescription);
   138     is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
   139        "IME enabled on parent html element: " + aDescription);
   140   }
   142   function testTabKey(aForward,
   143                       aNextFocusedNode, aWillFireFocusEvent,
   144                       aNextBlurredNode, aWillFireBlurEvent,
   145                       aIMEShouldBeEnabled, aTestingCaseDescription)
   146   {
   147     observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
   148                      aNextBlurredNode, aWillFireBlurEvent);
   149     synthesizeKey("VK_TAB", { shiftKey: !aForward });
   150     var description = "Tab key test: ";
   151     if (!aForward) {
   152       description = "Shift-" + description;
   153     }
   154     description += aTestingCaseDescription + ": ";
   155     is(fm.focusedElement, aNextFocusedNode,
   156        description + "didn't move focus as expected");
   157     is(utils.IMEStatus,
   158        aIMEShouldBeEnabled ?
   159          utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED,
   160        description + "didn't set IME state as expected");
   161   }
   163   function testMouseClick(aNextFocusedNode, aWillFireFocusEvent,
   164                           aWillAllNodeLostFocus,
   165                           aNextBlurredNode, aWillFireBlurEvent,
   166                           aIMEShouldBeEnabled, aTestingCaseDescription)
   167   {
   168     observeFocusBlur(aNextFocusedNode, aWillFireFocusEvent,
   169                      aNextBlurredNode, aWillFireBlurEvent);
   170     // We're relying on layout inside the iframe being up to date, so make it so
   171     iframe.contentDocument.documentElement.getBoundingClientRect();
   172     synthesizeMouse(iframe, 10, 80, { });
   173     var description = "Click test: " + aTestingCaseDescription + ": ";
   174     is(fm.focusedElement, !aWillAllNodeLostFocus ? aNextFocusedNode : null,
   175        description + "didn't move focus as expected");
   176     is(utils.IMEStatus,
   177        aIMEShouldBeEnabled ?
   178          utils.IME_STATUS_ENABLED : utils.IME_STATUS_DISABLED,
   179        description + "didn't set IME state as expected");
   180   }
   182   function testOnEditorFlagChange(aDescription, aIsInDesignMode)
   183   {
   184     const kReadonly =
   185       Components.interfaces.nsIPlaintextEditor.eEditorReadonlyMask;
   186     var description = "testOnEditorFlagChange: " + aDescription;
   187     resetFocusToParentHTML(description);
   188     var htmlEditor =
   189       iframe.contentWindow.
   190         QueryInterface(Components.interfaces.nsIInterfaceRequestor).
   191         getInterface(Components.interfaces.nsIWebNavigation).
   192         QueryInterface(Components.interfaces.nsIDocShell).editor;
   193     var e = aIsInDesignMode ? root : editor;
   194     e.focus();
   195     is(fm.focusedElement, e,
   196        description + ": focus() of editor didn't move focus as expected");
   197     is(utils.IMEStatus, utils.IME_STATUS_ENABLED,
   198        description + ": IME isn't enabled when the editor gets focus");
   199     var flags = htmlEditor.flags;
   200     htmlEditor.flags |= kReadonly;
   201     is(fm.focusedElement, e,
   202        description + ": when editor becomes readonly, focus moved unexpectedly");
   203     is(utils.IMEStatus, utils.IME_STATUS_DISABLED,
   204        description + ": when editor becomes readonly, IME is still enabled");
   205     htmlEditor.flags = flags;
   206     is(fm.focusedElement, e,
   207        description + ": when editor becomes read-write, focus moved unexpectedly");
   208     is(utils.IMEStatus, utils.IME_STATUS_ENABLED,
   209        description + ": when editor becomes read-write, IME is still disabled");
   210   }
   212   // hide all iframes
   213   document.getElementById("iframe_not_editable").style.display = "none";
   214   document.getElementById("iframe_html").style.display = "none";
   215   document.getElementById("iframe_designMode").style.display = "none";
   216   document.getElementById("iframe_body").style.display = "none";
   217   document.getElementById("iframe_p").style.display = "none";
   219   // non editable HTML element and input element can get focus.
   220   iframe = document.getElementById("iframe_not_editable");
   221   iframe.style.display = "inline";
   222   editor = iframe.contentDocument.getElementById("editor");
   223   root = iframe.contentDocument.documentElement;
   224   resetFocusToInput("initializing for iframe_not_editable");
   226   testTabKey(true, root, false, prev, true,
   227              false, "input#prev[readonly] -> html");
   228   testTabKey(true, editor, true, root, false,
   229              true, "html -> input in the subdoc");
   230   testTabKey(true, next, true, editor, true,
   231              false, "input in the subdoc -> input#next[readonly]");
   232   testTabKey(false, editor, true, next, true,
   233              true, "input#next[readonly] -> input in the subdoc");
   234   testTabKey(false, root, false, editor, true,
   235              false, "input in the subdoc -> html");
   236   testTabKey(false, prev, true, root, false,
   237              false, "html -> input#next[readonly]");
   239   iframe.style.display = "none";
   241   // HTML element (of course, it's root) must enables IME.
   242   iframe = document.getElementById("iframe_html");
   243   iframe.style.display = "inline";
   244   editor = iframe.contentDocument.getElementById("editor");
   245   root = iframe.contentDocument.documentElement;
   246   resetFocusToInput("initializing for iframe_html");
   248   testTabKey(true, editor, true, prev, true,
   249              true, "input#prev[readonly] -> html[contentediable=true]");
   250   testTabKey(true, next, true, editor, true,
   251              false, "html[contentediable=true] -> input#next[readonly]");
   252   testTabKey(false, editor, true, next, true,
   253              true, "input#next[readonly] -> html[contentediable=true]");
   254   testTabKey(false, prev, true, editor, true,
   255              false, "html[contenteditable=true] -> input[readonly]");
   257   prev.style.display = "none";
   258   resetFocusToParentHTML("testing iframe_html");
   259   testTabKey(true, editor, true, html, false,
   260              true, "html of parent -> html[contentediable=true]");
   261   testTabKey(false, html, false, editor, true,
   262              false, "html[contenteditable=true] -> html of parent");
   263   prev.style.display = "inline";
   264   resetFocusToInput("after parent html <-> html[contenteditable=true]");
   266   testMouseClick(editor, true, false, prev, true, true, "iframe_html");
   268   testOnEditorFlagChange("html[contentediable=true]", false);
   270   iframe.style.display = "none";
   272   // designMode should behave like <html contenteditable="true"></html>
   273   // but focus/blur events shouldn't be fired on its root element because
   274   // any elements shouldn't be focused state in designMode.
   275   iframe = document.getElementById("iframe_designMode");
   276   iframe.style.display = "inline";
   277   iframe.contentDocument.designMode = "on";
   278   editor = iframe.contentDocument.getElementById("editor");
   279   root = iframe.contentDocument.documentElement;
   280   resetFocusToInput("initializing for iframe_designMode");
   282   testTabKey(true, root, false, prev, true,
   283              true, "input#prev[readonly] -> html in designMode");
   284   testTabKey(true, next, true, root, false,
   285              false, "html in designMode -> input#next[readonly]");
   286   testTabKey(false, root, false, next, true,
   287              true, "input#next[readonly] -> html in designMode");
   288   testTabKey(false, prev, true, root, false,
   289              false, "html in designMode -> input#prev[readonly]");
   291   prev.style.display = "none";
   292   resetFocusToParentHTML("testing iframe_designMode");
   293   testTabKey(true, root, false, html, false,
   294              true, "html of parent -> html in designMode");
   295   testTabKey(false, html, false, root, false,
   296              false, "html in designMode -> html of parent");
   297   prev.style.display = "inline";
   298   resetFocusToInput("after parent html <-> html in designMode");
   300   testMouseClick(editor, false, true, prev, true, true, "iframe_designMode");
   302   testOnEditorFlagChange("html in designMode", true);
   304   iframe.style.display = "none";
   306   // When there is no HTML element but the BODY element is editable,
   307   // the body element should get focus and enables IME.
   308   iframe = document.getElementById("iframe_body");
   309   iframe.style.display = "inline";
   310   editor = iframe.contentDocument.getElementById("editor");
   311   root = iframe.contentDocument.documentElement;
   312   resetFocusToInput("initializing for iframe_body");
   314   testTabKey(true, editor, true, prev, true,
   315              true, "input#prev[readonly] -> body[contentediable=true]");
   316   testTabKey(true, next, true, editor, true,
   317              false, "body[contentediable=true] -> input#next[readonly]");
   318   testTabKey(false, editor, true, next, true,
   319              true, "input#next[readonly] -> body[contentediable=true]");
   320   testTabKey(false, prev, true, editor, true,
   321              false, "body[contenteditable=true] -> input#prev[readonly]");
   323   prev.style.display = "none";
   324   resetFocusToParentHTML("testing iframe_body");
   325   testTabKey(true, editor, true, html, false,
   326              true, "html of parent -> body[contentediable=true]");
   327   testTabKey(false, html, false, editor, true,
   328              false, "body[contenteditable=true] -> html of parent");
   329   prev.style.display = "inline";
   330   resetFocusToInput("after parent html <-> body[contenteditable=true]");
   332   testMouseClick(editor, true, false, prev, true, true, "iframe_body");
   334   testOnEditorFlagChange("body[contentediable=true]", false);
   336   iframe.style.display = "none";
   338   // When HTML/BODY elements are not editable, focus shouldn't be moved to
   339   // the editable content directly.
   340   iframe = document.getElementById("iframe_p");
   341   iframe.style.display = "inline";
   342   editor = iframe.contentDocument.getElementById("editor");
   343   root = iframe.contentDocument.documentElement;
   344   resetFocusToInput("initializing for iframe_p");
   346   testTabKey(true, root, false, prev, true,
   347              false, "input#prev[readonly] -> html (has p[contenteditable=true])");
   348   testTabKey(true, editor, true, root, false,
   349              true, "html (has p[contenteditable=true]) -> p[contentediable=true]");
   350   testTabKey(true, next, true, editor, true,
   351              false, "p[contentediable=true] -> input#next[readonly]");
   352   testTabKey(false, editor, true, next, true,
   353              true, "input#next[readonly] -> p[contentediable=true]");
   354   testTabKey(false, root, false, editor, true,
   355              false, "p[contenteditable=true] -> html (has p[contenteditable=true])");
   356   testTabKey(false, prev, true, root, false,
   357              false, "html (has p[contenteditable=true]) -> input#prev[readonly]");
   358   prev.style.display = "none";
   360   resetFocusToParentHTML("testing iframe_p");
   361   testTabKey(true, root, false, html, false,
   362              false, "html of parent -> html (has p[contentediable=true])");
   363   testTabKey(false, html, false, root, false,
   364              false, "html (has p[contentediable=true]) -> html of parent");
   365   prev.style.display = "inline";
   366   resetFocusToInput("after parent html <-> html (has p[contentediable=true])");
   368   testMouseClick(root, false, true, prev, true, false, "iframe_p");
   370   testOnEditorFlagChange("p[contenteditable=true]", false);
   372   iframe.style.display = "none";
   374   window.close();
   375 }
   377 </script>
   378 </body>
   380 </html>

mercurial