widget/tests/window_composition_text_querycontent.xul

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 <?xml version="1.0"?>
     2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
     4                  type="text/css"?>
     5 <window title="Testing composition, text and query content events"
     6   xmlns:html="http://www.w3.org/1999/xhtml"
     7   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
     8   onunload="onunload();">
    10   <script type="application/javascript"
    11           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
    12   <script type="application/javascript"
    13           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
    14   <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
    16   <panel id="panel" hidden="true"
    17          orient="vertical"
    18          onpopupshown="onPanelShown(event);"
    19          onpopuphidden="onPanelHidden(event);">
    20     <vbox id="vbox">
    21       <textbox id="textbox" onfocus="onFocusPanelTextbox(event);"
    22                multiline="true" cols="20" rows="4"/>
    23     </vbox>
    24   </panel>
    26 <body  xmlns="http://www.w3.org/1999/xhtml">
    27 <p id="display">
    28 <div id="div" style="margin: 0; padding: 0; font-size: 24px;">Here is a text frame.</div>
    29 <textarea style="margin: 0;" id="textarea" cols="20" rows="4"></textarea><br/>
    30 <iframe id="iframe" width="300" height="150"
    31         src="data:text/html,&lt;textarea id='textarea' cols='20' rows='4'&gt;&lt;/textarea&gt;"></iframe><br/>
    32 <iframe id="iframe2" width="300" height="150"
    33         src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
    34 <iframe id="iframe3" width="300" height="150"
    35         src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
    36 <input id="input" type="text"/><br/>
    37 </p>
    38 <div id="content" style="display: none">
    40 </div>
    41 <pre id="test">
    42 </pre>
    43 </body>
    45 <script class="testbody" type="application/javascript">
    46 <![CDATA[
    48 window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
    50 function ok(aCondition, aMessage)
    51 {
    52   window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
    53 }
    55 function is(aLeft, aRight, aMessage)
    56 {
    57   window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
    58 }
    60 function isnot(aLeft, aRight, aMessage)
    61 {
    62   window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
    63 }
    65 function finish()
    66 {
    67   window.close();
    68 }
    70 function onunload()
    71 {
    72   window.opener.wrappedJSObject.SimpleTest.finish();
    73 }
    75 var div = document.getElementById("div");
    76 var textarea = document.getElementById("textarea");
    77 var panel = document.getElementById("panel");
    78 var textbox = document.getElementById("textbox");
    79 var iframe = document.getElementById("iframe");
    80 var iframe2 = document.getElementById("iframe2");
    81 var iframe3 = document.getElementById("iframe3");
    82 var input = document.getElementById("input");
    83 var textareaInFrame;
    85 const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
    86 const nsIEditorIMESupport = Components.interfaces.nsIEditorIMESupport;
    87 const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
    88 const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
    89 const nsIDocShell = Components.interfaces.nsIDocShell;
    91 function hitEventLoop(aFunc, aTimes)
    92 {
    93   if (--aTimes) {
    94     setTimeout(hitEventLoop, 0, aFunc, aTimes);
    95   } else {
    96     setTimeout(aFunc, 20);
    97   }
    98 }
   100 function getEditorIMESupport(aNode)
   101 {
   102   return aNode.QueryInterface(nsIDOMNSEditableElement).
   103                editor.
   104                QueryInterface(nsIEditorIMESupport);
   105 }
   107 function getHTMLEditorIMESupport(aWindow)
   108 {
   109   return aWindow.QueryInterface(nsIInterfaceRequestor).
   110                  getInterface(nsIWebNavigation).
   111                  QueryInterface(nsIDocShell).
   112                  editor;
   113 }
   115 const kIsWin = (navigator.platform.indexOf("Win") == 0);
   116 const kIsMac = (navigator.platform.indexOf("Mac") == 0);
   118 const kLFLen = kIsWin ? 2 : 1;
   120 function checkQueryContentResult(aResult, aMessage)
   121 {
   122   ok(aResult, aMessage + ": the result is null");
   123   if (!aResult) {
   124     return false;
   125   }
   126   ok(aResult.succeeded, aMessage + ": the query content failed");
   127   return aResult.succeeded;
   128 }
   130 function checkContent(aExpectedText, aMessage, aID)
   131 {
   132   var textContent = synthesizeQueryTextContent(0, 100);
   133   if (!checkQueryContentResult(textContent, aMessage +
   134                                ": synthesizeQueryTextContent " + aID)) {
   135     return false;
   136   }
   137   is(textContent.text, aExpectedText,
   138      aMessage + ": composition string is wrong" + aID);
   139   return textContent.text == aExpectedText;
   140 }
   142 function checkSelection(aExpectedOffset, aExpectedText, aMessage, aID)
   143 {
   144   var selectedText = synthesizeQuerySelectedText();
   145   if (!checkQueryContentResult(selectedText, aMessage +
   146                                ": synthesizeQuerySelectedText " + aID)) {
   147     return false;
   148   }
   149   is(selectedText.offset, aExpectedOffset,
   150      aMessage + ": selection offset is wrong" + aID);
   151   is(selectedText.text, aExpectedText,
   152      aMessage + ": selected text is wrong" + aID);
   153   return selectedText.offset == aExpectedOffset &&
   154          selectedText.text == aExpectedText;
   155 }
   157 function checkRect(aRect, aExpectedRect, aMessage)
   158 {
   159   is(aRect.left, aExpectedRect.left, aMessage + ": left is wrong");
   160   is(aRect.top, aExpectedRect.top, aMessage + " top is wrong");
   161   is(aRect.width, aExpectedRect.width, aMessage + ": width is wrong");
   162   is(aRect.height, aExpectedRect.height, aMessage + ": height is wrong");
   163   return aRect.left == aExpectedRect.left &&
   164          aRect.top == aExpectedRect.top &&
   165          aRect.width == aExpectedRect.width &&
   166          aRect.height == aExpectedRect.height;
   167 }
   169 function checkRectContainsRect(aRect, aContainer, aMessage)
   170 {
   171   var container = { left: Math.ceil(aContainer.left),
   172                     top:  Math.ceil(aContainer.top),
   173                     width: Math.floor(aContainer.width),
   174                     height: Math.floor(aContainer.height) };
   176   var ret = container.left <= aRect.left &&
   177             container.top <= aRect.top &&
   178             container.left + container.width >= aRect.left + aRect.width &&
   179             container.top + container.height >= aRect.top + aRect.height;
   180   ret = ret && aMessage;
   181   ok(ret, aMessage + " container={ left=" + container.left + ", top=" +
   182      container.top + ", width=" + container.width + ", height=" +
   183      container.height + " } rect={ left=" + aRect.left + ", top=" + aRect.top +
   184      ", width=" + aRect.width + ", height=" + aRect.height + " }");
   185   return ret;
   186 }
   188 function runUndoRedoTest()
   189 {
   190   textarea.value = "";
   191   textarea.focus();
   193   // start composition
   194   synthesizeComposition({ type: "compositionstart" });
   196   // input raw characters
   197   synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
   198   synthesizeText(
   199     { "composition":
   200       { "string": "\u306D",
   201         "clauses":
   202         [
   203           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   204         ]
   205       },
   206       "caret": { "start": 1, "length": 0 }
   207     });
   209   synthesizeComposition({ type: "compositionupdate", data: "\u306D\u3053" });
   210   synthesizeText(
   211     { "composition":
   212       { "string": "\u306D\u3053",
   213         "clauses":
   214         [
   215           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   216         ]
   217       },
   218       "caret": { "start": 2, "length": 0 }
   219     });
   221   // convert
   222   synthesizeComposition({ type: "compositionupdate", data: "\u732B" });
   223   synthesizeText(
   224     { "composition":
   225       { "string": "\u732B",
   226         "clauses":
   227         [
   228           { "length": 1,
   229             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   230         ]
   231       },
   232       "caret": { "start": 1, "length": 0 }
   233     });
   235   // commit
   236   synthesizeText(
   237     { "composition":
   238       { "string": "\u732B",
   239         "clauses":
   240         [
   241           { "length": 0, "attr": 0 }
   242         ]
   243       },
   244       "caret": { "start": 1, "length": 0 }
   245     });
   247   // end composition
   248   synthesizeComposition({ type: "compositionend", data: "\u732B" });
   250   // start composition
   251   synthesizeComposition({ type: "compositionstart" });
   253   // input raw characters
   254   synthesizeComposition({ type: "compositionupdate", data: "\u307E" });
   255   synthesizeText(
   256     { "composition":
   257       { "string": "\u307E",
   258         "clauses":
   259         [
   260           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   261         ]
   262       },
   263       "caret": { "start": 1, "length": 0 }
   264     });
   266   // cancel the composition
   267   synthesizeComposition({ type: "compositionupdate", data: "" });
   268   synthesizeText(
   269     { "composition":
   270       { "string": "",
   271         "clauses":
   272         [
   273           { "length": 0, "attr": 0 }
   274         ]
   275       },
   276       "caret": { "start": 0, "length": 0 }
   277     });
   279   // end composition
   280   synthesizeComposition({ type: "compositionend", data: "" });
   282   // start composition
   283   synthesizeComposition({ type: "compositionstart" });
   285   // input raw characters
   286   synthesizeComposition({ type: "compositionupdate", data: "\u3080" });
   287   synthesizeText(
   288     { "composition":
   289       { "string": "\u3080",
   290         "clauses":
   291         [
   292           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   293         ]
   294       },
   295       "caret": { "start": 1, "length": 0 }
   296     });
   298   synthesizeComposition({ type: "compositionupdate", data: "\u3080\u3059" });
   299   synthesizeText(
   300     { "composition":
   301       { "string": "\u3080\u3059",
   302         "clauses":
   303         [
   304           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   305         ]
   306       },
   307       "caret": { "start": 2, "length": 0 }
   308     });
   310   synthesizeComposition({ type: "compositionupdate",
   311                           data: "\u3080\u3059\u3081" });
   312   synthesizeText(
   313     { "composition":
   314       { "string": "\u3080\u3059\u3081",
   315         "clauses":
   316         [
   317           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   318         ]
   319       },
   320       "caret": { "start": 3, "length": 0 }
   321     });
   323   // convert
   324   synthesizeComposition({ type: "compositionupdate", data: "\u5A18" });
   325   synthesizeText(
   326     { "composition":
   327       { "string": "\u5A18",
   328         "clauses":
   329         [
   330           { "length": 1,
   331             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   332         ]
   333       },
   334       "caret": { "start": 1, "length": 0 }
   335     });
   337   // commit
   338   synthesizeText(
   339     { "composition":
   340       { "string": "\u5A18",
   341         "clauses":
   342         [
   343           { "length": 0, "attr": 0 }
   344         ]
   345       },
   346       "caret": { "start": 1, "length": 0 }
   347     });
   349   // end composition
   350   synthesizeComposition({ type: "compositionend", data: "\u5A18" });
   352   synthesizeKey(" ", {});
   353   synthesizeKey("m", {});
   354   synthesizeKey("e", {});
   355   synthesizeKey("a", {});
   356   synthesizeKey("n", {});
   357   synthesizeKey("t", {});
   358   synthesizeKey("VK_BACK_SPACE", {});
   359   synthesizeKey("s", {});
   360   synthesizeKey(" ", {});
   361   synthesizeKey("\"", {});
   362   synthesizeKey("c", {});
   363   synthesizeKey("a", {});
   364   synthesizeKey("t", {});
   365   synthesizeKey("-", {});
   366   synthesizeKey("g", {});
   367   synthesizeKey("i", {});
   368   synthesizeKey("r", {});
   369   synthesizeKey("l", {});
   370   synthesizeKey("\"", {});
   371   synthesizeKey(".", {});
   372   synthesizeKey(" ", {});
   373   synthesizeKey("VK_SHIFT", { type: "keydown" });
   374   synthesizeKey("S", { shiftKey: true });
   375   synthesizeKey("VK_SHIFT", { type: "keyup" });
   376   synthesizeKey("h", {});
   377   synthesizeKey("e", {});
   378   synthesizeKey(" ", {});
   379   synthesizeKey("i", {});
   380   synthesizeKey("s", {});
   381   synthesizeKey(" ", {});
   382   synthesizeKey("a", {});
   383   synthesizeKey(" ", {});
   385   // start composition
   386   synthesizeComposition({ type: "compositionstart" });
   388   // input raw characters
   389   synthesizeComposition({ type: "compositionupdate", data: "\u3088" });
   390   synthesizeText(
   391     { "composition":
   392       { "string": "\u3088",
   393         "clauses":
   394         [
   395           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   396         ]
   397       },
   398       "caret": { "start": 1, "length": 0 }
   399     });
   401   synthesizeComposition({ type: "compositionupdate", data: "\u3088\u3046" });
   402   synthesizeText(
   403     { "composition":
   404       { "string": "\u3088\u3046",
   405         "clauses":
   406         [
   407           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   408         ]
   409       },
   410       "caret": { "start": 2, "length": 0 }
   411     });
   413   synthesizeComposition({ type: "compositionupdate",
   414                           data: "\u3088\u3046\u304b" });
   415   synthesizeText(
   416     { "composition":
   417       { "string": "\u3088\u3046\u304b",
   418         "clauses":
   419         [
   420           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   421         ]
   422       },
   423       "caret": { "start": 3, "length": 0 }
   424     });
   426   synthesizeComposition({ type: "compositionupdate",
   427                           data: "\u3088\u3046\u304b\u3044" });
   428   synthesizeText(
   429     { "composition":
   430       { "string": "\u3088\u3046\u304b\u3044",
   431         "clauses":
   432         [
   433           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   434         ]
   435       },
   436       "caret": { "start": 4, "length": 0 }
   437     });
   439   // convert
   440   synthesizeComposition({ type: "compositionupdate", data: "\u5996\u602a" });
   441   synthesizeText(
   442     { "composition":
   443       { "string": "\u5996\u602a",
   444         "clauses":
   445         [
   446           { "length": 2, "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   447         ]
   448       },
   449       "caret": { "start": 2, "length": 0 }
   450     });
   452   // commit
   453   synthesizeText(
   454     { "composition":
   455       { "string": "\u5996\u602a",
   456         "clauses":
   457         [
   458           { "length": 0, "attr": 0 }
   459         ]
   460       },
   461       "caret": { "start": 2, "length": 0 }
   462     });
   464   // end composition
   465   synthesizeComposition({ type: "compositionend", data: "\u5996\u602a" });
   467   synthesizeKey("VK_BACK_SPACE", {});
   468   synthesizeKey("VK_BACK_SPACE", {});
   469   synthesizeKey("VK_BACK_SPACE", {});
   470   synthesizeKey("VK_BACK_SPACE", {});
   471   synthesizeKey("VK_BACK_SPACE", {});
   472   synthesizeKey("VK_BACK_SPACE", {});
   473   synthesizeKey("VK_BACK_SPACE", {});
   474   synthesizeKey("VK_BACK_SPACE", {});
   475   synthesizeKey("VK_BACK_SPACE", {});
   476   synthesizeKey("VK_BACK_SPACE", {});
   477   synthesizeKey("VK_BACK_SPACE", {});
   478   synthesizeKey("VK_BACK_SPACE", {});
   480   var i = 0;
   481   if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   482                     "runUndoRedoTest", "#" + ++i) ||
   483       !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   484     return;
   485   }
   487   synthesizeKey("Z", {accelKey: true});
   489   if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a \u5996\u602A",
   490                     "runUndoRedoTest", "#" + ++i) ||
   491       !checkSelection(32, "", "runUndoRedoTest", "#" + i)) {
   492     return;
   493   }
   495   synthesizeKey("Z", {accelKey: true});
   497   if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a ",
   498                     "runUndoRedoTest", "#" + ++i) ||
   499       !checkSelection(30, "", "runUndoRedoTest", "#" + i)) {
   500     return;
   501   }
   503   synthesizeKey("Z", {accelKey: true});
   505   if (!checkContent("\u732B\u5A18 mean",
   506                     "runUndoRedoTest", "#" + ++i) ||
   507       !checkSelection(7, "", "runUndoRedoTest", "#" + i)) {
   508     return;
   509   }
   511   synthesizeKey("Z", {accelKey: true});
   513   if (!checkContent("\u732B\u5A18 meant",
   514                     "runUndoRedoTest", "#" + ++i) ||
   515       !checkSelection(8, "", "runUndoRedoTest", "#" + i)) {
   516     return;
   517   }
   519   synthesizeKey("Z", {accelKey: true});
   521   if (!checkContent("\u732B\u5A18",
   522                     "runUndoRedoTest", "#" + ++i) ||
   523       !checkSelection(2, "", "runUndoRedoTest", "#" + i)) {
   524     return;
   525   }
   527   synthesizeKey("Z", {accelKey: true});
   529   if (!checkContent("\u732B",
   530                     "runUndoRedoTest", "#" + ++i) ||
   531       !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   532     return;
   533   }
   535   synthesizeKey("Z", {accelKey: true});
   537   // XXX this is unexpected behavior, see bug 258291
   538   if (!checkContent("\u732B",
   539                     "runUndoRedoTest", "#" + ++i) ||
   540       !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   541     return;
   542   }
   544   synthesizeKey("Z", {accelKey: true});
   546   if (!checkContent("",
   547                     "runUndoRedoTest", "#" + ++i) ||
   548       !checkSelection(0, "", "runUndoRedoTest", "#" + i)) {
   549     return;
   550   }
   552   synthesizeKey("Z", {accelKey: true});
   554   if (!checkContent("",
   555                     "runUndoRedoTest", "#" + ++i) ||
   556       !checkSelection(0, "", "runUndoRedoTest", "#" + i)) {
   557     return;
   558   }
   560   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   562   if (!checkContent("\u732B",
   563                     "runUndoRedoTest", "#" + ++i) ||
   564       !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   565     return;
   566   }
   568   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   570   // XXX this is unexpected behavior, see bug 258291
   571   if (!checkContent("\u732B",
   572                     "runUndoRedoTest", "#" + ++i) ||
   573       !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   574     return;
   575   }
   577   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   579   if (!checkContent("\u732B\u5A18",
   580                     "runUndoRedoTest", "#" + ++i) ||
   581       !checkSelection(2, "", "runUndoRedoTest", "#" + i)) {
   582     return;
   583   }
   585   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   587   if (!checkContent("\u732B\u5A18 meant",
   588                     "runUndoRedoTest", "#" + ++i) ||
   589       !checkSelection(8, "", "runUndoRedoTest", "#" + i)) {
   590     return;
   591   }
   593   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   595   if (!checkContent("\u732B\u5A18 mean",
   596                     "runUndoRedoTest", "#" + ++i) ||
   597       !checkSelection(7, "", "runUndoRedoTest", "#" + i)) {
   598     return;
   599   }
   601   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   603   if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a ",
   604                     "runUndoRedoTest", "#" + ++i) ||
   605       !checkSelection(30, "", "runUndoRedoTest", "#" + i)) {
   606     return;
   607   }
   609   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   611   if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a \u5996\u602A",
   612                     "runUndoRedoTest", "#" + ++i) ||
   613       !checkSelection(32, "", "runUndoRedoTest", "#" + i)) {
   614     return;
   615   }
   617   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   619   if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   620                     "runUndoRedoTest", "#" + ++i) ||
   621       !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   622     return;
   623   }
   625   synthesizeKey("Z", {accelKey: true, shiftKey: true});
   627   if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   628                     "runUndoRedoTest", "#" + ++i) ||
   629       !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   630     return;
   631   }
   632 }
   634 function runCompositionTest()
   635 {
   636   textarea.value = "";
   637   textarea.focus();
   638   var caretRects = [];
   640   var caretRect = synthesizeQueryCaretRect(0);
   641   if (!checkQueryContentResult(caretRect,
   642         "runCompositionTest: synthesizeQueryCaretRect #0")) {
   643     return false;
   644   }
   645   caretRects[0] = caretRect;
   647   // start composition
   648   synthesizeComposition({ type: "compositionstart" });
   650   // input first character
   651   synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
   652   synthesizeText(
   653     { "composition":
   654       { "string": "\u3089",
   655         "clauses":
   656         [
   657           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   658         ]
   659       },
   660       "caret": { "start": 1, "length": 0 }
   661     });
   663   if (!checkContent("\u3089", "runCompositionTest", "#1-1") ||
   664       !checkSelection(1, "", "runCompositionTest", "#1-1")) {
   665     return;
   666   }
   668   caretRect = synthesizeQueryCaretRect(1);
   669   if (!checkQueryContentResult(caretRect,
   670         "runCompositionTest: synthesizeQueryCaretRect #1-1")) {
   671     return false;
   672   }
   673   caretRects[1] = caretRect;
   675   // input second character
   676   synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
   677   synthesizeText(
   678     { "composition":
   679       { "string": "\u3089\u30FC",
   680         "clauses":
   681         [
   682           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   683         ]
   684       },
   685       "caret": { "start": 2, "length": 0 }
   686     });
   688   if (!checkContent("\u3089\u30FC", "runCompositionTest", "#1-2") ||
   689       !checkSelection(2, "", "runCompositionTest", "#1-2")) {
   690     return;
   691   }
   693   caretRect = synthesizeQueryCaretRect(2);
   694   if (!checkQueryContentResult(caretRect,
   695         "runCompositionTest: synthesizeQueryCaretRect #1-2")) {
   696     return false;
   697   }
   698   caretRects[2] = caretRect;
   700   isnot(caretRects[2].left, caretRects[1].left,
   701         "runCompositionTest: caret isn't moved (#1-2)");
   702   is(caretRects[2].top, caretRects[1].top,
   703      "runCompositionTest: caret is moved to another line (#1-2)");
   704   is(caretRects[2].width, caretRects[1].width,
   705      "runCompositionTest: caret width is wrong (#1-2)");
   706   is(caretRects[2].height, caretRects[1].height,
   707      "runCompositionTest: caret width is wrong (#1-2)");
   709   // input third character
   710   synthesizeComposition({ type: "compositionupdate",
   711                           data: "\u3089\u30FC\u3081" });
   712   synthesizeText(
   713     { "composition":
   714       { "string": "\u3089\u30FC\u3081",
   715         "clauses":
   716         [
   717           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   718         ]
   719       },
   720       "caret": { "start": 3, "length": 0 }
   721     });
   723   if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3") ||
   724       !checkSelection(3, "", "runCompositionTest", "#1-3")) {
   725     return;
   726   }
   728   caretRect = synthesizeQueryCaretRect(3);
   729   if (!checkQueryContentResult(caretRect,
   730         "runCompositionTest: synthesizeQueryCaretRect #1-3")) {
   731     return false;
   732   }
   733   caretRects[3] = caretRect;
   735   isnot(caretRects[3].left, caretRects[2].left,
   736         "runCompositionTest: caret isn't moved (#1-3)");
   737   is(caretRects[3].top, caretRects[2].top,
   738      "runCompositionTest: caret is moved to another line (#1-3)");
   739   is(caretRects[3].width, caretRects[2].width,
   740      "runCompositionTest: caret width is wrong (#1-3)");
   741   is(caretRects[3].height, caretRects[2].height,
   742      "runCompositionTest: caret height is wrong (#1-3)");
   744   // moves the caret left
   745   synthesizeText(
   746     { "composition":
   747       { "string": "\u3089\u30FC\u3081",
   748         "clauses":
   749         [
   750           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   751         ]
   752       },
   753       "caret": { "start": 2, "length": 0 }
   754     });
   756   if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-1") ||
   757       !checkSelection(2, "", "runCompositionTest", "#1-3-1")) {
   758     return;
   759   }
   762   caretRect = synthesizeQueryCaretRect(2);
   763   if (!checkQueryContentResult(caretRect,
   764         "runCompositionTest: synthesizeQueryCaretRect #1-3-1")) {
   765     return false;
   766   }
   768   is(caretRect.left, caretRects[2].left,
   769      "runCompositionTest: caret rects are different (#1-3-1, left)");
   770   is(caretRect.top, caretRects[2].top,
   771      "runCompositionTest: caret rects are different (#1-3-1, top)");
   772   // by bug 335359, the caret width depends on the right side's character.
   773   is(caretRect.width, caretRects[2].width + 1,
   774      "runCompositionTest: caret rects are different (#1-3-1, width)");
   775   is(caretRect.height, caretRects[2].height,
   776      "runCompositionTest: caret rects are different (#1-3-1, height)");
   778   // moves the caret left
   779   synthesizeText(
   780     { "composition":
   781       { "string": "\u3089\u30FC\u3081",
   782         "clauses":
   783         [
   784           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   785         ]
   786       },
   787       "caret": { "start": 1, "length": 0 }
   788     });
   790   if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-2") ||
   791       !checkSelection(1, "", "runCompositionTest", "#1-3-2")) {
   792     return;
   793   }
   796   caretRect = synthesizeQueryCaretRect(1);
   797   if (!checkQueryContentResult(caretRect,
   798         "runCompositionTest: synthesizeQueryCaretRect #1-3-2")) {
   799     return false;
   800   }
   802   is(caretRect.left, caretRects[1].left,
   803      "runCompositionTest: caret rects are different (#1-3-2, left)");
   804   is(caretRect.top, caretRects[1].top,
   805      "runCompositionTest: caret rects are different (#1-3-2, top)");
   806   // by bug 335359, the caret width depends on the right side's character.
   807   is(caretRect.width, caretRects[1].width + 1,
   808      "runCompositionTest: caret rects are different (#1-3-2, width)");
   809   is(caretRect.height, caretRects[1].height,
   810      "runCompositionTest: caret rects are different (#1-3-2, height)");
   812   synthesizeComposition({ type: "compositionupdate",
   813                           data: "\u3089\u30FC\u3081\u3093" });
   814   synthesizeText(
   815     { "composition":
   816       { "string": "\u3089\u30FC\u3081\u3093",
   817         "clauses":
   818         [
   819           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   820         ]
   821       },
   822       "caret": { "start": 4, "length": 0 }
   823     });
   825   if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-4") ||
   826       !checkSelection(4, "", "runCompositionTest", "#1-4")) {
   827     return;
   828   }
   831   // backspace
   832   synthesizeComposition({ type: "compositionupdate",
   833                           data: "\u3089\u30FC\u3081" });
   834   synthesizeText(
   835     { "composition":
   836       { "string": "\u3089\u30FC\u3081",
   837         "clauses":
   838         [
   839           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   840         ]
   841       },
   842       "caret": { "start": 3, "length": 0 }
   843     });
   845   if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-5") ||
   846       !checkSelection(3, "", "runCompositionTest", "#1-5")) {
   847     return;
   848   }
   850   // re-input
   851   synthesizeComposition({ type: "compositionupdate",
   852                           data: "\u3089\u30FC\u3081\u3093" });
   853   synthesizeText(
   854     { "composition":
   855       { "string": "\u3089\u30FC\u3081\u3093",
   856         "clauses":
   857         [
   858           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   859         ]
   860       },
   861       "caret": { "start": 4, "length": 0 }
   862     });
   864   if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-6") ||
   865       !checkSelection(4, "", "runCompositionTest", "#1-6")) {
   866     return;
   867   }
   869   synthesizeComposition({ type: "compositionupdate",
   870                           data: "\u3089\u30FC\u3081\u3093\u3055" });
   871   synthesizeText(
   872     { "composition":
   873       { "string": "\u3089\u30FC\u3081\u3093\u3055",
   874         "clauses":
   875         [
   876           { "length": 5, "attr": COMPOSITION_ATTR_RAWINPUT }
   877         ]
   878       },
   879       "caret": { "start": 5, "length": 0 }
   880     });
   882   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", "runCompositionTest", "#1-7") ||
   883       !checkSelection(5, "", "runCompositionTest", "#1-7")) {
   884     return;
   885   }
   887   synthesizeComposition({ type: "compositionupdate",
   888                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
   889   synthesizeText(
   890     { "composition":
   891       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
   892         "clauses":
   893         [
   894           { "length": 6, "attr": COMPOSITION_ATTR_RAWINPUT }
   895         ]
   896       },
   897       "caret": { "start": 6, "length": 0 }
   898     });
   900   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", "runCompositionTest", "#1-8") ||
   901       !checkSelection(6, "", "runCompositionTest", "#1-8")) {
   902     return;
   903   }
   905   synthesizeComposition({ type: "compositionupdate",
   906                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
   907   synthesizeText(
   908     { "composition":
   909       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
   910         "clauses":
   911         [
   912           { "length": 7, "attr": COMPOSITION_ATTR_RAWINPUT }
   913         ]
   914       },
   915       "caret": { "start": 7, "length": 0 }
   916     });
   918   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053", "runCompositionTest", "#1-8") ||
   919       !checkSelection(7, "", "runCompositionTest", "#1-8")) {
   920     return;
   921   }
   923   synthesizeComposition({ type: "compositionupdate",
   924                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
   925   synthesizeText(
   926     { "composition":
   927       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
   928         "clauses":
   929         [
   930           { "length": 8, "attr": COMPOSITION_ATTR_RAWINPUT }
   931         ]
   932       },
   933       "caret": { "start": 8, "length": 0 }
   934     });
   936   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
   937                     "runCompositionTest", "#1-9") ||
   938       !checkSelection(8, "", "runCompositionTest", "#1-9")) {
   939     return;
   940   }
   942   // convert
   943   synthesizeComposition({ type: "compositionupdate",
   944                           data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
   945   synthesizeText(
   946     { "composition":
   947       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   948         "clauses":
   949         [
   950           { "length": 4,
   951             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
   952           { "length": 2,
   953             "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
   954         ]
   955       },
   956       "caret": { "start": 4, "length": 0 }
   957     });
   959   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   960                     "runCompositionTest", "#1-10") ||
   961       !checkSelection(4, "", "runCompositionTest", "#1-10")) {
   962     return;
   963   }
   965   // change the selected clause
   966   synthesizeText(
   967     { "composition":
   968       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   969         "clauses":
   970         [
   971           { "length": 4,
   972             "attr": COMPOSITION_ATTR_CONVERTEDTEXT },
   973           { "length": 2,
   974             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   975         ]
   976       },
   977       "caret": { "start": 6, "length": 0 }
   978     });
   980   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   981                     "runCompositionTest", "#1-11") ||
   982       !checkSelection(6, "", "runCompositionTest", "#1-11")) {
   983     return;
   984   }
   986   // reset clauses
   987   synthesizeComposition({ type: "compositionupdate",
   988                           data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
   989   synthesizeText(
   990     { "composition":
   991       { "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
   992         "clauses":
   993         [
   994           { "length": 5,
   995             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
   996           { "length": 3,
   997             "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
   998         ]
   999       },
  1000       "caret": { "start": 5, "length": 0 }
  1001     });
  1003   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1004                     "runCompositionTest", "#1-12") ||
  1005       !checkSelection(5, "", "runCompositionTest", "#1-12")) {
  1006     return;
  1010   var textRect1 = synthesizeQueryTextRect(0, 1);
  1011   var textRect2 = synthesizeQueryTextRect(1, 1);
  1012   if (!checkQueryContentResult(textRect1,
  1013         "runCompositionTest: synthesizeQueryTextRect #1-12-1") ||
  1014       !checkQueryContentResult(textRect2,
  1015         "runCompositionTest: synthesizeQueryTextRect #1-12-2")) {
  1016     return false;
  1019   // commit the composition string
  1020   synthesizeText(
  1021     { "composition":
  1022       { "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1023         "clauses":
  1025           { "length": 0, "attr": 0 }
  1027       },
  1028       "caret": { "start": 8, "length": 0 }
  1029     });
  1031   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1032                     "runCompositionTest", "#1-13") ||
  1033       !checkSelection(8, "", "runCompositionTest", "#1-13")) {
  1034     return;
  1037   synthesizeComposition({ type: "compositionend",
  1038                           data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
  1040   var textRect3 = synthesizeQueryTextRect(0, 1);
  1041   var textRect4 = synthesizeQueryTextRect(1, 1);
  1043   if (!checkQueryContentResult(textRect3,
  1044         "runCompositionTest: synthesizeQueryTextRect #1-13-1") ||
  1045       !checkQueryContentResult(textRect4,
  1046         "runCompositionTest: synthesizeQueryTextRect #1-13-2")) {
  1047     return false;
  1050   checkRect(textRect3, textRect1, "runCompositionTest: textRect #1-13-1");
  1051   checkRect(textRect4, textRect2, "runCompositionTest: textRect #1-13-2");
  1053   // restart composition
  1054   synthesizeComposition({ type: "compositionstart" });
  1056   // input characters
  1057   synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
  1058   synthesizeText(
  1059     { "composition":
  1060       { "string": "\u3057",
  1061         "clauses":
  1063           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1065       },
  1066       "caret": { "start": 1, "length": 0 }
  1067     });
  1069   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3057",
  1070                     "runCompositionTest", "#2-1") ||
  1071       !checkSelection(8 + 1, "", "runCompositionTest", "#2-1")) {
  1072     return;
  1075   synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
  1076   synthesizeText(
  1077     { "composition":
  1078       { "string": "\u3058",
  1079         "clauses":
  1081           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1083       },
  1084       "caret": { "start": 1, "length": 0 }
  1085     });
  1087   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058",
  1088                     "runCompositionTest", "#2-2") ||
  1089       !checkSelection(8 + 1, "", "runCompositionTest", "#2-2")) {
  1090     return;
  1093   synthesizeComposition({ type: "compositionupdate", data: "\u3058\u3087" });
  1094   synthesizeText(
  1095     { "composition":
  1096       { "string": "\u3058\u3087",
  1097         "clauses":
  1099           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  1101       },
  1102       "caret": { "start": 2, "length": 0 }
  1103     });
  1105   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087",
  1106                     "runCompositionTest", "#2-3") ||
  1107       !checkSelection(8 + 2, "", "runCompositionTest", "#2-3")) {
  1108     return;
  1111   synthesizeComposition({ type: "compositionupdate",
  1112                           data: "\u3058\u3087\u3046" });
  1113   synthesizeText(
  1114     { "composition":
  1115       { "string": "\u3058\u3087\u3046",
  1116         "clauses":
  1118           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  1120       },
  1121       "caret": { "start": 3, "length": 0 }
  1122     });
  1124   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
  1125                     "runCompositionTest", "#2-4") ||
  1126       !checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
  1127     return;
  1130   // commit the composition string
  1131   synthesizeText(
  1132     { "composition":
  1133       { "string": "\u3058\u3087\u3046",
  1134         "clauses":
  1136           { "length": 0, "attr": 0 }
  1138       },
  1139       "caret": { "start": 3, "length": 0 }
  1140     });
  1142   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
  1143                     "runCompositionTest", "#2-4") ||
  1144       !checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
  1145     return;
  1148   synthesizeComposition({ type: "compositionend", data: "\u3058\u3087\u3046" });
  1150   // set selection
  1151   var selectionSetTest = synthesizeSelectionSet(4, 7, false);
  1152   ok(selectionSetTest, "runCompositionTest: selectionSetTest failed");
  1154   if (!checkSelection(4, "\u3055\u884C\u3053\u3046\u3058\u3087\u3046", "runCompositionTest", "#3-1")) {
  1155     return;
  1158   // start composition with selection
  1159   synthesizeComposition({ type: "compositionstart" });
  1161   synthesizeComposition({ type: "compositionupdate", data: "\u304A" });
  1162   synthesizeText(
  1163     { "composition":
  1164       { "string": "\u304A",
  1165         "clauses":
  1167           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1169       },
  1170       "caret": { "start": 1, "length": 0 }
  1171     });
  1173   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u304A",
  1174                     "runCompositionTest", "#3-2") ||
  1175       !checkSelection(4 + 1, "", "runCompositionTest", "#3-2")) {
  1176     return;
  1179   // remove the composition string
  1180   synthesizeComposition({ type: "compositionupdate", data: "" });
  1181   synthesizeText(
  1182     { "composition":
  1183       { "string": "",
  1184         "clauses":
  1186           { "length": 0, "attr": 0 }
  1188       },
  1189       "caret": { "start": 0, "length": 0 }
  1190     });
  1192   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1193                     "runCompositionTest", "#3-3") ||
  1194       !checkSelection(4, "", "runCompositionTest", "#3-3")) {
  1195     return;
  1198   // re-input the composition string
  1199   synthesizeComposition({ type: "compositionupdate", data: "\u3046" });
  1200   synthesizeText(
  1201     { "composition":
  1202       { "string": "\u3046",
  1203         "clauses":
  1205           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1207       },
  1208       "caret": { "start": 1, "length": 0 }
  1209     });
  1211   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3046",
  1212                     "runCompositionTest", "#3-4") ||
  1213       !checkSelection(4 + 1, "", "runCompositionTest", "#3-4")) {
  1214     return;
  1217   // cancel the composition
  1218   synthesizeComposition({ type: "compositionupdate", data: "" });
  1219   synthesizeText(
  1220     { "composition":
  1221       { "string": "",
  1222         "clauses":
  1224           { "length": 0, "attr": 0 }
  1226       },
  1227       "caret": { "start": 0, "length": 0 }
  1228     });
  1230   synthesizeComposition({ type: "compositionend", data: "" });
  1232   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1233                     "runCompositionTest", "#3-5") ||
  1234       !checkSelection(4, "", "runCompositionTest", "#3-5")) {
  1235     return;
  1238   // bug 271815, some Chinese IMEs for Linux make empty composition string
  1239   // and compty clause information when it lists up Chinese characters on
  1240   // its candidate window.
  1241   synthesizeComposition({ type: "compositionstart" });
  1243   synthesizeText(
  1244     { "composition":
  1245       { "string": "",
  1246         "clauses":
  1248           { "length": 0, "attr": 0 }
  1250       },
  1251       "caret": { "start": 0, "length": 0 }
  1252     });
  1254   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1255                     "runCompositionTest", "#4-1") ||
  1256       !checkSelection(4, "", "runCompositionTest", "#4-1")) {
  1257     return;
  1260   synthesizeText(
  1261     { "composition":
  1262       { "string": "",
  1263         "clauses":
  1265           { "length": 0, "attr": 0 }
  1267       },
  1268       "caret": { "start": 0, "length": 0 }
  1269     });
  1271   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1272                     "runCompositionTest", "#4-2") ||
  1273       !checkSelection(4, "", "runCompositionTest", "#4-2")) {
  1274     return;
  1277   synthesizeComposition({ type: "compositionupdate", data: "\u6700" });
  1278   synthesizeText(
  1279     { "composition":
  1280       { "string": "\u6700",
  1281         "clauses":
  1283           { "length": 0, "attr": 0 }
  1285       },
  1286       "caret": { "start": 1, "length": 0 }
  1287     });
  1289   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1290                     "runCompositionTest", "#4-3") ||
  1291       !checkSelection(5, "", "runCompositionTest", "#4-3")) {
  1292     return;
  1295   synthesizeComposition({ type: "compositionend", data: "\u6700" });
  1297   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1298                     "runCompositionTest", "#4-4") ||
  1299       !checkSelection(5, "", "runCompositionTest", "#4-4")) {
  1300     return;
  1303   // testing the canceling case
  1304   synthesizeComposition({ type: "compositionstart" });
  1306   synthesizeText(
  1307     { "composition":
  1308       { "string": "",
  1309         "clauses":
  1311           { "length": 0, "attr": 0 }
  1313       },
  1314       "caret": { "start": 0, "length": 0 }
  1315     });
  1317   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1318                     "runCompositionTest", "#4-5") ||
  1319       !checkSelection(5, "", "runCompositionTest", "#4-5")) {
  1320     return;
  1323   synthesizeText(
  1324     { "composition":
  1325       { "string": "",
  1326         "clauses":
  1328           { "length": 0, "attr": 0 }
  1330       },
  1331       "caret": { "start": 0, "length": 0 }
  1332     });
  1334   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1335                     "runCompositionTest", "#4-6") ||
  1336       !checkSelection(5, "", "runCompositionTest", "#4-6")) {
  1337     return;
  1340   synthesizeComposition({ type: "compositionend", data: "\u6700" });
  1342   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1343                     "runCompositionTest", "#4-7") ||
  1344       !checkSelection(5, "", "runCompositionTest", "#4-7")) {
  1345     return;
  1348   // testing whether the empty composition string deletes selected string.
  1349   synthesizeKey("VK_LEFT", { shiftKey: true });
  1351   synthesizeComposition({ type: "compositionstart" });
  1353   synthesizeText(
  1354     { "composition":
  1355       { "string": "",
  1356         "clauses":
  1358           { "length": 0, "attr": 0 }
  1360       },
  1361       "caret": { "start": 0, "length": 0 }
  1362     });
  1364   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1365                     "runCompositionTest", "#4-8") ||
  1366       !checkSelection(4, "", "runCompositionTest", "#4-8")) {
  1367     return;
  1370   synthesizeComposition({ type: "compositionupdate", data: "\u9AD8" });
  1371   synthesizeText(
  1372     { "composition":
  1373       { "string": "\u9AD8",
  1374         "clauses":
  1376           { "length": 0, "attr": 0 }
  1378       },
  1379       "caret": { "start": 1, "length": 0 }
  1380     });
  1382   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1383                     "runCompositionTest", "#4-9") ||
  1384       !checkSelection(5, "", "runCompositionTest", "#4-9")) {
  1385     return;
  1388   synthesizeComposition({ type: "compositionend", data: "\u9AD8" });
  1390   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1391                     "runCompositionTest", "#4-10") ||
  1392       !checkSelection(5, "", "runCompositionTest", "#4-10")) {
  1393     return;
  1396   synthesizeKey("VK_BACK_SPACE", {});
  1397   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1398                     "runCompositionTest", "#4-11") ||
  1399       !checkSelection(4, "", "runCompositionTest", "#4-11")) {
  1400     return;
  1403   // bug 23558, ancient Japanese IMEs on Window may send empty text event
  1404   // twice at canceling composition.
  1405   synthesizeComposition({ type: "compositionstart" });
  1407   synthesizeComposition({ type: "compositionupdate", data: "\u6700" });
  1408   synthesizeText(
  1409     { "composition":
  1410       { "string": "\u6700",
  1411         "clauses":
  1413           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1415       },
  1416       "caret": { "start": 1, "length": 0 }
  1417     });
  1419   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1420                     "runCompositionTest", "#5-1") ||
  1421       !checkSelection(4 + 1, "", "runCompositionTest", "#5-1")) {
  1422     return;
  1425   synthesizeComposition({ type: "compositionupdate", data: "" });
  1426   synthesizeText(
  1427     { "composition":
  1428       { "string": "",
  1429         "clauses":
  1431           { "length": 0, "attr": 0 }
  1433       },
  1434       "caret": { "start": 0, "length": 0 }
  1435     });
  1437   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1438                     "runCompositionTest", "#5-2") ||
  1439       !checkSelection(4, "", "runCompositionTest", "#5-2")) {
  1440     return;
  1443   synthesizeText(
  1444     { "composition":
  1445       { "string": "",
  1446         "clauses":
  1448           { "length": 0, "attr": 0 }
  1450       },
  1451       "caret": { "start": 0, "length": 0 }
  1452     });
  1454   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1455                     "runCompositionTest", "#5-3") ||
  1456       !checkSelection(4, "", "runCompositionTest", "#5-3")) {
  1457     return;
  1460   synthesizeComposition({ type: "compositionend", data: "\u9AD8" });
  1462   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1463                     "runCompositionTest", "#5-4") ||
  1464       !checkSelection(4, "", "runCompositionTest", "#5-4")) {
  1465     return;
  1468   // Undo tests for the testcases for bug 23558 and bug 271815
  1469   synthesizeKey("Z", { accelKey: true });
  1471   // XXX this is unexpected behavior, see bug 258291
  1472   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1473                     "runCompositionTest", "#6-1") ||
  1474       !checkSelection(4, "", "runCompositionTest", "#6-1")) {
  1475     return;
  1478   synthesizeKey("Z", { accelKey: true });
  1480   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1481                     "runCompositionTest", "#6-2") ||
  1482       !checkSelection(5, "", "runCompositionTest", "#6-2")) {
  1483     return;
  1486   synthesizeKey("Z", { accelKey: true });
  1488   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1489                     "runCompositionTest", "#6-3") ||
  1490       !checkSelection(4, "\u6700", "runCompositionTest", "#6-3")) {
  1491     return;
  1494   synthesizeKey("Z", { accelKey: true });
  1496   // XXX this is unexpected behavior, see bug 258291
  1497   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1498                     "runCompositionTest", "#6-4") ||
  1499       !checkSelection(5, "", "runCompositionTest", "#6-4")) {
  1500     return;
  1503   synthesizeKey("Z", { accelKey: true });
  1505   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1506                     "runCompositionTest", "#6-5") ||
  1507       !checkSelection(4, "", "runCompositionTest", "#6-5")) {
  1508     return;
  1512 function runCompositionEventTest()
  1514   const kDescription = "runCompositionEventTest: ";
  1515   const kEvents = ["compositionstart", "compositionupdate", "compositionend",
  1516                    "input"];
  1518   input.value = "";
  1519   input.focus();
  1521   var windowEventCounts = [], windowEventData = [], windowEventLocale = [];
  1522   var inputEventCounts = [], inputEventData = [], inputEventLocale = [];
  1523   var preventDefault = false;
  1524   var stopPropagation = false;
  1526   function initResults()
  1528     for (var i = 0; i < kEvents.length; i++) {
  1529       windowEventCounts[kEvents[i]] = 0;
  1530       windowEventData[kEvents[i]] = "";
  1531       windowEventLocale[kEvents[i]] = "";
  1532       inputEventCounts[kEvents[i]] = 0;
  1533       inputEventData[kEvents[i]] = "";
  1534       inputEventLocale[kEvents[i]] = "";
  1538   function compositionEventHandlerForWindow(aEvent)
  1540     windowEventCounts[aEvent.type]++;
  1541     windowEventData[aEvent.type] = aEvent.data;
  1542     windowEventLocale[aEvent.type] = aEvent.locale;
  1543     if (preventDefault) {
  1544       aEvent.preventDefault();
  1546     if (stopPropagation) {
  1547       aEvent.stopPropagation();
  1551   function formEventHandlerForWindow(aEvent)
  1553     ok(aEvent.isTrusted, "input events must be trusted events");
  1554     windowEventCounts[aEvent.type]++;
  1555     windowEventData[aEvent.type] = input.value;
  1558   function compositionEventHandlerForInput(aEvent)
  1560     inputEventCounts[aEvent.type]++;
  1561     inputEventData[aEvent.type] = aEvent.data;
  1562     inputEventLocale[aEvent.type] = aEvent.locale;
  1563     if (preventDefault) {
  1564       aEvent.preventDefault();
  1566     if (stopPropagation) {
  1567       aEvent.stopPropagation();
  1571   function formEventHandlerForInput(aEvent)
  1573     inputEventCounts[aEvent.type]++;
  1574     inputEventData[aEvent.type] = input.value;
  1577   window.addEventListener("compositionstart", compositionEventHandlerForWindow,
  1578                           true, true);
  1579   window.addEventListener("compositionend", compositionEventHandlerForWindow,
  1580                           true, true);
  1581   window.addEventListener("compositionupdate", compositionEventHandlerForWindow,
  1582                           true, true);
  1583   window.addEventListener("input", formEventHandlerForWindow,
  1584                           true, true);
  1586   input.addEventListener("compositionstart", compositionEventHandlerForInput,
  1587                          true, true);
  1588   input.addEventListener("compositionend", compositionEventHandlerForInput,
  1589                          true, true);
  1590   input.addEventListener("compositionupdate", compositionEventHandlerForInput,
  1591                          true, true);
  1592   input.addEventListener("input", formEventHandlerForInput,
  1593                          true, true);
  1595   // test for normal case
  1596   initResults();
  1598   synthesizeComposition({ type: "compositionstart" });
  1599   synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  1600   synthesizeText(
  1601     { "composition":
  1602       { "string": "\u3089",
  1603         "clauses":
  1605           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1607       },
  1608       "caret": { "start": 1, "length": 0 }
  1609     });
  1611   is(windowEventCounts["compositionstart"], 1,
  1612      kDescription + "compositionstart hasn't been handled by window #1");
  1613   is(windowEventData["compositionstart"], "",
  1614      kDescription + "data of compositionstart isn't empty (window) #1");
  1615   is(windowEventLocale["compositionstart"], "",
  1616      kDescription + "locale of compositionstart isn't empty (window) #1");
  1617   is(inputEventCounts["compositionstart"], 1,
  1618      kDescription + "compositionstart hasn't been handled by input #1");
  1619   is(inputEventData["compositionstart"], "",
  1620      kDescription + "data of compositionstart isn't empty (input) #1");
  1621   is(inputEventLocale["compositionstart"], "",
  1622      kDescription + "locale of compositionstart isn't empty (input) #1");
  1624   is(windowEventCounts["compositionupdate"], 1,
  1625      kDescription + "compositionupdate hasn't been handled by window #1");
  1626   is(windowEventData["compositionupdate"], "\u3089",
  1627      kDescription + "data of compositionupdate doesn't match (window) #1");
  1628   is(windowEventLocale["compositionupdate"], "",
  1629      kDescription + "locale of compositionupdate isn't empty (window) #1");
  1630   is(inputEventCounts["compositionupdate"], 1,
  1631      kDescription + "compositionupdate hasn't been handled by input #1");
  1632   is(inputEventData["compositionupdate"], "\u3089",
  1633      kDescription + "data of compositionupdate doesn't match (input) #1");
  1634   is(inputEventLocale["compositionupdate"], "",
  1635      kDescription + "locale of compositionupdate isn't empty (input) #1");
  1637   is(windowEventCounts["compositionend"], 0,
  1638      kDescription + "compositionend has been handled by window #1");
  1639   is(inputEventCounts["compositionend"], 0,
  1640      kDescription + "compositionend has been handled by input #1");
  1642   is(windowEventCounts["input"], 1,
  1643      kDescription + "input hasn't been handled by window #1");
  1644   is(windowEventData["input"], "\u3089",
  1645      kDescription + "value of input element wasn't modified (window) #1");
  1646   is(inputEventCounts["input"], 1,
  1647      kDescription + "input hasn't been handled by input #1");
  1648   is(inputEventData["input"], "\u3089",
  1649      kDescription + "value of input element wasn't modified (input) #1");
  1651   synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
  1652   synthesizeText(
  1653     { "composition":
  1654       { "string": "\u3089\u30FC",
  1655         "clauses":
  1657           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  1659       },
  1660       "caret": { "start": 2, "length": 0 }
  1661     });
  1663   is(windowEventCounts["compositionstart"], 1,
  1664      kDescription + "compositionstart has been handled more than once by window #2");
  1665   is(inputEventCounts["compositionstart"], 1,
  1666      kDescription + "compositionstart has been handled more than once by input #2");
  1668   is(windowEventCounts["compositionupdate"], 2,
  1669      kDescription + "compositionupdate hasn't been handled by window #2");
  1670   is(windowEventData["compositionupdate"], "\u3089\u30FC",
  1671      kDescription + "data of compositionupdate doesn't match (window) #2");
  1672   is(windowEventLocale["compositionupdate"], "",
  1673      kDescription + "locale of compositionupdate isn't empty (window) #2");
  1674   is(inputEventCounts["compositionupdate"], 2,
  1675      kDescription + "compositionupdate hasn't been handled by input #2");
  1676   is(inputEventData["compositionupdate"], "\u3089\u30FC",
  1677      kDescription + "data of compositionupdate doesn't match (input) #2");
  1678   is(inputEventLocale["compositionupdate"], "",
  1679      kDescription + "locale of compositionupdate isn't empty (input) #2");
  1681   is(windowEventCounts["compositionend"], 0,
  1682      kDescription + "compositionend has been handled during composition by window #2");
  1683   is(inputEventCounts["compositionend"], 0,
  1684      kDescription + "compositionend has been handled during composition by input #2");
  1686   is(windowEventCounts["input"], 2,
  1687      kDescription + "input hasn't been handled by window #2");
  1688   is(windowEventData["input"], "\u3089\u30FC",
  1689      kDescription + "value of input element wasn't modified (window) #2");
  1690   is(inputEventCounts["input"], 2,
  1691      kDescription + "input hasn't been handled by input #2");
  1692   is(inputEventData["input"], "\u3089\u30FC",
  1693      kDescription + "value of input element wasn't modified (input) #2");
  1695   // text event shouldn't cause composition update, e.g., at committing.
  1696   synthesizeText(
  1697     { "composition":
  1698       { "string": "\u3089\u30FC",
  1699         "clauses":
  1701           { "length": 0, "attr": 0 }
  1703       },
  1704       "caret": { "start": 2, "length": 0 }
  1705     });
  1707   synthesizeComposition({ type: "compositionend", data: "\u3089\u30FC" });
  1709   is(windowEventCounts["compositionstart"], 1,
  1710      kDescription + "compositionstart has been handled more than once by window #3");
  1711   is(inputEventCounts["compositionstart"], 1,
  1712      kDescription + "compositionstart has been handled more than once by input #3");
  1714   is(windowEventCounts["compositionupdate"], 2,
  1715      kDescription + "compositionupdate has been fired unexpectedly on window #3");
  1716   is(inputEventCounts["compositionupdate"], 2,
  1717      kDescription + "compositionupdate has been fired unexpectedly on input #3");
  1719   is(windowEventCounts["compositionend"], 1,
  1720      kDescription + "compositionend hasn't been handled by window #3");
  1721   is(windowEventData["compositionend"], "\u3089\u30FC",
  1722      kDescription + "data of compositionend doesn't match (window) #3");
  1723   is(windowEventLocale["compositionend"], "",
  1724      kDescription + "locale of compositionend isn't empty (window) #3");
  1725   is(inputEventCounts["compositionend"], 1,
  1726      kDescription + "compositionend hasn't been handled by input #3");
  1727   is(inputEventData["compositionend"], "\u3089\u30FC",
  1728      kDescription + "data of compositionend doesn't match (input) #3");
  1729   is(inputEventLocale["compositionend"], "",
  1730      kDescription + "locale of compositionend isn't empty (input) #3");
  1732   is(windowEventCounts["input"], 3,
  1733      kDescription + "input hasn't been handled by window #3");
  1734   is(windowEventData["input"], "\u3089\u30FC",
  1735      kDescription + "value of input element wasn't modified (window) #3");
  1736   is(inputEventCounts["input"], 3,
  1737      kDescription + "input hasn't been handled by input #3");
  1738   is(inputEventData["input"], "\u3089\u30FC",
  1739      kDescription + "value of input element wasn't modified (input) #3");
  1741   // select the second character, then, data of composition start should be
  1742   // the selected character.
  1743   initResults();
  1744   synthesizeKey("VK_LEFT", { shiftKey: true });
  1746   synthesizeComposition({ type: "compositionstart" });
  1748   synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  1749   synthesizeText(
  1750     { "composition":
  1751       { "string": "\u3089",
  1752         "clauses":
  1754           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1756       },
  1757       "caret": { "start": 1, "length": 0 }
  1758     });
  1760   synthesizeText(
  1761     { "composition":
  1762       { "string": "\u3089",
  1763         "clauses":
  1765           { "length": 0, "attr": 0 }
  1767       },
  1768       "caret": { "start": 1, "length": 0 }
  1769     });
  1771   synthesizeComposition({ type: "compositionend", data: "\u3089" });
  1773   is(windowEventCounts["compositionstart"], 1,
  1774      kDescription + "compositionstart hasn't been handled by window #4");
  1775   is(windowEventData["compositionstart"], "\u30FC",
  1776      kDescription + "data of compositionstart is empty (window) #4");
  1777   is(windowEventLocale["compositionstart"], "",
  1778      kDescription + "locale of compositionstart isn't empty (window) #4");
  1779   is(inputEventCounts["compositionstart"], 1,
  1780      kDescription + "compositionstart hasn't been handled by input #4");
  1781   is(inputEventData["compositionstart"], "\u30FC",
  1782      kDescription + "data of compositionstart is empty (input) #4");
  1783   is(inputEventLocale["compositionstart"], "",
  1784      kDescription + "locale of compositionstart isn't empty (input) #4");
  1786   is(windowEventCounts["compositionupdate"], 1,
  1787      kDescription + "compositionupdate hasn't been handled by window #4");
  1788   is(windowEventData["compositionupdate"], "\u3089",
  1789      kDescription + "data of compositionupdate doesn't match (window) #4");
  1790   is(windowEventLocale["compositionupdate"], "",
  1791      kDescription + "locale of compositionupdate isn't empty (window) #4");
  1792   is(inputEventCounts["compositionupdate"], 1,
  1793      kDescription + "compositionupdate hasn't been handled by input #4");
  1794   is(inputEventData["compositionupdate"], "\u3089",
  1795      kDescription + "data of compositionupdate doesn't match (input) #4");
  1796   is(inputEventLocale["compositionupdate"], "",
  1797      kDescription + "locale of compositionupdate isn't empty (input) #4");
  1799   is(windowEventCounts["compositionend"], 1,
  1800      kDescription + "compositionend hasn't been handled by window #4");
  1801   is(windowEventData["compositionend"], "\u3089",
  1802      kDescription + "data of compositionend doesn't match (window) #4");
  1803   is(windowEventLocale["compositionend"], "",
  1804      kDescription + "locale of compositionend isn't empty (window) #4");
  1805   is(inputEventCounts["compositionend"], 1,
  1806      kDescription + "compositionend hasn't been handled by input #4");
  1807   is(inputEventData["compositionend"], "\u3089",
  1808      kDescription + "data of compositionend doesn't match (input) #4");
  1809   is(inputEventLocale["compositionend"], "",
  1810      kDescription + "locale of compositionend isn't empty (input) #4");
  1812   is(windowEventCounts["input"], 2,
  1813      kDescription + "input hasn't been handled by window #4");
  1814   is(windowEventData["input"], "\u3089\u3089",
  1815      kDescription + "value of input element wasn't modified (window) #4");
  1816   is(inputEventCounts["input"], 2,
  1817      kDescription + "input hasn't been handled by input #4");
  1818   is(inputEventData["input"], "\u3089\u3089",
  1819      kDescription + "value of input element wasn't modified (input) #4");
  1821   // preventDefault() should effect nothing.
  1822   preventDefault = true;
  1824   initResults();
  1825   synthesizeKey("A", { accelKey: true }); // Select All
  1827   synthesizeComposition({ type: "compositionstart" });
  1829   synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
  1830   synthesizeText(
  1831     { "composition":
  1832       { "string": "\u306D",
  1833         "clauses":
  1835           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1837       },
  1838       "caret": { "start": 1, "length": 0 }
  1839     });
  1841   synthesizeText(
  1842     { "composition":
  1843       { "string": "\u306D",
  1844         "clauses":
  1846           { "length": 0, "attr": 0 }
  1848       },
  1849       "caret": { "start": 1, "length": 0 }
  1850     });
  1852   synthesizeComposition({ type: "compositionend", data: "\u306D" });
  1854   is(windowEventCounts["compositionstart"], 1,
  1855      kDescription + "compositionstart hasn't been handled by window #5");
  1856   is(windowEventData["compositionstart"], "\u3089\u3089",
  1857      kDescription + "data of compositionstart is empty (window) #5");
  1858   is(windowEventLocale["compositionstart"], "",
  1859      kDescription + "locale of compositionstart isn't empty (window) #5");
  1860   is(inputEventCounts["compositionstart"], 1,
  1861      kDescription + "compositionstart hasn't been handled by input #5");
  1862   is(inputEventData["compositionstart"], "\u3089\u3089",
  1863      kDescription + "data of compositionstart is empty (input) #5");
  1864   is(inputEventLocale["compositionstart"], "",
  1865      kDescription + "locale of compositionstart isn't empty (input) #5");
  1867   is(windowEventCounts["compositionupdate"], 1,
  1868      kDescription + "compositionupdate hasn't been handled by window #5");
  1869   is(windowEventData["compositionupdate"], "\u306D",
  1870      kDescription + "data of compositionupdate doesn't match (window) #5");
  1871   is(windowEventLocale["compositionupdate"], "",
  1872      kDescription + "locale of compositionupdate isn't empty (window) #5");
  1873   is(inputEventCounts["compositionupdate"], 1,
  1874      kDescription + "compositionupdate hasn't been handled by input #5");
  1875   is(inputEventData["compositionupdate"], "\u306D",
  1876      kDescription + "data of compositionupdate doesn't match (input) #5");
  1877   is(inputEventLocale["compositionupdate"], "",
  1878      kDescription + "locale of compositionupdate isn't empty (input) #5");
  1880   is(windowEventCounts["compositionend"], 1,
  1881      kDescription + "compositionend hasn't been handled by window #5");
  1882   is(windowEventData["compositionend"], "\u306D",
  1883      kDescription + "data of compositionend doesn't match (window) #5");
  1884   is(windowEventLocale["compositionend"], "",
  1885      kDescription + "locale of compositionend isn't empty (window) #5");
  1886   is(inputEventCounts["compositionend"], 1,
  1887      kDescription + "compositionend hasn't been handled by input #5");
  1888   is(inputEventData["compositionend"], "\u306D",
  1889      kDescription + "data of compositionend doesn't match (input) #5");
  1890   is(inputEventLocale["compositionend"], "",
  1891      kDescription + "locale of compositionend isn't empty (input) #5");
  1893   is(windowEventCounts["input"], 2,
  1894      kDescription + "input hasn't been handled by window #5");
  1895   is(windowEventData["input"], "\u306D",
  1896      kDescription + "value of input element wasn't modified (window) #5");
  1897   is(inputEventCounts["input"], 2,
  1898      kDescription + "input hasn't been handled by input #5");
  1899   is(inputEventData["input"], "\u306D",
  1900      kDescription + "value of input element wasn't modified (input) #5");
  1902   prevnetDefault = false;
  1904   // stopPropagation() should effect nothing (except event count)
  1905   stopPropagation = true;
  1907   initResults();
  1908   synthesizeKey("A", { accelKey: true }); // Select All
  1910   synthesizeComposition({ type: "compositionstart" });
  1912   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1913   synthesizeText(
  1914     { "composition":
  1915       { "string": "\u306E",
  1916         "clauses":
  1918           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1920       },
  1921       "caret": { "start": 1, "length": 0 }
  1922     });
  1924   synthesizeText(
  1925     { "composition":
  1926       { "string": "\u306E",
  1927         "clauses":
  1929           { "length": 0, "attr": 0 }
  1931       },
  1932       "caret": { "start": 1, "length": 0 }
  1933     });
  1935   synthesizeComposition({ type: "compositionend", data: "\u306E" });
  1937   is(windowEventCounts["compositionstart"], 1,
  1938      kDescription + "compositionstart hasn't been handled by window #6");
  1939   is(windowEventData["compositionstart"], "\u306D",
  1940      kDescription + "data of compositionstart is empty #6");
  1941   is(windowEventLocale["compositionstart"], "",
  1942      kDescription + "locale of compositionstart isn't empty #6");
  1943   is(inputEventCounts["compositionstart"], 0,
  1944      kDescription + "compositionstart has been handled by input #6");
  1946   is(windowEventCounts["compositionupdate"], 1,
  1947      kDescription + "compositionupdate hasn't been handled by window #6");
  1948   is(windowEventData["compositionupdate"], "\u306E",
  1949      kDescription + "data of compositionupdate doesn't match #6");
  1950   is(windowEventLocale["compositionupdate"], "",
  1951      kDescription + "locale of compositionupdate isn't empty #6");
  1952   is(inputEventCounts["compositionupdate"], 0,
  1953      kDescription + "compositionupdate has been handled by input #6");
  1955   is(windowEventCounts["compositionend"], 1,
  1956      kDescription + "compositionend hasn't been handled by window #6");
  1957   is(windowEventData["compositionend"], "\u306E",
  1958      kDescription + "data of compositionend doesn't match #6");
  1959   is(windowEventLocale["compositionend"], "",
  1960      kDescription + "locale of compositionend isn't empty #6");
  1961   is(inputEventCounts["compositionend"], 0,
  1962      kDescription + "compositionend has been handled by input #6");
  1964   is(windowEventCounts["input"], 2,
  1965      kDescription + "input hasn't been handled by window #6");
  1966   is(windowEventData["input"], "\u306E",
  1967      kDescription + "value of input element wasn't modified (window) #6");
  1968   is(inputEventCounts["input"], 2,
  1969      kDescription + "input hasn't been handled by input #6");
  1970   is(inputEventData["input"], "\u306E",
  1971      kDescription + "value of input element wasn't modified (input) #6");
  1973   stopPropagation = false;
  1975   // create event and dispatch it.
  1976   initResults();
  1978   input.value = "value of input";
  1979   synthesizeKey("A", { accelKey: true }); // Select All
  1981   var compositionstart = document.createEvent("CompositionEvent");
  1982   compositionstart.initCompositionEvent("compositionstart",
  1983                                         true, true, document.defaultView,
  1984                                         "start data", "start locale");
  1985   is(compositionstart.type, "compositionstart",
  1986      kDescription + "type doesn't match #7");
  1987   is(compositionstart.data, "start data",
  1988      kDescription + "data doesn't match #7");
  1989   is(compositionstart.locale, "start locale",
  1990      kDescription + "locale doesn't match #7");
  1991   is(compositionstart.detail, 0,
  1992      kDescription + "detail isn't 0 #7");
  1994   input.dispatchEvent(compositionstart);
  1996   is(windowEventCounts["compositionstart"], 1,
  1997      kDescription + "compositionstart hasn't been handled by window #7");
  1998   is(windowEventData["compositionstart"], "start data",
  1999      kDescription + "data of compositionstart was changed (window) #7");
  2000   is(windowEventLocale["compositionstart"], "start locale",
  2001      kDescription + "locale of compositionstart was changed (window) #7");
  2002   is(inputEventCounts["compositionstart"], 1,
  2003      kDescription + "compositionstart hasn't been handled by input #7");
  2004   is(inputEventData["compositionstart"], "start data",
  2005      kDescription + "data of compositionstart was changed (input) #7");
  2006   is(inputEventLocale["compositionstart"], "start locale",
  2007      kDescription + "locale of compositionstart was changed (input) #7");
  2009   is(input.value, "value of input",
  2010      kDescription + "input value was changed #7");
  2012   var compositionupdate1 = document.createEvent("compositionevent");
  2013   compositionupdate1.initCompositionEvent("compositionupdate",
  2014                                           true, false, document.defaultView,
  2015                                           "composing string", "composing locale");
  2016   is(compositionupdate1.type, "compositionupdate",
  2017      kDescription + "type doesn't match #8");
  2018   is(compositionupdate1.data, "composing string",
  2019      kDescription + "data doesn't match #8");
  2020   is(compositionupdate1.locale, "composing locale",
  2021      kDescription + "locale doesn't match #8");
  2022   is(compositionupdate1.detail, 0,
  2023      kDescription + "detail isn't 0 #8");
  2025   input.dispatchEvent(compositionupdate1);
  2027   is(windowEventCounts["compositionupdate"], 1,
  2028      kDescription + "compositionupdate hasn't been handled by window #8");
  2029   is(windowEventData["compositionupdate"], "composing string",
  2030      kDescription + "data of compositionupdate was changed (window) #8");
  2031   is(windowEventLocale["compositionupdate"], "composing locale",
  2032      kDescription + "locale of compositionupdate was changed (window) #8");
  2033   is(inputEventCounts["compositionupdate"], 1,
  2034      kDescription + "compositionupdate hasn't been handled by input #8");
  2035   is(inputEventData["compositionupdate"], "composing string",
  2036      kDescription + "data of compositionupdate was changed (input) #8");
  2037   is(inputEventLocale["compositionupdate"], "composing locale",
  2038      kDescription + "locale of compositionupdate was changed (input) #8");
  2040   is(input.value, "value of input",
  2041      kDescription + "input value was changed #8");
  2043   var compositionupdate2 = document.createEvent("compositionEvent");
  2044   compositionupdate2.initCompositionEvent("compositionupdate",
  2045                                           true, false, document.defaultView,
  2046                                           "commit string", "commit locale");
  2047   is(compositionupdate2.type, "compositionupdate",
  2048      kDescription + "type doesn't match #9");
  2049   is(compositionupdate2.data, "commit string",
  2050      kDescription + "data doesn't match #9");
  2051   is(compositionupdate2.locale, "commit locale",
  2052      kDescription + "locale doesn't match #9");
  2053   is(compositionupdate2.detail, 0,
  2054      kDescription + "detail isn't 0 #9");
  2056   input.dispatchEvent(compositionupdate2);
  2058   is(windowEventCounts["compositionupdate"], 2,
  2059      kDescription + "compositionupdate hasn't been handled by window #9");
  2060   is(windowEventData["compositionupdate"], "commit string",
  2061      kDescription + "data of compositionupdate was changed (window) #9");
  2062   is(windowEventLocale["compositionupdate"], "commit locale",
  2063      kDescription + "locale of compositionupdate was changed (window) #9");
  2064   is(inputEventCounts["compositionupdate"], 2,
  2065      kDescription + "compositionupdate hasn't been handled by input #9");
  2066   is(inputEventData["compositionupdate"], "commit string",
  2067      kDescription + "data of compositionupdate was changed (input) #9");
  2068   is(inputEventLocale["compositionupdate"], "commit locale",
  2069      kDescription + "locale of compositionupdate was changed (input) #9");
  2071   is(input.value, "value of input",
  2072      kDescription + "input value was changed #9");
  2074   var compositionend = document.createEvent("Compositionevent");
  2075   compositionend.initCompositionEvent("compositionend",
  2076                                       true, false, document.defaultView,
  2077                                       "end data", "end locale");
  2078   is(compositionend.type, "compositionend",
  2079      kDescription + "type doesn't match #10");
  2080   is(compositionend.data, "end data",
  2081      kDescription + "data doesn't match #10");
  2082   is(compositionend.locale, "end locale",
  2083      kDescription + "locale doesn't match #10");
  2084   is(compositionend.detail, 0,
  2085      kDescription + "detail isn't 0 #10");
  2087   input.dispatchEvent(compositionend);
  2089   is(windowEventCounts["compositionend"], 1,
  2090      kDescription + "compositionend hasn't been handled by window #10");
  2091   is(windowEventData["compositionend"], "end data",
  2092      kDescription + "data of compositionend was changed (window) #10");
  2093   is(windowEventLocale["compositionend"], "end locale",
  2094      kDescription + "locale of compositionend was changed (window) #10");
  2095   is(inputEventCounts["compositionend"], 1,
  2096      kDescription + "compositionend hasn't been handled by input #10");
  2097   is(inputEventData["compositionend"], "end data",
  2098      kDescription + "data of compositionend was changed (input) #10");
  2099   is(inputEventLocale["compositionend"], "end locale",
  2100      kDescription + "locale of compositionend was changed (input) #10");
  2102   is(input.value, "value of input",
  2103      kDescription + "input value was changed #10");
  2105   window.removeEventListener("compositionstart",
  2106                              compositionEventHandlerForWindow, true);
  2107   window.removeEventListener("compositionend",
  2108                              compositionEventHandlerForWindow, true);
  2109   window.removeEventListener("compositionupdate",
  2110                              compositionEventHandlerForWindow, true);
  2111   window.removeEventListener("input",
  2112                              formEventHandlerForWindow, true);
  2114   input.removeEventListener("compositionstart",
  2115                             compositionEventHandlerForInput, true);
  2116   input.removeEventListener("compositionend",
  2117                             compositionEventHandlerForInput, true);
  2118   input.removeEventListener("compositionupdate",
  2119                             compositionEventHandlerForInput, true);
  2120   input.removeEventListener("input",
  2121                             formEventHandlerForInput, true);
  2124 function runCharAtPointTest(aFocusedEditor, aTargetName)
  2126   aFocusedEditor.value = "This is a test of the\nContent Events";
  2127                        // 012345678901234567890  12345678901234
  2128                        // 0         1         2           3    
  2130   aFocusedEditor.focus();
  2132   const kNone = -1;
  2133   const kTestingOffset   = [     0, 10,    20, 21 + kLFLen, 34 + kLFLen];
  2134   const kLeftSideOffset  = [ kNone,  9,    19,       kNone, 33 + kLFLen];
  2135   const kRightSideOffset = [     1, 11, kNone, 22 + kLFLen,       kNone];
  2137   var editorRect = synthesizeQueryEditorRect();
  2138   if (!checkQueryContentResult(editorRect,
  2139         "runCharAtPointTest (" + aTargetName + "): editorRect")) {
  2140     return;
  2143   for (var i = 0; i < kTestingOffset.length; i++) {
  2144     var textRect = synthesizeQueryTextRect(kTestingOffset[i], 1);
  2145     if (!checkQueryContentResult(textRect,
  2146           "runCharAtPointTest (" + aTargetName + "): textRect: i=" + i)) {
  2147       continue;
  2150     checkRectContainsRect(textRect, editorRect,
  2151       "runCharAtPointTest (" + aTargetName +
  2152       "): the text rect isn't in the editor");
  2154     // Test #1, getting same character rect by the point near the top-left.
  2155     var charAtPt1 = synthesizeCharAtPoint(textRect.left + 1,
  2156                                           textRect.top + 1);
  2157     if (checkQueryContentResult(charAtPt1,
  2158           "runCharAtPointTest (" + aTargetName + "): charAtPt1: i=" + i)) {
  2159       ok(!charAtPt1.notFound,
  2160          "runCharAtPointTest (" + aTargetName + "): charAtPt1 isn't found: i=" + i);
  2161       if (!charAtPt1.notFound) {
  2162         is(charAtPt1.offset, kTestingOffset[i],
  2163            "runCharAtPointTest (" + aTargetName + "): charAtPt1 offset is wrong: i=" + i);
  2164         checkRect(charAtPt1, textRect, "runCharAtPointTest (" + aTargetName +
  2165                   "): charAtPt1 left is wrong: i=" + i);
  2169     // Test #2, getting same character rect by the point near the bottom-right.
  2170     var charAtPt2 = synthesizeCharAtPoint(textRect.left + textRect.width - 2,
  2171                                           textRect.top + textRect.height - 2);
  2172     if (checkQueryContentResult(charAtPt2,
  2173           "runCharAtPointTest (" + aTargetName + "): charAtPt2: i=" + i)) {
  2174       ok(!charAtPt2.notFound,
  2175          "runCharAtPointTest (" + aTargetName + "): charAtPt2 isn't found: i=" + i);
  2176       if (!charAtPt2.notFound) {
  2177         is(charAtPt2.offset, kTestingOffset[i],
  2178            "runCharAtPointTest (" + aTargetName + "): charAtPt2 offset is wrong: i=" + i);
  2179         checkRect(charAtPt2, textRect, "runCharAtPointTest (" + aTargetName +
  2180                   "): charAtPt1 left is wrong: i=" + i);
  2184     // Test #3, getting left character offset.
  2185     var charAtPt3 = synthesizeCharAtPoint(textRect.left - 2,
  2186                                           textRect.top + 1);
  2187     if (checkQueryContentResult(charAtPt3,
  2188           "runCharAtPointTest (" + aTargetName + "): charAtPt3: i=" + i)) {
  2189       is(charAtPt3.notFound, kLeftSideOffset[i] == kNone,
  2190          kLeftSideOffset[i] == kNone ?
  2191            "runCharAtPointTest (" + aTargetName + "): charAtPt3 is found: i=" + i :
  2192            "runCharAtPointTest (" + aTargetName + "): charAtPt3 isn't found: i=" + i);
  2193       if (!charAtPt3.notFound) {
  2194         is(charAtPt3.offset, kLeftSideOffset[i],
  2195            "runCharAtPointTest (" + aTargetName + "): charAtPt3 offset is wrong: i=" + i);
  2199     // Test #4, getting right character offset.
  2200     var charAtPt4 = synthesizeCharAtPoint(textRect.left + textRect.width + 1,
  2201                                           textRect.top + textRect.height - 2);
  2202     if (checkQueryContentResult(charAtPt4,
  2203           "runCharAtPointTest (" + aTargetName + "): charAtPt4: i=" + i)) {
  2204       is(charAtPt4.notFound, kRightSideOffset[i] == kNone,
  2205          kRightSideOffset[i] == kNone ?
  2206            "runCharAtPointTest (" + aTargetName + "): charAtPt4 is found: i=" + i :
  2207            "runCharAtPointTest (" + aTargetName + "): charAtPt4 isn't found: i=" + i);
  2208       if (!charAtPt4.notFound) {
  2209         is(charAtPt4.offset, kRightSideOffset[i],
  2210            "runCharAtPointTest (" + aTargetName + "): charAtPt4 offset is wrong: i=" + i);
  2216 function runCharAtPointAtOutsideTest()
  2218   textarea.focus();
  2219   textarea.value = "some text";
  2220   var editorRect = synthesizeQueryEditorRect();
  2221   if (!checkQueryContentResult(editorRect,
  2222         "runCharAtPointAtOutsideTest: editorRect")) {
  2223     return;
  2225   // Check on a text node which is at the outside of editor.
  2226   var charAtPt = synthesizeCharAtPoint(editorRect.left + 20,
  2227                                        editorRect.top - 10);
  2228   if (checkQueryContentResult(charAtPt,
  2229         "runCharAtPointAtOutsideTest: charAtPt")) {
  2230     ok(charAtPt.notFound,
  2231        "runCharAtPointAtOutsideTest: charAtPt is found on outside of editor");
  2235 function runBug722639Test()
  2237   textarea.focus();
  2238   textarea.value = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  2239   textarea.value += textarea.value;
  2240   textarea.value += textarea.value; // 80 characters
  2242   var firstLine = synthesizeQueryTextRect(0, 1);
  2243   if (!checkQueryContentResult(firstLine,
  2244         "runBug722639Test: firstLine")) {
  2245     return;
  2247   var secondLine = synthesizeQueryTextRect(kLFLen, 1);
  2248   if (!checkQueryContentResult(secondLine,
  2249         "runBug722639Test: secondLine")) {
  2250     return;
  2252   var lineHeight = secondLine.top -  firstLine.top;
  2253   ok(lineHeight > 0,
  2254      "runBug722639Test: lineHeight must be positive");
  2255   is(secondLine.left, firstLine.left,
  2256      "runBug722639Test: the left value must be always same value");
  2257   var previousTop = secondLine.top;
  2258   for (var i = 2; i < textarea.value.length; i++) {
  2259     var currentLine = synthesizeQueryTextRect(kLFLen * i, 1);
  2260     if (!checkQueryContentResult(currentLine,
  2261            "runBug722639Test: " + i + "th currentLine")) {
  2262       return;
  2264     // NOTE: the top position may be 1px larger or smaller than other lines
  2265     //       due to sub pixel positioning.
  2266     if (Math.abs(currentLine.top - (previousTop + lineHeight)) <= 1) {
  2267       ok(true, "runBug722639Test: " + i + "th line's top is expected");
  2268     } else {
  2269       is(currentLine.top, previousTop + lineHeight,
  2270          "runBug722639Test: " + i + "th line's top is unexpected");
  2272     is(currentLine.left, firstLine.left,
  2273        "runBug722639Test: " + i + "th line's left is unexpected");
  2274     previousTop = currentLine.top;
  2278 function runForceCommitTest()
  2280   var events;
  2281   function eventHandler(aEvent)
  2283     events.push(aEvent);
  2285   window.addEventListener("compositionstart", eventHandler, true);
  2286   window.addEventListener("compositionupdate", eventHandler, true);
  2287   window.addEventListener("compositionend", eventHandler, true);
  2288   window.addEventListener("input", eventHandler, true);
  2289   window.addEventListener("text", eventHandler, true);
  2291   // Make the composition in textarea commit by click in the textarea
  2292   textarea.focus();
  2293   textarea.value = "";
  2295   events = [];
  2296   synthesizeComposition({ type: "compositionstart" });
  2298   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2299   synthesizeText(
  2300     { "composition":
  2301       { "string": "\u306E",
  2302         "clauses":
  2304           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2306       },
  2307       "caret": { "start": 1, "length": 0 }
  2308     });
  2310   is(events.length, 4,
  2311      "runForceCommitTest: wrong event count #1");
  2312   is(events[0].type, "compositionstart",
  2313      "runForceCommitTest: the 1st event must be compositionstart #1");
  2314   is(events[1].type, "compositionupdate",
  2315      "runForceCommitTest: the 2nd event must be compositionupdate #1");
  2316   is(events[2].type, "text",
  2317      "runForceCommitTest: the 3rd event must be text #1");
  2318   is(events[3].type, "input",
  2319      "runForceCommitTest: the 4th event must be input #1");
  2321   events = [];
  2322   synthesizeMouseAtCenter(textarea, {});
  2324   is(events.length, 3,
  2325      "runForceCommitTest: wrong event count #2");
  2326   is(events[0].type, "text",
  2327      "runForceCommitTest: the 1st event must be text #2");
  2328   is(events[1].type, "compositionend",
  2329      "runForceCommitTest: the 2nd event must be compositionend #2");
  2330   is(events[2].type, "input",
  2331      "runForceCommitTest: the 3rd event must be input #2");
  2332   is(events[1].data, "\u306E",
  2333      "runForceCommitTest: compositionend has wrong data #2");
  2334   is(events[0].target, textarea,
  2335      "runForceCommitTest: The 1st event was fired on wrong event target #2");
  2336   is(events[1].target, textarea,
  2337      "runForceCommitTest: The 2nd event was fired on wrong event target #2");
  2338   is(events[2].target, textarea,
  2339      "runForceCommitTest: The 3rd event was fired on wrong event target #2");
  2340   ok(!getEditorIMESupport(textarea).isComposing,
  2341      "runForceCommitTest: the textarea still has composition #2");
  2342   is(textarea.value, "\u306E",
  2343      "runForceCommitTest: the textarea doesn't have the committed text #2");
  2345   // Make the composition in textarea commit by click in another editor (input)
  2346   textarea.focus();
  2347   textarea.value = "";
  2348   input.value = "";
  2350   synthesizeComposition({ type: "compositionstart" });
  2352   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2353   synthesizeText(
  2354     { "composition":
  2355       { "string": "\u306E",
  2356         "clauses":
  2358           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2360       },
  2361       "caret": { "start": 1, "length": 0 }
  2362     });
  2364   events = [];
  2365   synthesizeMouseAtCenter(input, {});
  2367   is(events.length, 3,
  2368      "runForceCommitTest: wrong event count #3");
  2369   is(events[0].type, "text",
  2370      "runForceCommitTest: the 1st event must be text #3");
  2371   is(events[1].type, "compositionend",
  2372      "runForceCommitTest: the 2nd event must be compositionend #3");
  2373   is(events[2].type, "input",
  2374      "runForceCommitTest: the 3rd event must be input #3");
  2375   is(events[1].data, "\u306E",
  2376      "runForceCommitTest: compositionend has wrong data #3");
  2377   is(events[0].target, textarea,
  2378      "runForceCommitTest: The 1st event was fired on wrong event target #3");
  2379   is(events[1].target, textarea,
  2380      "runForceCommitTest: The 2nd event was fired on wrong event target #3");
  2381   is(events[2].target, textarea,
  2382      "runForceCommitTest: The 3rd event was fired on wrong event target #3");
  2383   ok(!getEditorIMESupport(textarea).isComposing,
  2384      "runForceCommitTest: the textarea still has composition #3");
  2385   ok(!getEditorIMESupport(input).isComposing,
  2386      "runForceCommitTest: the input has composition #3");
  2387   is(textarea.value, "\u306E",
  2388      "runForceCommitTest: the textarea doesn't have the committed text #3");
  2389   is(input.value, "",
  2390      "runForceCommitTest: the input has the committed text? #3");
  2392   // Make the composition in textarea commit by blur()
  2393   textarea.focus();
  2394   textarea.value = "";
  2396   synthesizeComposition({ type: "compositionstart" });
  2398   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2399   synthesizeText(
  2400     { "composition":
  2401       { "string": "\u306E",
  2402         "clauses":
  2404           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2406       },
  2407       "caret": { "start": 1, "length": 0 }
  2408     });
  2410   events = [];
  2411   textarea.blur();
  2413   is(events.length, 3,
  2414      "runForceCommitTest: wrong event count #4");
  2415   is(events[0].type, "text",
  2416      "runForceCommitTest: the 1st event must be text #4");
  2417   is(events[1].type, "compositionend",
  2418      "runForceCommitTest: the 2nd event must be compositionend #4");
  2419   is(events[2].type, "input",
  2420      "runForceCommitTest: the 3rd event must be input #4");
  2421   is(events[1].data, "\u306E",
  2422      "runForceCommitTest: compositionend has wrong data #4");
  2423   is(events[0].target, textarea,
  2424      "runForceCommitTest: The 1st event was fired on wrong event target #4");
  2425   is(events[1].target, textarea,
  2426      "runForceCommitTest: The 2nd event was fired on wrong event target #4");
  2427   is(events[2].target, textarea,
  2428      "runForceCommitTest: The 3rd event was fired on wrong event target #4");
  2429   ok(!getEditorIMESupport(textarea).isComposing,
  2430      "runForceCommitTest: the textarea still has composition #4");
  2431   is(textarea.value, "\u306E",
  2432      "runForceCommitTest: the textarea doesn't have the committed text #4");
  2434   // Make the composition in textarea commit by input.focus()
  2435   textarea.focus();
  2436   textarea.value = "";
  2437   input.value = "";
  2439   synthesizeComposition({ type: "compositionstart" });
  2441   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2442   synthesizeText(
  2443     { "composition":
  2444       { "string": "\u306E",
  2445         "clauses":
  2447           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2449       },
  2450       "caret": { "start": 1, "length": 0 }
  2451     });
  2453   events = [];
  2454   input.focus();
  2456   is(events.length, 3,
  2457      "runForceCommitTest: wrong event count #5");
  2458   is(events[0].type, "text",
  2459      "runForceCommitTest: the 1st event must be text #5");
  2460   is(events[1].type, "compositionend",
  2461      "runForceCommitTest: the 2nd event must be compositionend #5");
  2462   is(events[2].type, "input",
  2463      "runForceCommitTest: the 3rd event must be input #5");
  2464   is(events[1].data, "\u306E",
  2465      "runForceCommitTest: compositionend has wrong data #5");
  2466   is(events[0].target, textarea,
  2467      "runForceCommitTest: The 1st event was fired on wrong event target #5");
  2468   is(events[1].target, textarea,
  2469      "runForceCommitTest: The 2nd event was fired on wrong event target #5");
  2470   is(events[2].target, textarea,
  2471      "runForceCommitTest: The 3rd event was fired on wrong event target #5");
  2472   ok(!getEditorIMESupport(textarea).isComposing,
  2473      "runForceCommitTest: the textarea still has composition #5");
  2474   ok(!getEditorIMESupport(input).isComposing,
  2475      "runForceCommitTest: the input has composition #5");
  2476   is(textarea.value, "\u306E",
  2477      "runForceCommitTest: the textarea doesn't have the committed text #5");
  2478   is(input.value, "",
  2479      "runForceCommitTest: the input has the committed text? #5");
  2481   // Make the composition in textarea commit by click in another document's editor
  2482   textarea.focus();
  2483   textarea.value = "";
  2484   textareaInFrame.value = "";
  2486   synthesizeComposition({ type: "compositionstart" });
  2488   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2489   synthesizeText(
  2490     { "composition":
  2491       { "string": "\u306E",
  2492         "clauses":
  2494           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2496       },
  2497       "caret": { "start": 1, "length": 0 }
  2498     });
  2500   events = [];
  2501   synthesizeMouseAtCenter(textareaInFrame, {}, iframe.contentWindow);
  2503   is(events.length, 3,
  2504      "runForceCommitTest: wrong event count #6");
  2505   is(events[0].type, "text",
  2506      "runForceCommitTest: the 1st event must be text #6");
  2507   is(events[1].type, "compositionend",
  2508      "runForceCommitTest: the 2nd event must be compositionend #6");
  2509   is(events[2].type, "input",
  2510      "runForceCommitTest: the 3rd event must be input #6");
  2511   is(events[1].data, "\u306E",
  2512      "runForceCommitTest: compositionend has wrong data #6");
  2513   is(events[0].target, textarea,
  2514      "runForceCommitTest: The 1st event was fired on wrong event target #6");
  2515   is(events[1].target, textarea,
  2516      "runForceCommitTest: The 2nd event was fired on wrong event target #6");
  2517   is(events[2].target, textarea,
  2518      "runForceCommitTest: The 3rd event was fired on wrong event target #6");
  2519   ok(!getEditorIMESupport(textarea).isComposing,
  2520      "runForceCommitTest: the textarea still has composition #6");
  2521   ok(!getEditorIMESupport(textareaInFrame).isComposing,
  2522      "runForceCommitTest: the textarea in frame has composition #6");
  2523   is(textarea.value, "\u306E",
  2524      "runForceCommitTest: the textarea doesn't have the committed text #6");
  2525   is(textareaInFrame.value, "",
  2526      "runForceCommitTest: the textarea in frame has the committed text? #6");
  2528   // Make the composition in textarea commit by another document's editor's focus()
  2529   textarea.focus();
  2530   textarea.value = "";
  2531   textareaInFrame.value = "";
  2533   synthesizeComposition({ type: "compositionstart" });
  2535   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2536   synthesizeText(
  2537     { "composition":
  2538       { "string": "\u306E",
  2539         "clauses":
  2541           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2543       },
  2544       "caret": { "start": 1, "length": 0 }
  2545     });
  2547   events = [];
  2548   textareaInFrame.focus();
  2550   is(events.length, 3,
  2551      "runForceCommitTest: wrong event count #7");
  2552   is(events[0].type, "text",
  2553      "runForceCommitTest: the 1st event must be text #7");
  2554   is(events[1].type, "compositionend",
  2555      "runForceCommitTest: the 2nd event must be compositionend #7");
  2556   is(events[2].type, "input",
  2557      "runForceCommitTest: the 3rd event must be input #7");
  2558   is(events[1].data, "\u306E",
  2559      "runForceCommitTest: compositionend has wrong data #7");
  2560   is(events[0].target, textarea,
  2561      "runForceCommitTest: The 1st event was fired on wrong event target #7");
  2562   is(events[1].target, textarea,
  2563      "runForceCommitTest: The 2nd event was fired on wrong event target #7");
  2564   is(events[2].target, textarea,
  2565      "runForceCommitTest: The 3rd event was fired on wrong event target #7");
  2566   ok(!getEditorIMESupport(textarea).isComposing,
  2567      "runForceCommitTest: the textarea still has composition #7");
  2568   ok(!getEditorIMESupport(textareaInFrame).isComposing,
  2569      "runForceCommitTest: the textarea in frame has composition #7");
  2570   is(textarea.value, "\u306E",
  2571      "runForceCommitTest: the textarea doesn't have the committed text #7");
  2572   is(textareaInFrame.value, "",
  2573      "runForceCommitTest: the textarea in frame has the committed text? #7");
  2575   // Make the composition in a textarea commit by click in another editable document
  2576   textarea.focus();
  2577   textarea.value = "";
  2578   iframe2.contentDocument.body.innerHTML = "Text in the Body";
  2579   var iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  2581   synthesizeComposition({ type: "compositionstart" });
  2583   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2584   synthesizeText(
  2585     { "composition":
  2586       { "string": "\u306E",
  2587         "clauses":
  2589           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2591       },
  2592       "caret": { "start": 1, "length": 0 }
  2593     });
  2595   events = [];
  2596   synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
  2598   is(events.length, 3,
  2599      "runForceCommitTest: wrong event count #8");
  2600   is(events[0].type, "text",
  2601      "runForceCommitTest: the 1st event must be text #8");
  2602   is(events[1].type, "compositionend",
  2603      "runForceCommitTest: the 2nd event must be compositionend #8");
  2604   is(events[2].type, "input",
  2605      "runForceCommitTest: the 3rd event must be input #8");
  2606   is(events[1].data, "\u306E",
  2607      "runForceCommitTest: compositionend has wrong data #8");
  2608   is(events[0].target, textarea,
  2609      "runForceCommitTest: The 1st event was fired on wrong event target #8");
  2610   is(events[1].target, textarea,
  2611      "runForceCommitTest: The 2nd event was fired on wrong event target #8");
  2612   is(events[2].target, textarea,
  2613      "runForceCommitTest: The 3rd event was fired on wrong event target #8");
  2614   ok(!getEditorIMESupport(textarea).isComposing,
  2615      "runForceCommitTest: the textarea still has composition #8");
  2616   ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  2617      "runForceCommitTest: the editable document has composition #8");
  2618   is(textarea.value, "\u306E",
  2619      "runForceCommitTest: the textarea doesn't have the committed text #8");
  2620   is(iframe2.contentDocument.body.innerHTML, iframe2BodyInnerHTML,
  2621      "runForceCommitTest: the editable document has the committed text? #8");
  2623   // Make the composition in an editable document commit by click in it
  2624   iframe2.contentWindow.focus();
  2625   iframe2.contentDocument.body.innerHTML = "Text in the Body";
  2626   iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  2628   synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  2630   synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  2631   synthesizeText(
  2632     { "composition":
  2633       { "string": "\u306E",
  2634         "clauses":
  2636           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2638       },
  2639       "caret": { "start": 1, "length": 0 }
  2640     }, iframe2.contentWindow);
  2642   events = [];
  2643   synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
  2645   is(events.length, 3,
  2646      "runForceCommitTest: wrong event count #9");
  2647   is(events[0].type, "text",
  2648      "runForceCommitTest: the 1st event must be text #9");
  2649   is(events[1].type, "compositionend",
  2650      "runForceCommitTest: the 2nd event must be compositionend #9");
  2651   is(events[2].type, "input",
  2652      "runForceCommitTest: the 3rd event must be input #9");
  2653   is(events[1].data, "\u306E",
  2654      "runForceCommitTest: compositionend has wrong data #9");
  2655   is(events[0].target, iframe2.contentDocument.body,
  2656      "runForceCommitTest: The 1st event was fired on wrong event target #9");
  2657   is(events[1].target, iframe2.contentDocument.body,
  2658      "runForceCommitTest: The 2nd event was fired on wrong event target #9");
  2659   is(events[2].target, iframe2.contentDocument.body,
  2660      "runForceCommitTest: The 3rd event was fired on wrong event target #9");
  2661   ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  2662      "runForceCommitTest: the editable document still has composition #9");
  2663   ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  2664      iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  2665      "runForceCommitTest: the editable document doesn't have the committed text #9");
  2667   // Make the composition in an editable document commit by click in another document's editor
  2668   textarea.value = "";
  2669   iframe2.contentWindow.focus();
  2670   iframe2.contentDocument.body.innerHTML = "Text in the Body";
  2671   iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  2673   synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  2675   synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  2676   synthesizeText(
  2677     { "composition":
  2678       { "string": "\u306E",
  2679         "clauses":
  2681           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2683       },
  2684       "caret": { "start": 1, "length": 0 }
  2685     }, iframe2.contentWindow);
  2687   events = [];
  2688   synthesizeMouseAtCenter(textarea, {});
  2690   is(events.length, 3,
  2691      "runForceCommitTest: wrong event count #10");
  2692   is(events[0].type, "text",
  2693      "runForceCommitTest: the 1st event must be text #10");
  2694   is(events[1].type, "compositionend",
  2695      "runForceCommitTest: the 2nd event must be compositionend #10");
  2696   is(events[2].type, "input",
  2697      "runForceCommitTest: the 3rd event must be input #10");
  2698   is(events[1].data, "\u306E",
  2699      "runForceCommitTest: compositionend has wrong data #10");
  2700   is(events[0].target, iframe2.contentDocument.body,
  2701      "runForceCommitTest: The 1st event was fired on wrong event target #10");
  2702   is(events[1].target, iframe2.contentDocument.body,
  2703      "runForceCommitTest: The 2nd event was fired on wrong event target #10");
  2704   is(events[2].target, iframe2.contentDocument.body,
  2705      "runForceCommitTest: The 3rd event was fired on wrong event target #10");
  2706   ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  2707      "runForceCommitTest: the editable document still has composition #10");
  2708   ok(!getEditorIMESupport(textarea).isComposing,
  2709      "runForceCommitTest: the textarea has composition #10");
  2710   ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  2711      iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  2712      "runForceCommitTest: the editable document doesn't have the committed text #10");
  2713   is(textarea.value, "",
  2714      "runForceCommitTest: the textarea has the committed text? #10");
  2716   // Make the composition in an editable document commit by click in the another editable document
  2717   iframe2.contentWindow.focus();
  2718   iframe2.contentDocument.body.innerHTML = "Text in the Body";
  2719   iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  2720   iframe3.contentDocument.body.innerHTML = "Text in the Body";
  2721   iframe3BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  2723   synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  2725   synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  2726   synthesizeText(
  2727     { "composition":
  2728       { "string": "\u306E",
  2729         "clauses":
  2731           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2733       },
  2734       "caret": { "start": 1, "length": 0 }
  2735     }, iframe2.contentWindow);
  2737   events = [];
  2738   synthesizeMouseAtCenter(iframe3.contentDocument.body, {}, iframe3.contentWindow);
  2740   is(events.length, 3,
  2741      "runForceCommitTest: wrong event count #11");
  2742   is(events[0].type, "text",
  2743      "runForceCommitTest: the 1st event must be text #11");
  2744   is(events[1].type, "compositionend",
  2745      "runForceCommitTest: the 2nd event must be compositionend #11");
  2746   is(events[2].type, "input",
  2747      "runForceCommitTest: the 3rd event must be input #11");
  2748   is(events[1].data, "\u306E",
  2749      "runForceCommitTest: compositionend has wrong data #11");
  2750   is(events[0].target, iframe2.contentDocument.body,
  2751      "runForceCommitTest: The 1st event was fired on wrong event target #11");
  2752   is(events[1].target, iframe2.contentDocument.body,
  2753      "runForceCommitTest: The 2nd event was fired on wrong event target #11");
  2754   is(events[2].target, iframe2.contentDocument.body,
  2755      "runForceCommitTest: The 3rd event was fired on wrong event target #11");
  2756   ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  2757      "runForceCommitTest: the editable document still has composition #11");
  2758   ok(!getHTMLEditorIMESupport(iframe3.contentWindow).isComposing,
  2759      "runForceCommitTest: the other editable document has composition #11");
  2760   ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  2761      iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  2762      "runForceCommitTest: the editable document doesn't have the committed text #11");
  2763   is(iframe3.contentDocument.body.innerHTML, iframe3BodyInnerHTML,
  2764      "runForceCommitTest: the other editable document has the committed text? #11");
  2766   window.removeEventListener("compositionstart", eventHandler, true);
  2767   window.removeEventListener("compositionupdate", eventHandler, true);
  2768   window.removeEventListener("compositionend", eventHandler, true);
  2769   window.removeEventListener("input", eventHandler, true);
  2770   window.removeEventListener("text", eventHandler, true);
  2773 function runBug811755Test()
  2775   iframe2.contentDocument.body.innerHTML = "<div>content<br/></div>";
  2776   iframe2.contentWindow.focus();
  2777   // Query everything
  2778   var textContent = synthesizeQueryTextContent(0, 10);
  2779   if (!checkQueryContentResult(textContent, "runBug811755Test: synthesizeQueryTextContent #1")) {
  2780     return false;
  2782   // Query everything but specify exact end offset, which should be immediately after the <br> node
  2783   // If PreContentIterator is used, the next node after <br> is the node after </div>.
  2784   // If ContentIterator is used, the next node is the <div> node itself. In this case, the end
  2785   // node ends up being before the start node, and an empty string is returned.
  2786   var queryContent = synthesizeQueryTextContent(0, textContent.text.length);
  2787   if (!checkQueryContentResult(queryContent, "runBug811755Test: synthesizeQueryTextContent #2")) {
  2788     return false;
  2790   is(queryContent.text, textContent.text, "runBug811755Test: two queried texts don't match");
  2791   return queryContent.text == textContent.text;
  2794 function runIsComposingTest()
  2796   var expectedIsComposing = false;
  2797   var descriptionBase = "runIsComposingTest: ";
  2798   var description = "";
  2800   function eventHandler(aEvent)
  2802     if (aEvent.type == "keydown" || aEvent.type == "keyup") {
  2803       is(aEvent.isComposing, expectedIsComposing,
  2804          "runIsComposingTest: " + description + " (type=" + aEvent.type + ", key=" + aEvent.key + ")");
  2805     } else {
  2806       is(aEvent.isComposing, expectedIsComposing,
  2807          "runIsComposingTest: " + description + " (type=" + aEvent.type + ")");
  2811   textarea.addEventListener("keydown", eventHandler, true);
  2812   textarea.addEventListener("keypress", eventHandler, true);
  2813   textarea.addEventListener("keyup", eventHandler, true);
  2814   textarea.addEventListener("input", eventHandler, true);
  2816   textarea.focus();
  2817   textarea.value = "";
  2819   // XXX These cases shouldn't occur in actual native key events because we
  2820   //     don't dispatch key events while composition (bug 354358).
  2821   expectedIsComposing = false;
  2822   description = "events before dispatching compositionstart";
  2823   synthesizeKey("VK_LEFT", {});
  2825   synthesizeKey("a", { type: "keydown" });
  2826   synthesizeComposition({ type: "compositionstart" });
  2827   expectedIsComposing = true;
  2828   description = "events after dispatching compositionstart";
  2829   synthesizeComposition({ type: "compositionupdate", data: "\u3042" });
  2830   synthesizeText(
  2831     { "composition":
  2832       { "string": "\u3042",
  2833         "clauses":
  2835           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2837       },
  2838       "caret": { "start": 1, "length": 0 }
  2839     });
  2840   synthesizeKey("a", { type: "keyup" });
  2842   // Although, firing keypress event during composition is a bug.
  2843   synthesizeKey("VK_INSERT", {});
  2845   description = "events for committing composition string";
  2846   synthesizeKey("VK_RETURN", { type: "keydown" });
  2847   synthesizeText(
  2848     { "composition":
  2849       { "string": "\u3042",
  2850         "clauses":
  2852           { "length": 0, "attr": 0 }
  2854       },
  2855       "caret": { "start": 1, "length": 0 }
  2856     });
  2858   // input event will be fired by synthesizing compositionend event.
  2859   // Then, its isComposing should be false.
  2860   expectedIsComposing = false;
  2861   description = "events after dispatching compositionend";
  2862   synthesizeComposition({ type: "compositionend" });
  2863   synthesizeKey("VK_RETURN", { type: "keyup" });
  2865   textarea.removeEventListener("keydown", eventHandler, true);
  2866   textarea.removeEventListener("keypress", eventHandler, true);
  2867   textarea.removeEventListener("keyup", eventHandler, true);
  2868   textarea.removeEventListener("input", eventHandler, true);
  2870   textarea.value = "";
  2873 function runRemoveContentTest(aCallback)
  2875   var events = [];
  2876   function eventHandler(aEvent)
  2878     events.push(aEvent);
  2880   textarea.addEventListener("compositionstart", eventHandler, true);
  2881   textarea.addEventListener("compositionupdate", eventHandler, true);
  2882   textarea.addEventListener("compositionend", eventHandler, true);
  2883   textarea.addEventListener("input", eventHandler, true);
  2884   textarea.addEventListener("text", eventHandler, true);
  2886   textarea.focus();
  2887   textarea.value = "";
  2889   synthesizeComposition({ type: "compositionstart" });
  2891   synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  2892   synthesizeText(
  2893     { "composition":
  2894       { "string": "\u306E",
  2895         "clauses":
  2897           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  2899       },
  2900       "caret": { "start": 1, "length": 0 }
  2901     });
  2903   var nextSibling = textarea.nextSibling;
  2904   var parent = textarea.parentElement;
  2906   events = [];
  2907   parent.removeChild(textarea);
  2909   hitEventLoop(function () {
  2910     // XXX Currently, "input" event isn't fired on removed content.
  2911     is(events.length, 3,
  2912        "runRemoveContentTest: wrong event count #1");
  2913     is(events[0].type, "compositionupdate",
  2914        "runRemoveContentTest: the 1st event must be compositionupdate #1");
  2915     is(events[1].type, "text",
  2916        "runRemoveContentTest: the 2nd event must be text #1");
  2917     is(events[2].type, "compositionend",
  2918        "runRemoveContentTest: the 3rd event must be compositionend #1");
  2919     is(events[0].data, "",
  2920        "runRemoveContentTest: compositionupdate has wrong data #1");
  2921     is(events[2].data, "",
  2922        "runRemoveContentTest: compositionend has wrong data #1");
  2923     is(events[0].target, textarea,
  2924        "runRemoveContentTest: The 1st event was fired on wrong event target #1");
  2925     is(events[1].target, textarea,
  2926        "runRemoveContentTest: The 2nd event was fired on wrong event target #1");
  2927     is(events[2].target, textarea,
  2928        "runRemoveContentTest: The 3rd event was fired on wrong event target #1");
  2929     ok(!getEditorIMESupport(textarea).isComposing,
  2930        "runRemoveContentTest: the textarea still has composition #1");
  2931     todo_is(textarea.value, "",
  2932        "runRemoveContentTest: the textarea has the committed text? #1");
  2934     parent.insertBefore(textarea, nextSibling);
  2936     textarea.focus();
  2937     textarea.value = "";
  2939     synthesizeComposition({ type: "compositionstart" });
  2941     events = [];
  2942     parent.removeChild(textarea);
  2944     hitEventLoop(function () {
  2945       // XXX Currently, "input" event isn't fired on removed content.
  2946       is(events.length, 1,
  2947          "runRemoveContentTest: wrong event count #2");
  2948       is(events[0].type, "compositionend",
  2949          "runRemoveContentTest: the 1st event must be compositionend #2");
  2950       is(events[0].data, "",
  2951          "runRemoveContentTest: compositionupdate has wrong data #2");
  2952       is(events[0].target, textarea,
  2953          "runRemoveContentTest: The 1st event was fired on wrong event target #2");
  2954       ok(!getEditorIMESupport(textarea).isComposing,
  2955          "runRemoveContentTest: the textarea still has composition #2");
  2956       is(textarea.value, "",
  2957          "runRemoveContentTest: the textarea has the committed text? #2");
  2959       parent.insertBefore(textarea, nextSibling);
  2961       textarea.removeEventListener("compositionstart", eventHandler, true);
  2962       textarea.removeEventListener("compositionupdate", eventHandler, true);
  2963       textarea.removeEventListener("compositionend", eventHandler, true);
  2964       textarea.removeEventListener("input", eventHandler, true);
  2965       textarea.removeEventListener("text", eventHandler, true);
  2967       SimpleTest.executeSoon(aCallback);
  2968     }, 50);
  2969   }, 50);
  2972 function runTestOnAnotherContext(aPanelOrFrame, aFocusedEditor, aTestName)
  2974   aFocusedEditor.value = "";
  2976   var editorRect = synthesizeQueryEditorRect();
  2977   if (!checkQueryContentResult(editorRect, aTestName + ": editorRect")) {
  2978     return;
  2981   var r = aPanelOrFrame.getBoundingClientRect();
  2982   var parentRect = { "left": r.left, "top": r.top, "width": r.right - r.left,
  2983                      "height": r.bottom - r.top };
  2984   checkRectContainsRect(editorRect, parentRect, aTestName +
  2985                         ": the editor rect coordinates are wrong");
  2987   // start composition
  2988   synthesizeComposition({ type: "compositionstart" });
  2990   // input characters
  2991   synthesizeComposition({ type: "compositionupdate",
  2992                           data: "\u3078\u3093\u3057\u3093" });
  2993   synthesizeText(
  2994     { "composition":
  2995       { "string": "\u3078\u3093\u3057\u3093",
  2996         "clauses":
  2998           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  3000       },
  3001       "caret": { "start": 4, "length": 0 }
  3002     });
  3004   if (!checkContent("\u3078\u3093\u3057\u3093", aTestName, "#1-1") ||
  3005       !checkSelection(4, "", aTestName, "#1-1")) {
  3006     return;
  3009   // convert them #1
  3010   synthesizeComposition({ type: "compositionupdate", data: "\u8FD4\u4FE1" });
  3011   synthesizeText(
  3012     { "composition":
  3013       { "string": "\u8FD4\u4FE1",
  3014         "clauses":
  3016           { "length": 2,
  3017             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
  3019       },
  3020       "caret": { "start": 2, "length": 0 }
  3021     });
  3023   if (!checkContent("\u8FD4\u4FE1", aTestName, "#1-2") ||
  3024       !checkSelection(2, "", aTestName, "#1-2")) {
  3025     return;
  3028   // convert them #2
  3029   synthesizeComposition({ type: "compositionupdate", data: "\u5909\u8EAB" });
  3030   synthesizeText(
  3031     { "composition":
  3032       { "string": "\u5909\u8EAB",
  3033         "clauses":
  3035           { "length": 2,
  3036             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
  3038       },
  3039       "caret": { "start": 2, "length": 0 }
  3040     });
  3042   if (!checkContent("\u5909\u8EAB", aTestName, "#1-3") ||
  3043       !checkSelection(2, "", aTestName, "#1-3")) {
  3044     return;
  3047   // commit them
  3048   synthesizeText(
  3049     { "composition":
  3050       { "string": "\u5909\u8EAB",
  3051         "clauses":
  3053           { "length": 0, "attr": 0 }
  3055       },
  3056       "caret": { "start": 2, "length": 0 }
  3057     });
  3059   if (!checkContent("\u5909\u8EAB", aTestName, "#1-4") ||
  3060       !checkSelection(2, "", aTestName, "#1-4")) {
  3061     return;
  3064   synthesizeComposition({ type: "compositionend", data: "\u5909\u8EAB" });
  3066   is(aFocusedEditor.value, "\u5909\u8EAB",
  3067      aTestName + ": composition isn't in the focused editor");
  3068   if (aFocusedEditor.value != "\u5909\u8EAB") {
  3069     return;
  3072   var textRect = synthesizeQueryTextRect(0, 1);
  3073   var caretRect = synthesizeQueryCaretRect(2);
  3074   if (!checkQueryContentResult(textRect,
  3075                                aTestName + ": synthesizeQueryTextRect") ||
  3076       !checkQueryContentResult(caretRect,
  3077                                aTestName + ": synthesizeQueryCaretRect")) {
  3078     return;
  3080   checkRectContainsRect(textRect, editorRect, aTestName + ":testRect");
  3081   checkRectContainsRect(caretRect, editorRect, aTestName + ":caretRect");
  3084 function runFrameTest()
  3086   textareaInFrame.focus();
  3087   runTestOnAnotherContext(iframe, textareaInFrame, "runFrameTest");
  3088   runCharAtPointTest(textareaInFrame, "textarea in the iframe");
  3091 var gPanelShown = false;
  3092 var gPanelFocused = false;
  3093 function onPanelShown(aEvent)
  3095   gPanelShown = true;
  3096   textbox.focus();
  3097   setTimeout(doPanelTest, 0);
  3100 function onFocusPanelTextbox(aEvent)
  3102   gPanelFocused = true;
  3103   setTimeout(doPanelTest, 0);
  3106 var gIsPanelHiding = false;
  3107 var gIsRunPanelTestInternal = false;
  3108 function doPanelTest()
  3110   if (!gPanelFocused || !gPanelShown) {
  3111     return;
  3113   if (gIsRunPanelTestInternal) {
  3114     return;
  3116   gIsRunPanelTestInternal = true;
  3117   runTestOnAnotherContext(panel, textbox, "runPanelTest");
  3118   runCharAtPointTest(textbox, "textbox in the panel");
  3119   gIsPanelHiding = true;
  3120   panel.hidePopup();
  3123 function onPanelHidden(aEvent)
  3125   panel.hidden = true;
  3126   ok(gIsPanelHiding, "runPanelTest: the panel is hidden unexpectedly");
  3127   finish();
  3130 function runPanelTest()
  3132   panel.hidden = false;
  3133   panel.openPopupAtScreen(window.screenX + window.outerWidth, 0, false);
  3136 function runMaxLengthTest()
  3138   input.maxLength = 1;
  3139   input.value = "";
  3140   input.focus();
  3142   var kDesc ="runMaxLengthTest";
  3144   // start composition
  3145   synthesizeComposition({ type: "compositionstart" });
  3147   // input first character
  3148   synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  3149   synthesizeText(
  3150     { "composition":
  3151       { "string": "\u3089",
  3152         "clauses":
  3154           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  3156       },
  3157       "caret": { "start": 1, "length": 0 }
  3158     });
  3160   if (!checkContent("\u3089", kDesc, "#1-1") ||
  3161       !checkSelection(1, "", kDesc, "#1-1")) {
  3162     return;
  3165   // input second character
  3166   synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
  3167   synthesizeText(
  3168     { "composition":
  3169       { "string": "\u3089\u30FC",
  3170         "clauses":
  3172           { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  3174       },
  3175       "caret": { "start": 2, "length": 0 }
  3176     });
  3178   if (!checkContent("\u3089\u30FC", kDesc, "#1-2") ||
  3179       !checkSelection(2, "", kDesc, "#1-2")) {
  3180     return;
  3183   // input third character
  3184   synthesizeComposition({ type: "compositionupdate",
  3185                           data: "\u3089\u30FC\u3081" });
  3186   synthesizeText(
  3187     { "composition":
  3188       { "string": "\u3089\u30FC\u3081",
  3189         "clauses":
  3191           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  3193       },
  3194       "caret": { "start": 3, "length": 0 }
  3195     });
  3197   if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-3") ||
  3198       !checkSelection(3, "", kDesc, "#1-3")) {
  3199     return;
  3202   // input fourth character
  3203   synthesizeComposition({ type: "compositionupdate",
  3204                           data: "\u3089\u30FC\u3081\u3093" });
  3205   synthesizeText(
  3206     { "composition":
  3207       { "string": "\u3089\u30FC\u3081\u3093",
  3208         "clauses":
  3210           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  3212       },
  3213       "caret": { "start": 4, "length": 0 }
  3214     });
  3216   if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-4") ||
  3217       !checkSelection(4, "", kDesc, "#1-4")) {
  3218     return;
  3222   // backspace
  3223   synthesizeComposition({ type: "compositionupdate",
  3224                           data: "\u3089\u30FC\u3081" });
  3225   synthesizeText(
  3226     { "composition":
  3227       { "string": "\u3089\u30FC\u3081",
  3228         "clauses":
  3230           { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  3232       },
  3233       "caret": { "start": 3, "length": 0 }
  3234     });
  3236   if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-5") ||
  3237       !checkSelection(3, "", kDesc, "#1-5")) {
  3238     return;
  3241   // re-input
  3242   synthesizeComposition({ type: "compositionupdate",
  3243                           data: "\u3089\u30FC\u3081\u3093" });
  3244   synthesizeText(
  3245     { "composition":
  3246       { "string": "\u3089\u30FC\u3081\u3093",
  3247         "clauses":
  3249           { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  3251       },
  3252       "caret": { "start": 4, "length": 0 }
  3253     });
  3255   if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-6") ||
  3256       !checkSelection(4, "", kDesc, "#1-6")) {
  3257     return;
  3260   synthesizeComposition({ type: "compositionupdate",
  3261                           data: "\u3089\u30FC\u3081\u3093\u3055" });
  3262   synthesizeText(
  3263     { "composition":
  3264       { "string": "\u3089\u30FC\u3081\u3093\u3055",
  3265         "clauses":
  3267           { "length": 5, "attr": COMPOSITION_ATTR_RAWINPUT }
  3269       },
  3270       "caret": { "start": 5, "length": 0 }
  3271     });
  3273   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", kDesc, "#1-7") ||
  3274       !checkSelection(5, "", kDesc, "#1-7")) {
  3275     return;
  3278   synthesizeComposition({ type: "compositionupdate",
  3279                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
  3280   synthesizeText(
  3281     { "composition":
  3282       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
  3283         "clauses":
  3285           { "length": 6, "attr": COMPOSITION_ATTR_RAWINPUT }
  3287       },
  3288       "caret": { "start": 6, "length": 0 }
  3289     });
  3291   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", kDesc, "#1-8") ||
  3292       !checkSelection(6, "", kDesc, "#1-8")) {
  3293     return;
  3296   synthesizeComposition({ type: "compositionupdate",
  3297                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
  3298   synthesizeText(
  3299     { "composition":
  3300       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
  3301         "clauses":
  3303           { "length": 7, "attr": COMPOSITION_ATTR_RAWINPUT }
  3305       },
  3306       "caret": { "start": 7, "length": 0 }
  3307     });
  3309   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
  3310                     kDesc, "#1-8") ||
  3311       !checkSelection(7, "", kDesc, "#1-8")) {
  3312     return;
  3315   synthesizeComposition({ type: "compositionupdate",
  3316                           data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
  3317   synthesizeText(
  3318     { "composition":
  3319       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
  3320         "clauses":
  3322           { "length": 8, "attr": COMPOSITION_ATTR_RAWINPUT }
  3324       },
  3325       "caret": { "start": 8, "length": 0 }
  3326     });
  3328   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
  3329                     kDesc, "#1-9") ||
  3330       !checkSelection(8, "", kDesc, "#1-9")) {
  3331     return;
  3334   // convert
  3335   synthesizeComposition({ type: "compositionupdate",
  3336                           data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
  3337   synthesizeText(
  3338     { "composition":
  3339       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
  3340         "clauses":
  3342           { "length": 4,
  3343             "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
  3344           { "length": 2,
  3345             "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
  3347       },
  3348       "caret": { "start": 4, "length": 0 }
  3349     });
  3351   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8", kDesc, "#1-10") ||
  3352       !checkSelection(4, "", kDesc, "#1-10")) {
  3353     return;
  3356   // commit the composition string
  3357   synthesizeText(
  3358     { "composition":
  3359       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
  3360         "clauses":
  3362           { "length": 0, "attr": 0 }
  3364       },
  3365       "caret": { "start": 6, "length": 0 }
  3366     });
  3368   if (!checkContent("\u30E9", kDesc, "#1-11") ||
  3369       !checkSelection(1, "", kDesc, "#1-11")) {
  3370     return;
  3373   synthesizeComposition({ type: "compositionend",
  3374                           data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
  3376   // restart composition
  3377   synthesizeComposition({ type: "compositionstart" });
  3379   // input characters
  3380   synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
  3381   synthesizeText(
  3382     { "composition":
  3383       { "string": "\u3057",
  3384         "clauses":
  3386           { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  3388       },
  3389       "caret": { "start": 1, "length": 0 }
  3390     });
  3392   if (!checkContent("\u30E9\u3057", kDesc, "#2-1") ||
  3393       !checkSelection(1 + 1, "", kDesc, "#2-1")) {
  3394     return;
  3397   // commit the composition string
  3398   synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
  3399   synthesizeText(
  3400     { "composition":
  3401       { "string": "\u3058",
  3402         "clauses":
  3404           { "length": 0, "attr": 0 }
  3406       },
  3407       "caret": { "start": 1, "length": 0 }
  3408     });
  3410   if (!checkContent("\u30E9", kDesc, "#2-2") ||
  3411       !checkSelection(1 + 0, "", kDesc, "#2-2")) {
  3412     return;
  3415   synthesizeComposition({ type: "compositionend", data: "\u3058" });
  3417   // Undo
  3418   synthesizeKey("Z", {accelKey: true});
  3420   // XXX this is unexpected behavior, see bug 258291
  3421   if (!checkContent("\u30E9", kDesc, "#3-1") ||
  3422       !checkSelection(1 + 0, "", kDesc, "#3-1")) {
  3423     return;
  3426   // Undo
  3427   synthesizeKey("Z", {accelKey: true});
  3428   if (!checkContent("", kDesc, "#3-2") ||
  3429       !checkSelection(0, "", kDesc, "#3-2")) {
  3430     return;
  3433   // Redo
  3434   synthesizeKey("Z", {accelKey: true, shiftKey: true});
  3435   if (!checkContent("\u30E9", kDesc, "#3-3") ||
  3436       !checkSelection(1, "", kDesc, "#3-3")) {
  3437     return;
  3440   // Redo
  3441   synthesizeKey("Z", {accelKey: true, shiftKey: true});
  3442   if (!checkContent("\u30E9", kDesc, "#3-4") ||
  3443       !checkSelection(1 + 0, "", kDesc, "#3-4")) {
  3444     return;
  3448 function runTest()
  3450   textareaInFrame = iframe.contentDocument.getElementById("textarea");
  3452   runUndoRedoTest();
  3453   runCompositionTest();
  3454   runCompositionEventTest();
  3455   runCharAtPointTest(textarea, "textarea in the document");
  3456   runCharAtPointAtOutsideTest();
  3457   runBug722639Test();
  3458   runForceCommitTest();
  3459   runBug811755Test();
  3460   runIsComposingTest();
  3461   runRemoveContentTest(function () {
  3462     runFrameTest();
  3463     runPanelTest();
  3464     runMaxLengthTest();
  3465   });
  3468 ]]>
  3469 </script>
  3471 </window>

mercurial