widget/tests/window_composition_text_querycontent.xul

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/tests/window_composition_text_querycontent.xul	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3471 @@
     1.4 +<?xml version="1.0"?>
     1.5 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     1.6 +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
     1.7 +                 type="text/css"?>
     1.8 +<window title="Testing composition, text and query content events"
     1.9 +  xmlns:html="http://www.w3.org/1999/xhtml"
    1.10 +  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    1.11 +  onunload="onunload();">
    1.12 +
    1.13 +  <script type="application/javascript"
    1.14 +          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
    1.15 +  <script type="application/javascript"
    1.16 +          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
    1.17 +  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
    1.18 +
    1.19 +  <panel id="panel" hidden="true"
    1.20 +         orient="vertical"
    1.21 +         onpopupshown="onPanelShown(event);"
    1.22 +         onpopuphidden="onPanelHidden(event);">
    1.23 +    <vbox id="vbox">
    1.24 +      <textbox id="textbox" onfocus="onFocusPanelTextbox(event);"
    1.25 +               multiline="true" cols="20" rows="4"/>
    1.26 +    </vbox>
    1.27 +  </panel>
    1.28 +
    1.29 +<body  xmlns="http://www.w3.org/1999/xhtml">
    1.30 +<p id="display">
    1.31 +<div id="div" style="margin: 0; padding: 0; font-size: 24px;">Here is a text frame.</div>
    1.32 +<textarea style="margin: 0;" id="textarea" cols="20" rows="4"></textarea><br/>
    1.33 +<iframe id="iframe" width="300" height="150"
    1.34 +        src="data:text/html,&lt;textarea id='textarea' cols='20' rows='4'&gt;&lt;/textarea&gt;"></iframe><br/>
    1.35 +<iframe id="iframe2" width="300" height="150"
    1.36 +        src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
    1.37 +<iframe id="iframe3" width="300" height="150"
    1.38 +        src="data:text/html,&lt;body onload='document.designMode=%22on%22'&gt;body content&lt;/body&gt;"></iframe><br/>
    1.39 +<input id="input" type="text"/><br/>
    1.40 +</p>
    1.41 +<div id="content" style="display: none">
    1.42 +  
    1.43 +</div>
    1.44 +<pre id="test">
    1.45 +</pre>
    1.46 +</body>
    1.47 +
    1.48 +<script class="testbody" type="application/javascript">
    1.49 +<![CDATA[
    1.50 +
    1.51 +window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
    1.52 +
    1.53 +function ok(aCondition, aMessage)
    1.54 +{
    1.55 +  window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
    1.56 +}
    1.57 +
    1.58 +function is(aLeft, aRight, aMessage)
    1.59 +{
    1.60 +  window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
    1.61 +}
    1.62 +
    1.63 +function isnot(aLeft, aRight, aMessage)
    1.64 +{
    1.65 +  window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
    1.66 +}
    1.67 +
    1.68 +function finish()
    1.69 +{
    1.70 +  window.close();
    1.71 +}
    1.72 +
    1.73 +function onunload()
    1.74 +{
    1.75 +  window.opener.wrappedJSObject.SimpleTest.finish();
    1.76 +}
    1.77 +
    1.78 +var div = document.getElementById("div");
    1.79 +var textarea = document.getElementById("textarea");
    1.80 +var panel = document.getElementById("panel");
    1.81 +var textbox = document.getElementById("textbox");
    1.82 +var iframe = document.getElementById("iframe");
    1.83 +var iframe2 = document.getElementById("iframe2");
    1.84 +var iframe3 = document.getElementById("iframe3");
    1.85 +var input = document.getElementById("input");
    1.86 +var textareaInFrame;
    1.87 +
    1.88 +const nsIDOMNSEditableElement = Components.interfaces.nsIDOMNSEditableElement;
    1.89 +const nsIEditorIMESupport = Components.interfaces.nsIEditorIMESupport;
    1.90 +const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
    1.91 +const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
    1.92 +const nsIDocShell = Components.interfaces.nsIDocShell;
    1.93 +
    1.94 +function hitEventLoop(aFunc, aTimes)
    1.95 +{
    1.96 +  if (--aTimes) {
    1.97 +    setTimeout(hitEventLoop, 0, aFunc, aTimes);
    1.98 +  } else {
    1.99 +    setTimeout(aFunc, 20);
   1.100 +  }
   1.101 +}
   1.102 +
   1.103 +function getEditorIMESupport(aNode)
   1.104 +{
   1.105 +  return aNode.QueryInterface(nsIDOMNSEditableElement).
   1.106 +               editor.
   1.107 +               QueryInterface(nsIEditorIMESupport);
   1.108 +}
   1.109 +
   1.110 +function getHTMLEditorIMESupport(aWindow)
   1.111 +{
   1.112 +  return aWindow.QueryInterface(nsIInterfaceRequestor).
   1.113 +                 getInterface(nsIWebNavigation).
   1.114 +                 QueryInterface(nsIDocShell).
   1.115 +                 editor;
   1.116 +}
   1.117 +
   1.118 +const kIsWin = (navigator.platform.indexOf("Win") == 0);
   1.119 +const kIsMac = (navigator.platform.indexOf("Mac") == 0);
   1.120 +
   1.121 +const kLFLen = kIsWin ? 2 : 1;
   1.122 +
   1.123 +function checkQueryContentResult(aResult, aMessage)
   1.124 +{
   1.125 +  ok(aResult, aMessage + ": the result is null");
   1.126 +  if (!aResult) {
   1.127 +    return false;
   1.128 +  }
   1.129 +  ok(aResult.succeeded, aMessage + ": the query content failed");
   1.130 +  return aResult.succeeded;
   1.131 +}
   1.132 +
   1.133 +function checkContent(aExpectedText, aMessage, aID)
   1.134 +{
   1.135 +  var textContent = synthesizeQueryTextContent(0, 100);
   1.136 +  if (!checkQueryContentResult(textContent, aMessage +
   1.137 +                               ": synthesizeQueryTextContent " + aID)) {
   1.138 +    return false;
   1.139 +  }
   1.140 +  is(textContent.text, aExpectedText,
   1.141 +     aMessage + ": composition string is wrong" + aID);
   1.142 +  return textContent.text == aExpectedText;
   1.143 +}
   1.144 +
   1.145 +function checkSelection(aExpectedOffset, aExpectedText, aMessage, aID)
   1.146 +{
   1.147 +  var selectedText = synthesizeQuerySelectedText();
   1.148 +  if (!checkQueryContentResult(selectedText, aMessage +
   1.149 +                               ": synthesizeQuerySelectedText " + aID)) {
   1.150 +    return false;
   1.151 +  }
   1.152 +  is(selectedText.offset, aExpectedOffset,
   1.153 +     aMessage + ": selection offset is wrong" + aID);
   1.154 +  is(selectedText.text, aExpectedText,
   1.155 +     aMessage + ": selected text is wrong" + aID);
   1.156 +  return selectedText.offset == aExpectedOffset &&
   1.157 +         selectedText.text == aExpectedText;
   1.158 +}
   1.159 +
   1.160 +function checkRect(aRect, aExpectedRect, aMessage)
   1.161 +{
   1.162 +  is(aRect.left, aExpectedRect.left, aMessage + ": left is wrong");
   1.163 +  is(aRect.top, aExpectedRect.top, aMessage + " top is wrong");
   1.164 +  is(aRect.width, aExpectedRect.width, aMessage + ": width is wrong");
   1.165 +  is(aRect.height, aExpectedRect.height, aMessage + ": height is wrong");
   1.166 +  return aRect.left == aExpectedRect.left &&
   1.167 +         aRect.top == aExpectedRect.top &&
   1.168 +         aRect.width == aExpectedRect.width &&
   1.169 +         aRect.height == aExpectedRect.height;
   1.170 +}
   1.171 +
   1.172 +function checkRectContainsRect(aRect, aContainer, aMessage)
   1.173 +{
   1.174 +  var container = { left: Math.ceil(aContainer.left),
   1.175 +                    top:  Math.ceil(aContainer.top),
   1.176 +                    width: Math.floor(aContainer.width),
   1.177 +                    height: Math.floor(aContainer.height) };
   1.178 +
   1.179 +  var ret = container.left <= aRect.left &&
   1.180 +            container.top <= aRect.top &&
   1.181 +            container.left + container.width >= aRect.left + aRect.width &&
   1.182 +            container.top + container.height >= aRect.top + aRect.height;
   1.183 +  ret = ret && aMessage;
   1.184 +  ok(ret, aMessage + " container={ left=" + container.left + ", top=" +
   1.185 +     container.top + ", width=" + container.width + ", height=" +
   1.186 +     container.height + " } rect={ left=" + aRect.left + ", top=" + aRect.top +
   1.187 +     ", width=" + aRect.width + ", height=" + aRect.height + " }");
   1.188 +  return ret;
   1.189 +}
   1.190 +
   1.191 +function runUndoRedoTest()
   1.192 +{
   1.193 +  textarea.value = "";
   1.194 +  textarea.focus();
   1.195 +
   1.196 +  // start composition
   1.197 +  synthesizeComposition({ type: "compositionstart" });
   1.198 +
   1.199 +  // input raw characters
   1.200 +  synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
   1.201 +  synthesizeText(
   1.202 +    { "composition":
   1.203 +      { "string": "\u306D",
   1.204 +        "clauses":
   1.205 +        [
   1.206 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.207 +        ]
   1.208 +      },
   1.209 +      "caret": { "start": 1, "length": 0 }
   1.210 +    });
   1.211 +
   1.212 +  synthesizeComposition({ type: "compositionupdate", data: "\u306D\u3053" });
   1.213 +  synthesizeText(
   1.214 +    { "composition":
   1.215 +      { "string": "\u306D\u3053",
   1.216 +        "clauses":
   1.217 +        [
   1.218 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.219 +        ]
   1.220 +      },
   1.221 +      "caret": { "start": 2, "length": 0 }
   1.222 +    });
   1.223 +
   1.224 +  // convert
   1.225 +  synthesizeComposition({ type: "compositionupdate", data: "\u732B" });
   1.226 +  synthesizeText(
   1.227 +    { "composition":
   1.228 +      { "string": "\u732B",
   1.229 +        "clauses":
   1.230 +        [
   1.231 +          { "length": 1,
   1.232 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   1.233 +        ]
   1.234 +      },
   1.235 +      "caret": { "start": 1, "length": 0 }
   1.236 +    });
   1.237 +
   1.238 +  // commit
   1.239 +  synthesizeText(
   1.240 +    { "composition":
   1.241 +      { "string": "\u732B",
   1.242 +        "clauses":
   1.243 +        [
   1.244 +          { "length": 0, "attr": 0 }
   1.245 +        ]
   1.246 +      },
   1.247 +      "caret": { "start": 1, "length": 0 }
   1.248 +    });
   1.249 +
   1.250 +  // end composition
   1.251 +  synthesizeComposition({ type: "compositionend", data: "\u732B" });
   1.252 +
   1.253 +  // start composition
   1.254 +  synthesizeComposition({ type: "compositionstart" });
   1.255 +
   1.256 +  // input raw characters
   1.257 +  synthesizeComposition({ type: "compositionupdate", data: "\u307E" });
   1.258 +  synthesizeText(
   1.259 +    { "composition":
   1.260 +      { "string": "\u307E",
   1.261 +        "clauses":
   1.262 +        [
   1.263 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.264 +        ]
   1.265 +      },
   1.266 +      "caret": { "start": 1, "length": 0 }
   1.267 +    });
   1.268 +
   1.269 +  // cancel the composition
   1.270 +  synthesizeComposition({ type: "compositionupdate", data: "" });
   1.271 +  synthesizeText(
   1.272 +    { "composition":
   1.273 +      { "string": "",
   1.274 +        "clauses":
   1.275 +        [
   1.276 +          { "length": 0, "attr": 0 }
   1.277 +        ]
   1.278 +      },
   1.279 +      "caret": { "start": 0, "length": 0 }
   1.280 +    });
   1.281 +
   1.282 +  // end composition
   1.283 +  synthesizeComposition({ type: "compositionend", data: "" });
   1.284 +
   1.285 +  // start composition
   1.286 +  synthesizeComposition({ type: "compositionstart" });
   1.287 +
   1.288 +  // input raw characters
   1.289 +  synthesizeComposition({ type: "compositionupdate", data: "\u3080" });
   1.290 +  synthesizeText(
   1.291 +    { "composition":
   1.292 +      { "string": "\u3080",
   1.293 +        "clauses":
   1.294 +        [
   1.295 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.296 +        ]
   1.297 +      },
   1.298 +      "caret": { "start": 1, "length": 0 }
   1.299 +    });
   1.300 +
   1.301 +  synthesizeComposition({ type: "compositionupdate", data: "\u3080\u3059" });
   1.302 +  synthesizeText(
   1.303 +    { "composition":
   1.304 +      { "string": "\u3080\u3059",
   1.305 +        "clauses":
   1.306 +        [
   1.307 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.308 +        ]
   1.309 +      },
   1.310 +      "caret": { "start": 2, "length": 0 }
   1.311 +    });
   1.312 +
   1.313 +  synthesizeComposition({ type: "compositionupdate",
   1.314 +                          data: "\u3080\u3059\u3081" });
   1.315 +  synthesizeText(
   1.316 +    { "composition":
   1.317 +      { "string": "\u3080\u3059\u3081",
   1.318 +        "clauses":
   1.319 +        [
   1.320 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.321 +        ]
   1.322 +      },
   1.323 +      "caret": { "start": 3, "length": 0 }
   1.324 +    });
   1.325 +
   1.326 +  // convert
   1.327 +  synthesizeComposition({ type: "compositionupdate", data: "\u5A18" });
   1.328 +  synthesizeText(
   1.329 +    { "composition":
   1.330 +      { "string": "\u5A18",
   1.331 +        "clauses":
   1.332 +        [
   1.333 +          { "length": 1,
   1.334 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   1.335 +        ]
   1.336 +      },
   1.337 +      "caret": { "start": 1, "length": 0 }
   1.338 +    });
   1.339 +
   1.340 +  // commit
   1.341 +  synthesizeText(
   1.342 +    { "composition":
   1.343 +      { "string": "\u5A18",
   1.344 +        "clauses":
   1.345 +        [
   1.346 +          { "length": 0, "attr": 0 }
   1.347 +        ]
   1.348 +      },
   1.349 +      "caret": { "start": 1, "length": 0 }
   1.350 +    });
   1.351 +
   1.352 +  // end composition
   1.353 +  synthesizeComposition({ type: "compositionend", data: "\u5A18" });
   1.354 +
   1.355 +  synthesizeKey(" ", {});
   1.356 +  synthesizeKey("m", {});
   1.357 +  synthesizeKey("e", {});
   1.358 +  synthesizeKey("a", {});
   1.359 +  synthesizeKey("n", {});
   1.360 +  synthesizeKey("t", {});
   1.361 +  synthesizeKey("VK_BACK_SPACE", {});
   1.362 +  synthesizeKey("s", {});
   1.363 +  synthesizeKey(" ", {});
   1.364 +  synthesizeKey("\"", {});
   1.365 +  synthesizeKey("c", {});
   1.366 +  synthesizeKey("a", {});
   1.367 +  synthesizeKey("t", {});
   1.368 +  synthesizeKey("-", {});
   1.369 +  synthesizeKey("g", {});
   1.370 +  synthesizeKey("i", {});
   1.371 +  synthesizeKey("r", {});
   1.372 +  synthesizeKey("l", {});
   1.373 +  synthesizeKey("\"", {});
   1.374 +  synthesizeKey(".", {});
   1.375 +  synthesizeKey(" ", {});
   1.376 +  synthesizeKey("VK_SHIFT", { type: "keydown" });
   1.377 +  synthesizeKey("S", { shiftKey: true });
   1.378 +  synthesizeKey("VK_SHIFT", { type: "keyup" });
   1.379 +  synthesizeKey("h", {});
   1.380 +  synthesizeKey("e", {});
   1.381 +  synthesizeKey(" ", {});
   1.382 +  synthesizeKey("i", {});
   1.383 +  synthesizeKey("s", {});
   1.384 +  synthesizeKey(" ", {});
   1.385 +  synthesizeKey("a", {});
   1.386 +  synthesizeKey(" ", {});
   1.387 +
   1.388 +  // start composition
   1.389 +  synthesizeComposition({ type: "compositionstart" });
   1.390 +
   1.391 +  // input raw characters
   1.392 +  synthesizeComposition({ type: "compositionupdate", data: "\u3088" });
   1.393 +  synthesizeText(
   1.394 +    { "composition":
   1.395 +      { "string": "\u3088",
   1.396 +        "clauses":
   1.397 +        [
   1.398 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.399 +        ]
   1.400 +      },
   1.401 +      "caret": { "start": 1, "length": 0 }
   1.402 +    });
   1.403 +
   1.404 +  synthesizeComposition({ type: "compositionupdate", data: "\u3088\u3046" });
   1.405 +  synthesizeText(
   1.406 +    { "composition":
   1.407 +      { "string": "\u3088\u3046",
   1.408 +        "clauses":
   1.409 +        [
   1.410 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.411 +        ]
   1.412 +      },
   1.413 +      "caret": { "start": 2, "length": 0 }
   1.414 +    });
   1.415 +
   1.416 +  synthesizeComposition({ type: "compositionupdate",
   1.417 +                          data: "\u3088\u3046\u304b" });
   1.418 +  synthesizeText(
   1.419 +    { "composition":
   1.420 +      { "string": "\u3088\u3046\u304b",
   1.421 +        "clauses":
   1.422 +        [
   1.423 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.424 +        ]
   1.425 +      },
   1.426 +      "caret": { "start": 3, "length": 0 }
   1.427 +    });
   1.428 +
   1.429 +  synthesizeComposition({ type: "compositionupdate",
   1.430 +                          data: "\u3088\u3046\u304b\u3044" });
   1.431 +  synthesizeText(
   1.432 +    { "composition":
   1.433 +      { "string": "\u3088\u3046\u304b\u3044",
   1.434 +        "clauses":
   1.435 +        [
   1.436 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.437 +        ]
   1.438 +      },
   1.439 +      "caret": { "start": 4, "length": 0 }
   1.440 +    });
   1.441 +
   1.442 +  // convert
   1.443 +  synthesizeComposition({ type: "compositionupdate", data: "\u5996\u602a" });
   1.444 +  synthesizeText(
   1.445 +    { "composition":
   1.446 +      { "string": "\u5996\u602a",
   1.447 +        "clauses":
   1.448 +        [
   1.449 +          { "length": 2, "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   1.450 +        ]
   1.451 +      },
   1.452 +      "caret": { "start": 2, "length": 0 }
   1.453 +    });
   1.454 +
   1.455 +  // commit
   1.456 +  synthesizeText(
   1.457 +    { "composition":
   1.458 +      { "string": "\u5996\u602a",
   1.459 +        "clauses":
   1.460 +        [
   1.461 +          { "length": 0, "attr": 0 }
   1.462 +        ]
   1.463 +      },
   1.464 +      "caret": { "start": 2, "length": 0 }
   1.465 +    });
   1.466 +
   1.467 +  // end composition
   1.468 +  synthesizeComposition({ type: "compositionend", data: "\u5996\u602a" });
   1.469 +
   1.470 +  synthesizeKey("VK_BACK_SPACE", {});
   1.471 +  synthesizeKey("VK_BACK_SPACE", {});
   1.472 +  synthesizeKey("VK_BACK_SPACE", {});
   1.473 +  synthesizeKey("VK_BACK_SPACE", {});
   1.474 +  synthesizeKey("VK_BACK_SPACE", {});
   1.475 +  synthesizeKey("VK_BACK_SPACE", {});
   1.476 +  synthesizeKey("VK_BACK_SPACE", {});
   1.477 +  synthesizeKey("VK_BACK_SPACE", {});
   1.478 +  synthesizeKey("VK_BACK_SPACE", {});
   1.479 +  synthesizeKey("VK_BACK_SPACE", {});
   1.480 +  synthesizeKey("VK_BACK_SPACE", {});
   1.481 +  synthesizeKey("VK_BACK_SPACE", {});
   1.482 +
   1.483 +  var i = 0;
   1.484 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   1.485 +                    "runUndoRedoTest", "#" + ++i) ||
   1.486 +      !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   1.487 +    return;
   1.488 +  }
   1.489 +
   1.490 +  synthesizeKey("Z", {accelKey: true});
   1.491 +
   1.492 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a \u5996\u602A",
   1.493 +                    "runUndoRedoTest", "#" + ++i) ||
   1.494 +      !checkSelection(32, "", "runUndoRedoTest", "#" + i)) {
   1.495 +    return;
   1.496 +  }
   1.497 +
   1.498 +  synthesizeKey("Z", {accelKey: true});
   1.499 +
   1.500 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a ",
   1.501 +                    "runUndoRedoTest", "#" + ++i) ||
   1.502 +      !checkSelection(30, "", "runUndoRedoTest", "#" + i)) {
   1.503 +    return;
   1.504 +  }
   1.505 +
   1.506 +  synthesizeKey("Z", {accelKey: true});
   1.507 +
   1.508 +  if (!checkContent("\u732B\u5A18 mean",
   1.509 +                    "runUndoRedoTest", "#" + ++i) ||
   1.510 +      !checkSelection(7, "", "runUndoRedoTest", "#" + i)) {
   1.511 +    return;
   1.512 +  }
   1.513 +
   1.514 +  synthesizeKey("Z", {accelKey: true});
   1.515 +
   1.516 +  if (!checkContent("\u732B\u5A18 meant",
   1.517 +                    "runUndoRedoTest", "#" + ++i) ||
   1.518 +      !checkSelection(8, "", "runUndoRedoTest", "#" + i)) {
   1.519 +    return;
   1.520 +  }
   1.521 +
   1.522 +  synthesizeKey("Z", {accelKey: true});
   1.523 +
   1.524 +  if (!checkContent("\u732B\u5A18",
   1.525 +                    "runUndoRedoTest", "#" + ++i) ||
   1.526 +      !checkSelection(2, "", "runUndoRedoTest", "#" + i)) {
   1.527 +    return;
   1.528 +  }
   1.529 +
   1.530 +  synthesizeKey("Z", {accelKey: true});
   1.531 +
   1.532 +  if (!checkContent("\u732B",
   1.533 +                    "runUndoRedoTest", "#" + ++i) ||
   1.534 +      !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   1.535 +    return;
   1.536 +  }
   1.537 +
   1.538 +  synthesizeKey("Z", {accelKey: true});
   1.539 +
   1.540 +  // XXX this is unexpected behavior, see bug 258291
   1.541 +  if (!checkContent("\u732B",
   1.542 +                    "runUndoRedoTest", "#" + ++i) ||
   1.543 +      !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   1.544 +    return;
   1.545 +  }
   1.546 +
   1.547 +  synthesizeKey("Z", {accelKey: true});
   1.548 +
   1.549 +  if (!checkContent("",
   1.550 +                    "runUndoRedoTest", "#" + ++i) ||
   1.551 +      !checkSelection(0, "", "runUndoRedoTest", "#" + i)) {
   1.552 +    return;
   1.553 +  }
   1.554 +
   1.555 +  synthesizeKey("Z", {accelKey: true});
   1.556 +
   1.557 +  if (!checkContent("",
   1.558 +                    "runUndoRedoTest", "#" + ++i) ||
   1.559 +      !checkSelection(0, "", "runUndoRedoTest", "#" + i)) {
   1.560 +    return;
   1.561 +  }
   1.562 +
   1.563 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.564 +
   1.565 +  if (!checkContent("\u732B",
   1.566 +                    "runUndoRedoTest", "#" + ++i) ||
   1.567 +      !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   1.568 +    return;
   1.569 +  }
   1.570 +
   1.571 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.572 +
   1.573 +  // XXX this is unexpected behavior, see bug 258291
   1.574 +  if (!checkContent("\u732B",
   1.575 +                    "runUndoRedoTest", "#" + ++i) ||
   1.576 +      !checkSelection(1, "", "runUndoRedoTest", "#" + i)) {
   1.577 +    return;
   1.578 +  }
   1.579 +
   1.580 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.581 +
   1.582 +  if (!checkContent("\u732B\u5A18",
   1.583 +                    "runUndoRedoTest", "#" + ++i) ||
   1.584 +      !checkSelection(2, "", "runUndoRedoTest", "#" + i)) {
   1.585 +    return;
   1.586 +  }
   1.587 +
   1.588 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.589 +
   1.590 +  if (!checkContent("\u732B\u5A18 meant",
   1.591 +                    "runUndoRedoTest", "#" + ++i) ||
   1.592 +      !checkSelection(8, "", "runUndoRedoTest", "#" + i)) {
   1.593 +    return;
   1.594 +  }
   1.595 +
   1.596 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.597 +
   1.598 +  if (!checkContent("\u732B\u5A18 mean",
   1.599 +                    "runUndoRedoTest", "#" + ++i) ||
   1.600 +      !checkSelection(7, "", "runUndoRedoTest", "#" + i)) {
   1.601 +    return;
   1.602 +  }
   1.603 +
   1.604 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.605 +
   1.606 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a ",
   1.607 +                    "runUndoRedoTest", "#" + ++i) ||
   1.608 +      !checkSelection(30, "", "runUndoRedoTest", "#" + i)) {
   1.609 +    return;
   1.610 +  }
   1.611 +
   1.612 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.613 +
   1.614 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\". She is a \u5996\u602A",
   1.615 +                    "runUndoRedoTest", "#" + ++i) ||
   1.616 +      !checkSelection(32, "", "runUndoRedoTest", "#" + i)) {
   1.617 +    return;
   1.618 +  }
   1.619 +
   1.620 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.621 +
   1.622 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   1.623 +                    "runUndoRedoTest", "#" + ++i) ||
   1.624 +      !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   1.625 +    return;
   1.626 +  }
   1.627 +
   1.628 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
   1.629 +
   1.630 +  if (!checkContent("\u732B\u5A18 means \"cat-girl\".",
   1.631 +                    "runUndoRedoTest", "#" + ++i) ||
   1.632 +      !checkSelection(20, "", "runUndoRedoTest", "#" + i)) {
   1.633 +    return;
   1.634 +  }
   1.635 +}
   1.636 +
   1.637 +function runCompositionTest()
   1.638 +{
   1.639 +  textarea.value = "";
   1.640 +  textarea.focus();
   1.641 +  var caretRects = [];
   1.642 +
   1.643 +  var caretRect = synthesizeQueryCaretRect(0);
   1.644 +  if (!checkQueryContentResult(caretRect,
   1.645 +        "runCompositionTest: synthesizeQueryCaretRect #0")) {
   1.646 +    return false;
   1.647 +  }
   1.648 +  caretRects[0] = caretRect;
   1.649 +
   1.650 +  // start composition
   1.651 +  synthesizeComposition({ type: "compositionstart" });
   1.652 +
   1.653 +  // input first character
   1.654 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
   1.655 +  synthesizeText(
   1.656 +    { "composition":
   1.657 +      { "string": "\u3089",
   1.658 +        "clauses":
   1.659 +        [
   1.660 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.661 +        ]
   1.662 +      },
   1.663 +      "caret": { "start": 1, "length": 0 }
   1.664 +    });
   1.665 +
   1.666 +  if (!checkContent("\u3089", "runCompositionTest", "#1-1") ||
   1.667 +      !checkSelection(1, "", "runCompositionTest", "#1-1")) {
   1.668 +    return;
   1.669 +  }
   1.670 +
   1.671 +  caretRect = synthesizeQueryCaretRect(1);
   1.672 +  if (!checkQueryContentResult(caretRect,
   1.673 +        "runCompositionTest: synthesizeQueryCaretRect #1-1")) {
   1.674 +    return false;
   1.675 +  }
   1.676 +  caretRects[1] = caretRect;
   1.677 +
   1.678 +  // input second character
   1.679 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
   1.680 +  synthesizeText(
   1.681 +    { "composition":
   1.682 +      { "string": "\u3089\u30FC",
   1.683 +        "clauses":
   1.684 +        [
   1.685 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.686 +        ]
   1.687 +      },
   1.688 +      "caret": { "start": 2, "length": 0 }
   1.689 +    });
   1.690 +
   1.691 +  if (!checkContent("\u3089\u30FC", "runCompositionTest", "#1-2") ||
   1.692 +      !checkSelection(2, "", "runCompositionTest", "#1-2")) {
   1.693 +    return;
   1.694 +  }
   1.695 +
   1.696 +  caretRect = synthesizeQueryCaretRect(2);
   1.697 +  if (!checkQueryContentResult(caretRect,
   1.698 +        "runCompositionTest: synthesizeQueryCaretRect #1-2")) {
   1.699 +    return false;
   1.700 +  }
   1.701 +  caretRects[2] = caretRect;
   1.702 +
   1.703 +  isnot(caretRects[2].left, caretRects[1].left,
   1.704 +        "runCompositionTest: caret isn't moved (#1-2)");
   1.705 +  is(caretRects[2].top, caretRects[1].top,
   1.706 +     "runCompositionTest: caret is moved to another line (#1-2)");
   1.707 +  is(caretRects[2].width, caretRects[1].width,
   1.708 +     "runCompositionTest: caret width is wrong (#1-2)");
   1.709 +  is(caretRects[2].height, caretRects[1].height,
   1.710 +     "runCompositionTest: caret width is wrong (#1-2)");
   1.711 +
   1.712 +  // input third character
   1.713 +  synthesizeComposition({ type: "compositionupdate",
   1.714 +                          data: "\u3089\u30FC\u3081" });
   1.715 +  synthesizeText(
   1.716 +    { "composition":
   1.717 +      { "string": "\u3089\u30FC\u3081",
   1.718 +        "clauses":
   1.719 +        [
   1.720 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.721 +        ]
   1.722 +      },
   1.723 +      "caret": { "start": 3, "length": 0 }
   1.724 +    });
   1.725 +
   1.726 +  if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3") ||
   1.727 +      !checkSelection(3, "", "runCompositionTest", "#1-3")) {
   1.728 +    return;
   1.729 +  }
   1.730 +
   1.731 +  caretRect = synthesizeQueryCaretRect(3);
   1.732 +  if (!checkQueryContentResult(caretRect,
   1.733 +        "runCompositionTest: synthesizeQueryCaretRect #1-3")) {
   1.734 +    return false;
   1.735 +  }
   1.736 +  caretRects[3] = caretRect;
   1.737 +
   1.738 +  isnot(caretRects[3].left, caretRects[2].left,
   1.739 +        "runCompositionTest: caret isn't moved (#1-3)");
   1.740 +  is(caretRects[3].top, caretRects[2].top,
   1.741 +     "runCompositionTest: caret is moved to another line (#1-3)");
   1.742 +  is(caretRects[3].width, caretRects[2].width,
   1.743 +     "runCompositionTest: caret width is wrong (#1-3)");
   1.744 +  is(caretRects[3].height, caretRects[2].height,
   1.745 +     "runCompositionTest: caret height is wrong (#1-3)");
   1.746 +
   1.747 +  // moves the caret left
   1.748 +  synthesizeText(
   1.749 +    { "composition":
   1.750 +      { "string": "\u3089\u30FC\u3081",
   1.751 +        "clauses":
   1.752 +        [
   1.753 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.754 +        ]
   1.755 +      },
   1.756 +      "caret": { "start": 2, "length": 0 }
   1.757 +    });
   1.758 +
   1.759 +  if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-1") ||
   1.760 +      !checkSelection(2, "", "runCompositionTest", "#1-3-1")) {
   1.761 +    return;
   1.762 +  }
   1.763 +
   1.764 +
   1.765 +  caretRect = synthesizeQueryCaretRect(2);
   1.766 +  if (!checkQueryContentResult(caretRect,
   1.767 +        "runCompositionTest: synthesizeQueryCaretRect #1-3-1")) {
   1.768 +    return false;
   1.769 +  }
   1.770 +
   1.771 +  is(caretRect.left, caretRects[2].left,
   1.772 +     "runCompositionTest: caret rects are different (#1-3-1, left)");
   1.773 +  is(caretRect.top, caretRects[2].top,
   1.774 +     "runCompositionTest: caret rects are different (#1-3-1, top)");
   1.775 +  // by bug 335359, the caret width depends on the right side's character.
   1.776 +  is(caretRect.width, caretRects[2].width + 1,
   1.777 +     "runCompositionTest: caret rects are different (#1-3-1, width)");
   1.778 +  is(caretRect.height, caretRects[2].height,
   1.779 +     "runCompositionTest: caret rects are different (#1-3-1, height)");
   1.780 +
   1.781 +  // moves the caret left
   1.782 +  synthesizeText(
   1.783 +    { "composition":
   1.784 +      { "string": "\u3089\u30FC\u3081",
   1.785 +        "clauses":
   1.786 +        [
   1.787 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.788 +        ]
   1.789 +      },
   1.790 +      "caret": { "start": 1, "length": 0 }
   1.791 +    });
   1.792 +
   1.793 +  if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-2") ||
   1.794 +      !checkSelection(1, "", "runCompositionTest", "#1-3-2")) {
   1.795 +    return;
   1.796 +  }
   1.797 +
   1.798 +
   1.799 +  caretRect = synthesizeQueryCaretRect(1);
   1.800 +  if (!checkQueryContentResult(caretRect,
   1.801 +        "runCompositionTest: synthesizeQueryCaretRect #1-3-2")) {
   1.802 +    return false;
   1.803 +  }
   1.804 +
   1.805 +  is(caretRect.left, caretRects[1].left,
   1.806 +     "runCompositionTest: caret rects are different (#1-3-2, left)");
   1.807 +  is(caretRect.top, caretRects[1].top,
   1.808 +     "runCompositionTest: caret rects are different (#1-3-2, top)");
   1.809 +  // by bug 335359, the caret width depends on the right side's character.
   1.810 +  is(caretRect.width, caretRects[1].width + 1,
   1.811 +     "runCompositionTest: caret rects are different (#1-3-2, width)");
   1.812 +  is(caretRect.height, caretRects[1].height,
   1.813 +     "runCompositionTest: caret rects are different (#1-3-2, height)");
   1.814 +
   1.815 +  synthesizeComposition({ type: "compositionupdate",
   1.816 +                          data: "\u3089\u30FC\u3081\u3093" });
   1.817 +  synthesizeText(
   1.818 +    { "composition":
   1.819 +      { "string": "\u3089\u30FC\u3081\u3093",
   1.820 +        "clauses":
   1.821 +        [
   1.822 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.823 +        ]
   1.824 +      },
   1.825 +      "caret": { "start": 4, "length": 0 }
   1.826 +    });
   1.827 +
   1.828 +  if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-4") ||
   1.829 +      !checkSelection(4, "", "runCompositionTest", "#1-4")) {
   1.830 +    return;
   1.831 +  }
   1.832 +
   1.833 +
   1.834 +  // backspace
   1.835 +  synthesizeComposition({ type: "compositionupdate",
   1.836 +                          data: "\u3089\u30FC\u3081" });
   1.837 +  synthesizeText(
   1.838 +    { "composition":
   1.839 +      { "string": "\u3089\u30FC\u3081",
   1.840 +        "clauses":
   1.841 +        [
   1.842 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.843 +        ]
   1.844 +      },
   1.845 +      "caret": { "start": 3, "length": 0 }
   1.846 +    });
   1.847 +
   1.848 +  if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-5") ||
   1.849 +      !checkSelection(3, "", "runCompositionTest", "#1-5")) {
   1.850 +    return;
   1.851 +  }
   1.852 +
   1.853 +  // re-input
   1.854 +  synthesizeComposition({ type: "compositionupdate",
   1.855 +                          data: "\u3089\u30FC\u3081\u3093" });
   1.856 +  synthesizeText(
   1.857 +    { "composition":
   1.858 +      { "string": "\u3089\u30FC\u3081\u3093",
   1.859 +        "clauses":
   1.860 +        [
   1.861 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.862 +        ]
   1.863 +      },
   1.864 +      "caret": { "start": 4, "length": 0 }
   1.865 +    });
   1.866 +
   1.867 +  if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-6") ||
   1.868 +      !checkSelection(4, "", "runCompositionTest", "#1-6")) {
   1.869 +    return;
   1.870 +  }
   1.871 +
   1.872 +  synthesizeComposition({ type: "compositionupdate",
   1.873 +                          data: "\u3089\u30FC\u3081\u3093\u3055" });
   1.874 +  synthesizeText(
   1.875 +    { "composition":
   1.876 +      { "string": "\u3089\u30FC\u3081\u3093\u3055",
   1.877 +        "clauses":
   1.878 +        [
   1.879 +          { "length": 5, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.880 +        ]
   1.881 +      },
   1.882 +      "caret": { "start": 5, "length": 0 }
   1.883 +    });
   1.884 +
   1.885 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", "runCompositionTest", "#1-7") ||
   1.886 +      !checkSelection(5, "", "runCompositionTest", "#1-7")) {
   1.887 +    return;
   1.888 +  }
   1.889 +
   1.890 +  synthesizeComposition({ type: "compositionupdate",
   1.891 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
   1.892 +  synthesizeText(
   1.893 +    { "composition":
   1.894 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
   1.895 +        "clauses":
   1.896 +        [
   1.897 +          { "length": 6, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.898 +        ]
   1.899 +      },
   1.900 +      "caret": { "start": 6, "length": 0 }
   1.901 +    });
   1.902 +
   1.903 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", "runCompositionTest", "#1-8") ||
   1.904 +      !checkSelection(6, "", "runCompositionTest", "#1-8")) {
   1.905 +    return;
   1.906 +  }
   1.907 +
   1.908 +  synthesizeComposition({ type: "compositionupdate",
   1.909 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
   1.910 +  synthesizeText(
   1.911 +    { "composition":
   1.912 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
   1.913 +        "clauses":
   1.914 +        [
   1.915 +          { "length": 7, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.916 +        ]
   1.917 +      },
   1.918 +      "caret": { "start": 7, "length": 0 }
   1.919 +    });
   1.920 +
   1.921 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053", "runCompositionTest", "#1-8") ||
   1.922 +      !checkSelection(7, "", "runCompositionTest", "#1-8")) {
   1.923 +    return;
   1.924 +  }
   1.925 +
   1.926 +  synthesizeComposition({ type: "compositionupdate",
   1.927 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
   1.928 +  synthesizeText(
   1.929 +    { "composition":
   1.930 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
   1.931 +        "clauses":
   1.932 +        [
   1.933 +          { "length": 8, "attr": COMPOSITION_ATTR_RAWINPUT }
   1.934 +        ]
   1.935 +      },
   1.936 +      "caret": { "start": 8, "length": 0 }
   1.937 +    });
   1.938 +
   1.939 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
   1.940 +                    "runCompositionTest", "#1-9") ||
   1.941 +      !checkSelection(8, "", "runCompositionTest", "#1-9")) {
   1.942 +    return;
   1.943 +  }
   1.944 +
   1.945 +  // convert
   1.946 +  synthesizeComposition({ type: "compositionupdate",
   1.947 +                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
   1.948 +  synthesizeText(
   1.949 +    { "composition":
   1.950 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   1.951 +        "clauses":
   1.952 +        [
   1.953 +          { "length": 4,
   1.954 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
   1.955 +          { "length": 2,
   1.956 +            "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
   1.957 +        ]
   1.958 +      },
   1.959 +      "caret": { "start": 4, "length": 0 }
   1.960 +    });
   1.961 +
   1.962 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   1.963 +                    "runCompositionTest", "#1-10") ||
   1.964 +      !checkSelection(4, "", "runCompositionTest", "#1-10")) {
   1.965 +    return;
   1.966 +  }
   1.967 +
   1.968 +  // change the selected clause
   1.969 +  synthesizeText(
   1.970 +    { "composition":
   1.971 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   1.972 +        "clauses":
   1.973 +        [
   1.974 +          { "length": 4,
   1.975 +            "attr": COMPOSITION_ATTR_CONVERTEDTEXT },
   1.976 +          { "length": 2,
   1.977 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
   1.978 +        ]
   1.979 +      },
   1.980 +      "caret": { "start": 6, "length": 0 }
   1.981 +    });
   1.982 +
   1.983 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
   1.984 +                    "runCompositionTest", "#1-11") ||
   1.985 +      !checkSelection(6, "", "runCompositionTest", "#1-11")) {
   1.986 +    return;
   1.987 +  }
   1.988 +
   1.989 +  // reset clauses
   1.990 +  synthesizeComposition({ type: "compositionupdate",
   1.991 +                          data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
   1.992 +  synthesizeText(
   1.993 +    { "composition":
   1.994 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
   1.995 +        "clauses":
   1.996 +        [
   1.997 +          { "length": 5,
   1.998 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
   1.999 +          { "length": 3,
  1.1000 +            "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
  1.1001 +        ]
  1.1002 +      },
  1.1003 +      "caret": { "start": 5, "length": 0 }
  1.1004 +    });
  1.1005 +
  1.1006 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1.1007 +                    "runCompositionTest", "#1-12") ||
  1.1008 +      !checkSelection(5, "", "runCompositionTest", "#1-12")) {
  1.1009 +    return;
  1.1010 +  }
  1.1011 +
  1.1012 +
  1.1013 +  var textRect1 = synthesizeQueryTextRect(0, 1);
  1.1014 +  var textRect2 = synthesizeQueryTextRect(1, 1);
  1.1015 +  if (!checkQueryContentResult(textRect1,
  1.1016 +        "runCompositionTest: synthesizeQueryTextRect #1-12-1") ||
  1.1017 +      !checkQueryContentResult(textRect2,
  1.1018 +        "runCompositionTest: synthesizeQueryTextRect #1-12-2")) {
  1.1019 +    return false;
  1.1020 +  }
  1.1021 +
  1.1022 +  // commit the composition string
  1.1023 +  synthesizeText(
  1.1024 +    { "composition":
  1.1025 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1.1026 +        "clauses":
  1.1027 +        [
  1.1028 +          { "length": 0, "attr": 0 }
  1.1029 +        ]
  1.1030 +      },
  1.1031 +      "caret": { "start": 8, "length": 0 }
  1.1032 +    });
  1.1033 +
  1.1034 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
  1.1035 +                    "runCompositionTest", "#1-13") ||
  1.1036 +      !checkSelection(8, "", "runCompositionTest", "#1-13")) {
  1.1037 +    return;
  1.1038 +  }
  1.1039 +
  1.1040 +  synthesizeComposition({ type: "compositionend",
  1.1041 +                          data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
  1.1042 +
  1.1043 +  var textRect3 = synthesizeQueryTextRect(0, 1);
  1.1044 +  var textRect4 = synthesizeQueryTextRect(1, 1);
  1.1045 +
  1.1046 +  if (!checkQueryContentResult(textRect3,
  1.1047 +        "runCompositionTest: synthesizeQueryTextRect #1-13-1") ||
  1.1048 +      !checkQueryContentResult(textRect4,
  1.1049 +        "runCompositionTest: synthesizeQueryTextRect #1-13-2")) {
  1.1050 +    return false;
  1.1051 +  }
  1.1052 +
  1.1053 +  checkRect(textRect3, textRect1, "runCompositionTest: textRect #1-13-1");
  1.1054 +  checkRect(textRect4, textRect2, "runCompositionTest: textRect #1-13-2");
  1.1055 +
  1.1056 +  // restart composition
  1.1057 +  synthesizeComposition({ type: "compositionstart" });
  1.1058 +
  1.1059 +  // input characters
  1.1060 +  synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
  1.1061 +  synthesizeText(
  1.1062 +    { "composition":
  1.1063 +      { "string": "\u3057",
  1.1064 +        "clauses":
  1.1065 +        [
  1.1066 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1067 +        ]
  1.1068 +      },
  1.1069 +      "caret": { "start": 1, "length": 0 }
  1.1070 +    });
  1.1071 +
  1.1072 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3057",
  1.1073 +                    "runCompositionTest", "#2-1") ||
  1.1074 +      !checkSelection(8 + 1, "", "runCompositionTest", "#2-1")) {
  1.1075 +    return;
  1.1076 +  }
  1.1077 +
  1.1078 +  synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
  1.1079 +  synthesizeText(
  1.1080 +    { "composition":
  1.1081 +      { "string": "\u3058",
  1.1082 +        "clauses":
  1.1083 +        [
  1.1084 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1085 +        ]
  1.1086 +      },
  1.1087 +      "caret": { "start": 1, "length": 0 }
  1.1088 +    });
  1.1089 +
  1.1090 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058",
  1.1091 +                    "runCompositionTest", "#2-2") ||
  1.1092 +      !checkSelection(8 + 1, "", "runCompositionTest", "#2-2")) {
  1.1093 +    return;
  1.1094 +  }
  1.1095 +
  1.1096 +  synthesizeComposition({ type: "compositionupdate", data: "\u3058\u3087" });
  1.1097 +  synthesizeText(
  1.1098 +    { "composition":
  1.1099 +      { "string": "\u3058\u3087",
  1.1100 +        "clauses":
  1.1101 +        [
  1.1102 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1103 +        ]
  1.1104 +      },
  1.1105 +      "caret": { "start": 2, "length": 0 }
  1.1106 +    });
  1.1107 +
  1.1108 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087",
  1.1109 +                    "runCompositionTest", "#2-3") ||
  1.1110 +      !checkSelection(8 + 2, "", "runCompositionTest", "#2-3")) {
  1.1111 +    return;
  1.1112 +  }
  1.1113 +
  1.1114 +  synthesizeComposition({ type: "compositionupdate",
  1.1115 +                          data: "\u3058\u3087\u3046" });
  1.1116 +  synthesizeText(
  1.1117 +    { "composition":
  1.1118 +      { "string": "\u3058\u3087\u3046",
  1.1119 +        "clauses":
  1.1120 +        [
  1.1121 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1122 +        ]
  1.1123 +      },
  1.1124 +      "caret": { "start": 3, "length": 0 }
  1.1125 +    });
  1.1126 +
  1.1127 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
  1.1128 +                    "runCompositionTest", "#2-4") ||
  1.1129 +      !checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
  1.1130 +    return;
  1.1131 +  }
  1.1132 +
  1.1133 +  // commit the composition string
  1.1134 +  synthesizeText(
  1.1135 +    { "composition":
  1.1136 +      { "string": "\u3058\u3087\u3046",
  1.1137 +        "clauses":
  1.1138 +        [
  1.1139 +          { "length": 0, "attr": 0 }
  1.1140 +        ]
  1.1141 +      },
  1.1142 +      "caret": { "start": 3, "length": 0 }
  1.1143 +    });
  1.1144 +
  1.1145 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
  1.1146 +                    "runCompositionTest", "#2-4") ||
  1.1147 +      !checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
  1.1148 +    return;
  1.1149 +  }
  1.1150 +
  1.1151 +  synthesizeComposition({ type: "compositionend", data: "\u3058\u3087\u3046" });
  1.1152 +
  1.1153 +  // set selection
  1.1154 +  var selectionSetTest = synthesizeSelectionSet(4, 7, false);
  1.1155 +  ok(selectionSetTest, "runCompositionTest: selectionSetTest failed");
  1.1156 +
  1.1157 +  if (!checkSelection(4, "\u3055\u884C\u3053\u3046\u3058\u3087\u3046", "runCompositionTest", "#3-1")) {
  1.1158 +    return;
  1.1159 +  }
  1.1160 +
  1.1161 +  // start composition with selection
  1.1162 +  synthesizeComposition({ type: "compositionstart" });
  1.1163 +
  1.1164 +  synthesizeComposition({ type: "compositionupdate", data: "\u304A" });
  1.1165 +  synthesizeText(
  1.1166 +    { "composition":
  1.1167 +      { "string": "\u304A",
  1.1168 +        "clauses":
  1.1169 +        [
  1.1170 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1171 +        ]
  1.1172 +      },
  1.1173 +      "caret": { "start": 1, "length": 0 }
  1.1174 +    });
  1.1175 +
  1.1176 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u304A",
  1.1177 +                    "runCompositionTest", "#3-2") ||
  1.1178 +      !checkSelection(4 + 1, "", "runCompositionTest", "#3-2")) {
  1.1179 +    return;
  1.1180 +  }
  1.1181 +
  1.1182 +  // remove the composition string
  1.1183 +  synthesizeComposition({ type: "compositionupdate", data: "" });
  1.1184 +  synthesizeText(
  1.1185 +    { "composition":
  1.1186 +      { "string": "",
  1.1187 +        "clauses":
  1.1188 +        [
  1.1189 +          { "length": 0, "attr": 0 }
  1.1190 +        ]
  1.1191 +      },
  1.1192 +      "caret": { "start": 0, "length": 0 }
  1.1193 +    });
  1.1194 +
  1.1195 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1196 +                    "runCompositionTest", "#3-3") ||
  1.1197 +      !checkSelection(4, "", "runCompositionTest", "#3-3")) {
  1.1198 +    return;
  1.1199 +  }
  1.1200 +
  1.1201 +  // re-input the composition string
  1.1202 +  synthesizeComposition({ type: "compositionupdate", data: "\u3046" });
  1.1203 +  synthesizeText(
  1.1204 +    { "composition":
  1.1205 +      { "string": "\u3046",
  1.1206 +        "clauses":
  1.1207 +        [
  1.1208 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1209 +        ]
  1.1210 +      },
  1.1211 +      "caret": { "start": 1, "length": 0 }
  1.1212 +    });
  1.1213 +
  1.1214 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3046",
  1.1215 +                    "runCompositionTest", "#3-4") ||
  1.1216 +      !checkSelection(4 + 1, "", "runCompositionTest", "#3-4")) {
  1.1217 +    return;
  1.1218 +  }
  1.1219 +
  1.1220 +  // cancel the composition
  1.1221 +  synthesizeComposition({ type: "compositionupdate", data: "" });
  1.1222 +  synthesizeText(
  1.1223 +    { "composition":
  1.1224 +      { "string": "",
  1.1225 +        "clauses":
  1.1226 +        [
  1.1227 +          { "length": 0, "attr": 0 }
  1.1228 +        ]
  1.1229 +      },
  1.1230 +      "caret": { "start": 0, "length": 0 }
  1.1231 +    });
  1.1232 +
  1.1233 +  synthesizeComposition({ type: "compositionend", data: "" });
  1.1234 +
  1.1235 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1236 +                    "runCompositionTest", "#3-5") ||
  1.1237 +      !checkSelection(4, "", "runCompositionTest", "#3-5")) {
  1.1238 +    return;
  1.1239 +  }
  1.1240 +
  1.1241 +  // bug 271815, some Chinese IMEs for Linux make empty composition string
  1.1242 +  // and compty clause information when it lists up Chinese characters on
  1.1243 +  // its candidate window.
  1.1244 +  synthesizeComposition({ type: "compositionstart" });
  1.1245 +
  1.1246 +  synthesizeText(
  1.1247 +    { "composition":
  1.1248 +      { "string": "",
  1.1249 +        "clauses":
  1.1250 +        [
  1.1251 +          { "length": 0, "attr": 0 }
  1.1252 +        ]
  1.1253 +      },
  1.1254 +      "caret": { "start": 0, "length": 0 }
  1.1255 +    });
  1.1256 +
  1.1257 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1258 +                    "runCompositionTest", "#4-1") ||
  1.1259 +      !checkSelection(4, "", "runCompositionTest", "#4-1")) {
  1.1260 +    return;
  1.1261 +  }
  1.1262 +
  1.1263 +  synthesizeText(
  1.1264 +    { "composition":
  1.1265 +      { "string": "",
  1.1266 +        "clauses":
  1.1267 +        [
  1.1268 +          { "length": 0, "attr": 0 }
  1.1269 +        ]
  1.1270 +      },
  1.1271 +      "caret": { "start": 0, "length": 0 }
  1.1272 +    });
  1.1273 +
  1.1274 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1275 +                    "runCompositionTest", "#4-2") ||
  1.1276 +      !checkSelection(4, "", "runCompositionTest", "#4-2")) {
  1.1277 +    return;
  1.1278 +  }
  1.1279 +
  1.1280 +  synthesizeComposition({ type: "compositionupdate", data: "\u6700" });
  1.1281 +  synthesizeText(
  1.1282 +    { "composition":
  1.1283 +      { "string": "\u6700",
  1.1284 +        "clauses":
  1.1285 +        [
  1.1286 +          { "length": 0, "attr": 0 }
  1.1287 +        ]
  1.1288 +      },
  1.1289 +      "caret": { "start": 1, "length": 0 }
  1.1290 +    });
  1.1291 +
  1.1292 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1293 +                    "runCompositionTest", "#4-3") ||
  1.1294 +      !checkSelection(5, "", "runCompositionTest", "#4-3")) {
  1.1295 +    return;
  1.1296 +  }
  1.1297 +
  1.1298 +  synthesizeComposition({ type: "compositionend", data: "\u6700" });
  1.1299 +
  1.1300 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1301 +                    "runCompositionTest", "#4-4") ||
  1.1302 +      !checkSelection(5, "", "runCompositionTest", "#4-4")) {
  1.1303 +    return;
  1.1304 +  }
  1.1305 +
  1.1306 +  // testing the canceling case
  1.1307 +  synthesizeComposition({ type: "compositionstart" });
  1.1308 +
  1.1309 +  synthesizeText(
  1.1310 +    { "composition":
  1.1311 +      { "string": "",
  1.1312 +        "clauses":
  1.1313 +        [
  1.1314 +          { "length": 0, "attr": 0 }
  1.1315 +        ]
  1.1316 +      },
  1.1317 +      "caret": { "start": 0, "length": 0 }
  1.1318 +    });
  1.1319 +
  1.1320 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1321 +                    "runCompositionTest", "#4-5") ||
  1.1322 +      !checkSelection(5, "", "runCompositionTest", "#4-5")) {
  1.1323 +    return;
  1.1324 +  }
  1.1325 +
  1.1326 +  synthesizeText(
  1.1327 +    { "composition":
  1.1328 +      { "string": "",
  1.1329 +        "clauses":
  1.1330 +        [
  1.1331 +          { "length": 0, "attr": 0 }
  1.1332 +        ]
  1.1333 +      },
  1.1334 +      "caret": { "start": 0, "length": 0 }
  1.1335 +    });
  1.1336 +
  1.1337 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1338 +                    "runCompositionTest", "#4-6") ||
  1.1339 +      !checkSelection(5, "", "runCompositionTest", "#4-6")) {
  1.1340 +    return;
  1.1341 +  }
  1.1342 +
  1.1343 +  synthesizeComposition({ type: "compositionend", data: "\u6700" });
  1.1344 +
  1.1345 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1346 +                    "runCompositionTest", "#4-7") ||
  1.1347 +      !checkSelection(5, "", "runCompositionTest", "#4-7")) {
  1.1348 +    return;
  1.1349 +  }
  1.1350 +
  1.1351 +  // testing whether the empty composition string deletes selected string.
  1.1352 +  synthesizeKey("VK_LEFT", { shiftKey: true });
  1.1353 +
  1.1354 +  synthesizeComposition({ type: "compositionstart" });
  1.1355 +
  1.1356 +  synthesizeText(
  1.1357 +    { "composition":
  1.1358 +      { "string": "",
  1.1359 +        "clauses":
  1.1360 +        [
  1.1361 +          { "length": 0, "attr": 0 }
  1.1362 +        ]
  1.1363 +      },
  1.1364 +      "caret": { "start": 0, "length": 0 }
  1.1365 +    });
  1.1366 +
  1.1367 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1368 +                    "runCompositionTest", "#4-8") ||
  1.1369 +      !checkSelection(4, "", "runCompositionTest", "#4-8")) {
  1.1370 +    return;
  1.1371 +  }
  1.1372 +
  1.1373 +  synthesizeComposition({ type: "compositionupdate", data: "\u9AD8" });
  1.1374 +  synthesizeText(
  1.1375 +    { "composition":
  1.1376 +      { "string": "\u9AD8",
  1.1377 +        "clauses":
  1.1378 +        [
  1.1379 +          { "length": 0, "attr": 0 }
  1.1380 +        ]
  1.1381 +      },
  1.1382 +      "caret": { "start": 1, "length": 0 }
  1.1383 +    });
  1.1384 +
  1.1385 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1.1386 +                    "runCompositionTest", "#4-9") ||
  1.1387 +      !checkSelection(5, "", "runCompositionTest", "#4-9")) {
  1.1388 +    return;
  1.1389 +  }
  1.1390 +
  1.1391 +  synthesizeComposition({ type: "compositionend", data: "\u9AD8" });
  1.1392 +
  1.1393 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1.1394 +                    "runCompositionTest", "#4-10") ||
  1.1395 +      !checkSelection(5, "", "runCompositionTest", "#4-10")) {
  1.1396 +    return;
  1.1397 +  }
  1.1398 +
  1.1399 +  synthesizeKey("VK_BACK_SPACE", {});
  1.1400 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1401 +                    "runCompositionTest", "#4-11") ||
  1.1402 +      !checkSelection(4, "", "runCompositionTest", "#4-11")) {
  1.1403 +    return;
  1.1404 +  }
  1.1405 +
  1.1406 +  // bug 23558, ancient Japanese IMEs on Window may send empty text event
  1.1407 +  // twice at canceling composition.
  1.1408 +  synthesizeComposition({ type: "compositionstart" });
  1.1409 +
  1.1410 +  synthesizeComposition({ type: "compositionupdate", data: "\u6700" });
  1.1411 +  synthesizeText(
  1.1412 +    { "composition":
  1.1413 +      { "string": "\u6700",
  1.1414 +        "clauses":
  1.1415 +        [
  1.1416 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1417 +        ]
  1.1418 +      },
  1.1419 +      "caret": { "start": 1, "length": 0 }
  1.1420 +    });
  1.1421 +
  1.1422 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1423 +                    "runCompositionTest", "#5-1") ||
  1.1424 +      !checkSelection(4 + 1, "", "runCompositionTest", "#5-1")) {
  1.1425 +    return;
  1.1426 +  }
  1.1427 +
  1.1428 +  synthesizeComposition({ type: "compositionupdate", data: "" });
  1.1429 +  synthesizeText(
  1.1430 +    { "composition":
  1.1431 +      { "string": "",
  1.1432 +        "clauses":
  1.1433 +        [
  1.1434 +          { "length": 0, "attr": 0 }
  1.1435 +        ]
  1.1436 +      },
  1.1437 +      "caret": { "start": 0, "length": 0 }
  1.1438 +    });
  1.1439 +
  1.1440 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1441 +                    "runCompositionTest", "#5-2") ||
  1.1442 +      !checkSelection(4, "", "runCompositionTest", "#5-2")) {
  1.1443 +    return;
  1.1444 +  }
  1.1445 +
  1.1446 +  synthesizeText(
  1.1447 +    { "composition":
  1.1448 +      { "string": "",
  1.1449 +        "clauses":
  1.1450 +        [
  1.1451 +          { "length": 0, "attr": 0 }
  1.1452 +        ]
  1.1453 +      },
  1.1454 +      "caret": { "start": 0, "length": 0 }
  1.1455 +    });
  1.1456 +
  1.1457 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1458 +                    "runCompositionTest", "#5-3") ||
  1.1459 +      !checkSelection(4, "", "runCompositionTest", "#5-3")) {
  1.1460 +    return;
  1.1461 +  }
  1.1462 +
  1.1463 +  synthesizeComposition({ type: "compositionend", data: "\u9AD8" });
  1.1464 +
  1.1465 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1466 +                    "runCompositionTest", "#5-4") ||
  1.1467 +      !checkSelection(4, "", "runCompositionTest", "#5-4")) {
  1.1468 +    return;
  1.1469 +  }
  1.1470 +
  1.1471 +  // Undo tests for the testcases for bug 23558 and bug 271815
  1.1472 +  synthesizeKey("Z", { accelKey: true });
  1.1473 +
  1.1474 +  // XXX this is unexpected behavior, see bug 258291
  1.1475 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1476 +                    "runCompositionTest", "#6-1") ||
  1.1477 +      !checkSelection(4, "", "runCompositionTest", "#6-1")) {
  1.1478 +    return;
  1.1479 +  }
  1.1480 +
  1.1481 +  synthesizeKey("Z", { accelKey: true });
  1.1482 +
  1.1483 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u9AD8",
  1.1484 +                    "runCompositionTest", "#6-2") ||
  1.1485 +      !checkSelection(5, "", "runCompositionTest", "#6-2")) {
  1.1486 +    return;
  1.1487 +  }
  1.1488 +
  1.1489 +  synthesizeKey("Z", { accelKey: true });
  1.1490 +
  1.1491 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1492 +                    "runCompositionTest", "#6-3") ||
  1.1493 +      !checkSelection(4, "\u6700", "runCompositionTest", "#6-3")) {
  1.1494 +    return;
  1.1495 +  }
  1.1496 +
  1.1497 +  synthesizeKey("Z", { accelKey: true });
  1.1498 +
  1.1499 +  // XXX this is unexpected behavior, see bug 258291
  1.1500 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700",
  1.1501 +                    "runCompositionTest", "#6-4") ||
  1.1502 +      !checkSelection(5, "", "runCompositionTest", "#6-4")) {
  1.1503 +    return;
  1.1504 +  }
  1.1505 +
  1.1506 +  synthesizeKey("Z", { accelKey: true });
  1.1507 +
  1.1508 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
  1.1509 +                    "runCompositionTest", "#6-5") ||
  1.1510 +      !checkSelection(4, "", "runCompositionTest", "#6-5")) {
  1.1511 +    return;
  1.1512 +  }
  1.1513 +}
  1.1514 +
  1.1515 +function runCompositionEventTest()
  1.1516 +{
  1.1517 +  const kDescription = "runCompositionEventTest: ";
  1.1518 +  const kEvents = ["compositionstart", "compositionupdate", "compositionend",
  1.1519 +                   "input"];
  1.1520 +
  1.1521 +  input.value = "";
  1.1522 +  input.focus();
  1.1523 +
  1.1524 +  var windowEventCounts = [], windowEventData = [], windowEventLocale = [];
  1.1525 +  var inputEventCounts = [], inputEventData = [], inputEventLocale = [];
  1.1526 +  var preventDefault = false;
  1.1527 +  var stopPropagation = false;
  1.1528 +
  1.1529 +  function initResults()
  1.1530 +  {
  1.1531 +    for (var i = 0; i < kEvents.length; i++) {
  1.1532 +      windowEventCounts[kEvents[i]] = 0;
  1.1533 +      windowEventData[kEvents[i]] = "";
  1.1534 +      windowEventLocale[kEvents[i]] = "";
  1.1535 +      inputEventCounts[kEvents[i]] = 0;
  1.1536 +      inputEventData[kEvents[i]] = "";
  1.1537 +      inputEventLocale[kEvents[i]] = "";
  1.1538 +    }
  1.1539 +  }
  1.1540 +
  1.1541 +  function compositionEventHandlerForWindow(aEvent)
  1.1542 +  {
  1.1543 +    windowEventCounts[aEvent.type]++;
  1.1544 +    windowEventData[aEvent.type] = aEvent.data;
  1.1545 +    windowEventLocale[aEvent.type] = aEvent.locale;
  1.1546 +    if (preventDefault) {
  1.1547 +      aEvent.preventDefault();
  1.1548 +    }
  1.1549 +    if (stopPropagation) {
  1.1550 +      aEvent.stopPropagation();
  1.1551 +    }
  1.1552 +  }
  1.1553 +
  1.1554 +  function formEventHandlerForWindow(aEvent)
  1.1555 +  {
  1.1556 +    ok(aEvent.isTrusted, "input events must be trusted events");
  1.1557 +    windowEventCounts[aEvent.type]++;
  1.1558 +    windowEventData[aEvent.type] = input.value;
  1.1559 +  }
  1.1560 +
  1.1561 +  function compositionEventHandlerForInput(aEvent)
  1.1562 +  {
  1.1563 +    inputEventCounts[aEvent.type]++;
  1.1564 +    inputEventData[aEvent.type] = aEvent.data;
  1.1565 +    inputEventLocale[aEvent.type] = aEvent.locale;
  1.1566 +    if (preventDefault) {
  1.1567 +      aEvent.preventDefault();
  1.1568 +    }
  1.1569 +    if (stopPropagation) {
  1.1570 +      aEvent.stopPropagation();
  1.1571 +    }
  1.1572 +  }
  1.1573 +
  1.1574 +  function formEventHandlerForInput(aEvent)
  1.1575 +  {
  1.1576 +    inputEventCounts[aEvent.type]++;
  1.1577 +    inputEventData[aEvent.type] = input.value;
  1.1578 +  }
  1.1579 +
  1.1580 +  window.addEventListener("compositionstart", compositionEventHandlerForWindow,
  1.1581 +                          true, true);
  1.1582 +  window.addEventListener("compositionend", compositionEventHandlerForWindow,
  1.1583 +                          true, true);
  1.1584 +  window.addEventListener("compositionupdate", compositionEventHandlerForWindow,
  1.1585 +                          true, true);
  1.1586 +  window.addEventListener("input", formEventHandlerForWindow,
  1.1587 +                          true, true);
  1.1588 +
  1.1589 +  input.addEventListener("compositionstart", compositionEventHandlerForInput,
  1.1590 +                         true, true);
  1.1591 +  input.addEventListener("compositionend", compositionEventHandlerForInput,
  1.1592 +                         true, true);
  1.1593 +  input.addEventListener("compositionupdate", compositionEventHandlerForInput,
  1.1594 +                         true, true);
  1.1595 +  input.addEventListener("input", formEventHandlerForInput,
  1.1596 +                         true, true);
  1.1597 +
  1.1598 +  // test for normal case
  1.1599 +  initResults();
  1.1600 +
  1.1601 +  synthesizeComposition({ type: "compositionstart" });
  1.1602 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  1.1603 +  synthesizeText(
  1.1604 +    { "composition":
  1.1605 +      { "string": "\u3089",
  1.1606 +        "clauses":
  1.1607 +        [
  1.1608 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1609 +        ]
  1.1610 +      },
  1.1611 +      "caret": { "start": 1, "length": 0 }
  1.1612 +    });
  1.1613 +
  1.1614 +  is(windowEventCounts["compositionstart"], 1,
  1.1615 +     kDescription + "compositionstart hasn't been handled by window #1");
  1.1616 +  is(windowEventData["compositionstart"], "",
  1.1617 +     kDescription + "data of compositionstart isn't empty (window) #1");
  1.1618 +  is(windowEventLocale["compositionstart"], "",
  1.1619 +     kDescription + "locale of compositionstart isn't empty (window) #1");
  1.1620 +  is(inputEventCounts["compositionstart"], 1,
  1.1621 +     kDescription + "compositionstart hasn't been handled by input #1");
  1.1622 +  is(inputEventData["compositionstart"], "",
  1.1623 +     kDescription + "data of compositionstart isn't empty (input) #1");
  1.1624 +  is(inputEventLocale["compositionstart"], "",
  1.1625 +     kDescription + "locale of compositionstart isn't empty (input) #1");
  1.1626 +
  1.1627 +  is(windowEventCounts["compositionupdate"], 1,
  1.1628 +     kDescription + "compositionupdate hasn't been handled by window #1");
  1.1629 +  is(windowEventData["compositionupdate"], "\u3089",
  1.1630 +     kDescription + "data of compositionupdate doesn't match (window) #1");
  1.1631 +  is(windowEventLocale["compositionupdate"], "",
  1.1632 +     kDescription + "locale of compositionupdate isn't empty (window) #1");
  1.1633 +  is(inputEventCounts["compositionupdate"], 1,
  1.1634 +     kDescription + "compositionupdate hasn't been handled by input #1");
  1.1635 +  is(inputEventData["compositionupdate"], "\u3089",
  1.1636 +     kDescription + "data of compositionupdate doesn't match (input) #1");
  1.1637 +  is(inputEventLocale["compositionupdate"], "",
  1.1638 +     kDescription + "locale of compositionupdate isn't empty (input) #1");
  1.1639 +
  1.1640 +  is(windowEventCounts["compositionend"], 0,
  1.1641 +     kDescription + "compositionend has been handled by window #1");
  1.1642 +  is(inputEventCounts["compositionend"], 0,
  1.1643 +     kDescription + "compositionend has been handled by input #1");
  1.1644 +
  1.1645 +  is(windowEventCounts["input"], 1,
  1.1646 +     kDescription + "input hasn't been handled by window #1");
  1.1647 +  is(windowEventData["input"], "\u3089",
  1.1648 +     kDescription + "value of input element wasn't modified (window) #1");
  1.1649 +  is(inputEventCounts["input"], 1,
  1.1650 +     kDescription + "input hasn't been handled by input #1");
  1.1651 +  is(inputEventData["input"], "\u3089",
  1.1652 +     kDescription + "value of input element wasn't modified (input) #1");
  1.1653 +
  1.1654 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
  1.1655 +  synthesizeText(
  1.1656 +    { "composition":
  1.1657 +      { "string": "\u3089\u30FC",
  1.1658 +        "clauses":
  1.1659 +        [
  1.1660 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1661 +        ]
  1.1662 +      },
  1.1663 +      "caret": { "start": 2, "length": 0 }
  1.1664 +    });
  1.1665 +
  1.1666 +  is(windowEventCounts["compositionstart"], 1,
  1.1667 +     kDescription + "compositionstart has been handled more than once by window #2");
  1.1668 +  is(inputEventCounts["compositionstart"], 1,
  1.1669 +     kDescription + "compositionstart has been handled more than once by input #2");
  1.1670 +
  1.1671 +  is(windowEventCounts["compositionupdate"], 2,
  1.1672 +     kDescription + "compositionupdate hasn't been handled by window #2");
  1.1673 +  is(windowEventData["compositionupdate"], "\u3089\u30FC",
  1.1674 +     kDescription + "data of compositionupdate doesn't match (window) #2");
  1.1675 +  is(windowEventLocale["compositionupdate"], "",
  1.1676 +     kDescription + "locale of compositionupdate isn't empty (window) #2");
  1.1677 +  is(inputEventCounts["compositionupdate"], 2,
  1.1678 +     kDescription + "compositionupdate hasn't been handled by input #2");
  1.1679 +  is(inputEventData["compositionupdate"], "\u3089\u30FC",
  1.1680 +     kDescription + "data of compositionupdate doesn't match (input) #2");
  1.1681 +  is(inputEventLocale["compositionupdate"], "",
  1.1682 +     kDescription + "locale of compositionupdate isn't empty (input) #2");
  1.1683 +
  1.1684 +  is(windowEventCounts["compositionend"], 0,
  1.1685 +     kDescription + "compositionend has been handled during composition by window #2");
  1.1686 +  is(inputEventCounts["compositionend"], 0,
  1.1687 +     kDescription + "compositionend has been handled during composition by input #2");
  1.1688 +
  1.1689 +  is(windowEventCounts["input"], 2,
  1.1690 +     kDescription + "input hasn't been handled by window #2");
  1.1691 +  is(windowEventData["input"], "\u3089\u30FC",
  1.1692 +     kDescription + "value of input element wasn't modified (window) #2");
  1.1693 +  is(inputEventCounts["input"], 2,
  1.1694 +     kDescription + "input hasn't been handled by input #2");
  1.1695 +  is(inputEventData["input"], "\u3089\u30FC",
  1.1696 +     kDescription + "value of input element wasn't modified (input) #2");
  1.1697 +
  1.1698 +  // text event shouldn't cause composition update, e.g., at committing.
  1.1699 +  synthesizeText(
  1.1700 +    { "composition":
  1.1701 +      { "string": "\u3089\u30FC",
  1.1702 +        "clauses":
  1.1703 +        [
  1.1704 +          { "length": 0, "attr": 0 }
  1.1705 +        ]
  1.1706 +      },
  1.1707 +      "caret": { "start": 2, "length": 0 }
  1.1708 +    });
  1.1709 +
  1.1710 +  synthesizeComposition({ type: "compositionend", data: "\u3089\u30FC" });
  1.1711 +
  1.1712 +  is(windowEventCounts["compositionstart"], 1,
  1.1713 +     kDescription + "compositionstart has been handled more than once by window #3");
  1.1714 +  is(inputEventCounts["compositionstart"], 1,
  1.1715 +     kDescription + "compositionstart has been handled more than once by input #3");
  1.1716 +
  1.1717 +  is(windowEventCounts["compositionupdate"], 2,
  1.1718 +     kDescription + "compositionupdate has been fired unexpectedly on window #3");
  1.1719 +  is(inputEventCounts["compositionupdate"], 2,
  1.1720 +     kDescription + "compositionupdate has been fired unexpectedly on input #3");
  1.1721 +
  1.1722 +  is(windowEventCounts["compositionend"], 1,
  1.1723 +     kDescription + "compositionend hasn't been handled by window #3");
  1.1724 +  is(windowEventData["compositionend"], "\u3089\u30FC",
  1.1725 +     kDescription + "data of compositionend doesn't match (window) #3");
  1.1726 +  is(windowEventLocale["compositionend"], "",
  1.1727 +     kDescription + "locale of compositionend isn't empty (window) #3");
  1.1728 +  is(inputEventCounts["compositionend"], 1,
  1.1729 +     kDescription + "compositionend hasn't been handled by input #3");
  1.1730 +  is(inputEventData["compositionend"], "\u3089\u30FC",
  1.1731 +     kDescription + "data of compositionend doesn't match (input) #3");
  1.1732 +  is(inputEventLocale["compositionend"], "",
  1.1733 +     kDescription + "locale of compositionend isn't empty (input) #3");
  1.1734 +
  1.1735 +  is(windowEventCounts["input"], 3,
  1.1736 +     kDescription + "input hasn't been handled by window #3");
  1.1737 +  is(windowEventData["input"], "\u3089\u30FC",
  1.1738 +     kDescription + "value of input element wasn't modified (window) #3");
  1.1739 +  is(inputEventCounts["input"], 3,
  1.1740 +     kDescription + "input hasn't been handled by input #3");
  1.1741 +  is(inputEventData["input"], "\u3089\u30FC",
  1.1742 +     kDescription + "value of input element wasn't modified (input) #3");
  1.1743 +
  1.1744 +  // select the second character, then, data of composition start should be
  1.1745 +  // the selected character.
  1.1746 +  initResults();
  1.1747 +  synthesizeKey("VK_LEFT", { shiftKey: true });
  1.1748 +
  1.1749 +  synthesizeComposition({ type: "compositionstart" });
  1.1750 +
  1.1751 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  1.1752 +  synthesizeText(
  1.1753 +    { "composition":
  1.1754 +      { "string": "\u3089",
  1.1755 +        "clauses":
  1.1756 +        [
  1.1757 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1758 +        ]
  1.1759 +      },
  1.1760 +      "caret": { "start": 1, "length": 0 }
  1.1761 +    });
  1.1762 +
  1.1763 +  synthesizeText(
  1.1764 +    { "composition":
  1.1765 +      { "string": "\u3089",
  1.1766 +        "clauses":
  1.1767 +        [
  1.1768 +          { "length": 0, "attr": 0 }
  1.1769 +        ]
  1.1770 +      },
  1.1771 +      "caret": { "start": 1, "length": 0 }
  1.1772 +    });
  1.1773 +
  1.1774 +  synthesizeComposition({ type: "compositionend", data: "\u3089" });
  1.1775 +
  1.1776 +  is(windowEventCounts["compositionstart"], 1,
  1.1777 +     kDescription + "compositionstart hasn't been handled by window #4");
  1.1778 +  is(windowEventData["compositionstart"], "\u30FC",
  1.1779 +     kDescription + "data of compositionstart is empty (window) #4");
  1.1780 +  is(windowEventLocale["compositionstart"], "",
  1.1781 +     kDescription + "locale of compositionstart isn't empty (window) #4");
  1.1782 +  is(inputEventCounts["compositionstart"], 1,
  1.1783 +     kDescription + "compositionstart hasn't been handled by input #4");
  1.1784 +  is(inputEventData["compositionstart"], "\u30FC",
  1.1785 +     kDescription + "data of compositionstart is empty (input) #4");
  1.1786 +  is(inputEventLocale["compositionstart"], "",
  1.1787 +     kDescription + "locale of compositionstart isn't empty (input) #4");
  1.1788 +
  1.1789 +  is(windowEventCounts["compositionupdate"], 1,
  1.1790 +     kDescription + "compositionupdate hasn't been handled by window #4");
  1.1791 +  is(windowEventData["compositionupdate"], "\u3089",
  1.1792 +     kDescription + "data of compositionupdate doesn't match (window) #4");
  1.1793 +  is(windowEventLocale["compositionupdate"], "",
  1.1794 +     kDescription + "locale of compositionupdate isn't empty (window) #4");
  1.1795 +  is(inputEventCounts["compositionupdate"], 1,
  1.1796 +     kDescription + "compositionupdate hasn't been handled by input #4");
  1.1797 +  is(inputEventData["compositionupdate"], "\u3089",
  1.1798 +     kDescription + "data of compositionupdate doesn't match (input) #4");
  1.1799 +  is(inputEventLocale["compositionupdate"], "",
  1.1800 +     kDescription + "locale of compositionupdate isn't empty (input) #4");
  1.1801 +
  1.1802 +  is(windowEventCounts["compositionend"], 1,
  1.1803 +     kDescription + "compositionend hasn't been handled by window #4");
  1.1804 +  is(windowEventData["compositionend"], "\u3089",
  1.1805 +     kDescription + "data of compositionend doesn't match (window) #4");
  1.1806 +  is(windowEventLocale["compositionend"], "",
  1.1807 +     kDescription + "locale of compositionend isn't empty (window) #4");
  1.1808 +  is(inputEventCounts["compositionend"], 1,
  1.1809 +     kDescription + "compositionend hasn't been handled by input #4");
  1.1810 +  is(inputEventData["compositionend"], "\u3089",
  1.1811 +     kDescription + "data of compositionend doesn't match (input) #4");
  1.1812 +  is(inputEventLocale["compositionend"], "",
  1.1813 +     kDescription + "locale of compositionend isn't empty (input) #4");
  1.1814 +
  1.1815 +  is(windowEventCounts["input"], 2,
  1.1816 +     kDescription + "input hasn't been handled by window #4");
  1.1817 +  is(windowEventData["input"], "\u3089\u3089",
  1.1818 +     kDescription + "value of input element wasn't modified (window) #4");
  1.1819 +  is(inputEventCounts["input"], 2,
  1.1820 +     kDescription + "input hasn't been handled by input #4");
  1.1821 +  is(inputEventData["input"], "\u3089\u3089",
  1.1822 +     kDescription + "value of input element wasn't modified (input) #4");
  1.1823 +
  1.1824 +  // preventDefault() should effect nothing.
  1.1825 +  preventDefault = true;
  1.1826 +
  1.1827 +  initResults();
  1.1828 +  synthesizeKey("A", { accelKey: true }); // Select All
  1.1829 +
  1.1830 +  synthesizeComposition({ type: "compositionstart" });
  1.1831 +
  1.1832 +  synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
  1.1833 +  synthesizeText(
  1.1834 +    { "composition":
  1.1835 +      { "string": "\u306D",
  1.1836 +        "clauses":
  1.1837 +        [
  1.1838 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1839 +        ]
  1.1840 +      },
  1.1841 +      "caret": { "start": 1, "length": 0 }
  1.1842 +    });
  1.1843 +
  1.1844 +  synthesizeText(
  1.1845 +    { "composition":
  1.1846 +      { "string": "\u306D",
  1.1847 +        "clauses":
  1.1848 +        [
  1.1849 +          { "length": 0, "attr": 0 }
  1.1850 +        ]
  1.1851 +      },
  1.1852 +      "caret": { "start": 1, "length": 0 }
  1.1853 +    });
  1.1854 +
  1.1855 +  synthesizeComposition({ type: "compositionend", data: "\u306D" });
  1.1856 +
  1.1857 +  is(windowEventCounts["compositionstart"], 1,
  1.1858 +     kDescription + "compositionstart hasn't been handled by window #5");
  1.1859 +  is(windowEventData["compositionstart"], "\u3089\u3089",
  1.1860 +     kDescription + "data of compositionstart is empty (window) #5");
  1.1861 +  is(windowEventLocale["compositionstart"], "",
  1.1862 +     kDescription + "locale of compositionstart isn't empty (window) #5");
  1.1863 +  is(inputEventCounts["compositionstart"], 1,
  1.1864 +     kDescription + "compositionstart hasn't been handled by input #5");
  1.1865 +  is(inputEventData["compositionstart"], "\u3089\u3089",
  1.1866 +     kDescription + "data of compositionstart is empty (input) #5");
  1.1867 +  is(inputEventLocale["compositionstart"], "",
  1.1868 +     kDescription + "locale of compositionstart isn't empty (input) #5");
  1.1869 +
  1.1870 +  is(windowEventCounts["compositionupdate"], 1,
  1.1871 +     kDescription + "compositionupdate hasn't been handled by window #5");
  1.1872 +  is(windowEventData["compositionupdate"], "\u306D",
  1.1873 +     kDescription + "data of compositionupdate doesn't match (window) #5");
  1.1874 +  is(windowEventLocale["compositionupdate"], "",
  1.1875 +     kDescription + "locale of compositionupdate isn't empty (window) #5");
  1.1876 +  is(inputEventCounts["compositionupdate"], 1,
  1.1877 +     kDescription + "compositionupdate hasn't been handled by input #5");
  1.1878 +  is(inputEventData["compositionupdate"], "\u306D",
  1.1879 +     kDescription + "data of compositionupdate doesn't match (input) #5");
  1.1880 +  is(inputEventLocale["compositionupdate"], "",
  1.1881 +     kDescription + "locale of compositionupdate isn't empty (input) #5");
  1.1882 +
  1.1883 +  is(windowEventCounts["compositionend"], 1,
  1.1884 +     kDescription + "compositionend hasn't been handled by window #5");
  1.1885 +  is(windowEventData["compositionend"], "\u306D",
  1.1886 +     kDescription + "data of compositionend doesn't match (window) #5");
  1.1887 +  is(windowEventLocale["compositionend"], "",
  1.1888 +     kDescription + "locale of compositionend isn't empty (window) #5");
  1.1889 +  is(inputEventCounts["compositionend"], 1,
  1.1890 +     kDescription + "compositionend hasn't been handled by input #5");
  1.1891 +  is(inputEventData["compositionend"], "\u306D",
  1.1892 +     kDescription + "data of compositionend doesn't match (input) #5");
  1.1893 +  is(inputEventLocale["compositionend"], "",
  1.1894 +     kDescription + "locale of compositionend isn't empty (input) #5");
  1.1895 +
  1.1896 +  is(windowEventCounts["input"], 2,
  1.1897 +     kDescription + "input hasn't been handled by window #5");
  1.1898 +  is(windowEventData["input"], "\u306D",
  1.1899 +     kDescription + "value of input element wasn't modified (window) #5");
  1.1900 +  is(inputEventCounts["input"], 2,
  1.1901 +     kDescription + "input hasn't been handled by input #5");
  1.1902 +  is(inputEventData["input"], "\u306D",
  1.1903 +     kDescription + "value of input element wasn't modified (input) #5");
  1.1904 +
  1.1905 +  prevnetDefault = false;
  1.1906 +
  1.1907 +  // stopPropagation() should effect nothing (except event count)
  1.1908 +  stopPropagation = true;
  1.1909 +
  1.1910 +  initResults();
  1.1911 +  synthesizeKey("A", { accelKey: true }); // Select All
  1.1912 +
  1.1913 +  synthesizeComposition({ type: "compositionstart" });
  1.1914 +
  1.1915 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.1916 +  synthesizeText(
  1.1917 +    { "composition":
  1.1918 +      { "string": "\u306E",
  1.1919 +        "clauses":
  1.1920 +        [
  1.1921 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.1922 +        ]
  1.1923 +      },
  1.1924 +      "caret": { "start": 1, "length": 0 }
  1.1925 +    });
  1.1926 +
  1.1927 +  synthesizeText(
  1.1928 +    { "composition":
  1.1929 +      { "string": "\u306E",
  1.1930 +        "clauses":
  1.1931 +        [
  1.1932 +          { "length": 0, "attr": 0 }
  1.1933 +        ]
  1.1934 +      },
  1.1935 +      "caret": { "start": 1, "length": 0 }
  1.1936 +    });
  1.1937 +
  1.1938 +  synthesizeComposition({ type: "compositionend", data: "\u306E" });
  1.1939 +
  1.1940 +  is(windowEventCounts["compositionstart"], 1,
  1.1941 +     kDescription + "compositionstart hasn't been handled by window #6");
  1.1942 +  is(windowEventData["compositionstart"], "\u306D",
  1.1943 +     kDescription + "data of compositionstart is empty #6");
  1.1944 +  is(windowEventLocale["compositionstart"], "",
  1.1945 +     kDescription + "locale of compositionstart isn't empty #6");
  1.1946 +  is(inputEventCounts["compositionstart"], 0,
  1.1947 +     kDescription + "compositionstart has been handled by input #6");
  1.1948 +
  1.1949 +  is(windowEventCounts["compositionupdate"], 1,
  1.1950 +     kDescription + "compositionupdate hasn't been handled by window #6");
  1.1951 +  is(windowEventData["compositionupdate"], "\u306E",
  1.1952 +     kDescription + "data of compositionupdate doesn't match #6");
  1.1953 +  is(windowEventLocale["compositionupdate"], "",
  1.1954 +     kDescription + "locale of compositionupdate isn't empty #6");
  1.1955 +  is(inputEventCounts["compositionupdate"], 0,
  1.1956 +     kDescription + "compositionupdate has been handled by input #6");
  1.1957 +
  1.1958 +  is(windowEventCounts["compositionend"], 1,
  1.1959 +     kDescription + "compositionend hasn't been handled by window #6");
  1.1960 +  is(windowEventData["compositionend"], "\u306E",
  1.1961 +     kDescription + "data of compositionend doesn't match #6");
  1.1962 +  is(windowEventLocale["compositionend"], "",
  1.1963 +     kDescription + "locale of compositionend isn't empty #6");
  1.1964 +  is(inputEventCounts["compositionend"], 0,
  1.1965 +     kDescription + "compositionend has been handled by input #6");
  1.1966 +
  1.1967 +  is(windowEventCounts["input"], 2,
  1.1968 +     kDescription + "input hasn't been handled by window #6");
  1.1969 +  is(windowEventData["input"], "\u306E",
  1.1970 +     kDescription + "value of input element wasn't modified (window) #6");
  1.1971 +  is(inputEventCounts["input"], 2,
  1.1972 +     kDescription + "input hasn't been handled by input #6");
  1.1973 +  is(inputEventData["input"], "\u306E",
  1.1974 +     kDescription + "value of input element wasn't modified (input) #6");
  1.1975 +
  1.1976 +  stopPropagation = false;
  1.1977 +
  1.1978 +  // create event and dispatch it.
  1.1979 +  initResults();
  1.1980 +
  1.1981 +  input.value = "value of input";
  1.1982 +  synthesizeKey("A", { accelKey: true }); // Select All
  1.1983 +
  1.1984 +  var compositionstart = document.createEvent("CompositionEvent");
  1.1985 +  compositionstart.initCompositionEvent("compositionstart",
  1.1986 +                                        true, true, document.defaultView,
  1.1987 +                                        "start data", "start locale");
  1.1988 +  is(compositionstart.type, "compositionstart",
  1.1989 +     kDescription + "type doesn't match #7");
  1.1990 +  is(compositionstart.data, "start data",
  1.1991 +     kDescription + "data doesn't match #7");
  1.1992 +  is(compositionstart.locale, "start locale",
  1.1993 +     kDescription + "locale doesn't match #7");
  1.1994 +  is(compositionstart.detail, 0,
  1.1995 +     kDescription + "detail isn't 0 #7");
  1.1996 +
  1.1997 +  input.dispatchEvent(compositionstart);
  1.1998 +
  1.1999 +  is(windowEventCounts["compositionstart"], 1,
  1.2000 +     kDescription + "compositionstart hasn't been handled by window #7");
  1.2001 +  is(windowEventData["compositionstart"], "start data",
  1.2002 +     kDescription + "data of compositionstart was changed (window) #7");
  1.2003 +  is(windowEventLocale["compositionstart"], "start locale",
  1.2004 +     kDescription + "locale of compositionstart was changed (window) #7");
  1.2005 +  is(inputEventCounts["compositionstart"], 1,
  1.2006 +     kDescription + "compositionstart hasn't been handled by input #7");
  1.2007 +  is(inputEventData["compositionstart"], "start data",
  1.2008 +     kDescription + "data of compositionstart was changed (input) #7");
  1.2009 +  is(inputEventLocale["compositionstart"], "start locale",
  1.2010 +     kDescription + "locale of compositionstart was changed (input) #7");
  1.2011 +
  1.2012 +  is(input.value, "value of input",
  1.2013 +     kDescription + "input value was changed #7");
  1.2014 +
  1.2015 +  var compositionupdate1 = document.createEvent("compositionevent");
  1.2016 +  compositionupdate1.initCompositionEvent("compositionupdate",
  1.2017 +                                          true, false, document.defaultView,
  1.2018 +                                          "composing string", "composing locale");
  1.2019 +  is(compositionupdate1.type, "compositionupdate",
  1.2020 +     kDescription + "type doesn't match #8");
  1.2021 +  is(compositionupdate1.data, "composing string",
  1.2022 +     kDescription + "data doesn't match #8");
  1.2023 +  is(compositionupdate1.locale, "composing locale",
  1.2024 +     kDescription + "locale doesn't match #8");
  1.2025 +  is(compositionupdate1.detail, 0,
  1.2026 +     kDescription + "detail isn't 0 #8");
  1.2027 +
  1.2028 +  input.dispatchEvent(compositionupdate1);
  1.2029 +
  1.2030 +  is(windowEventCounts["compositionupdate"], 1,
  1.2031 +     kDescription + "compositionupdate hasn't been handled by window #8");
  1.2032 +  is(windowEventData["compositionupdate"], "composing string",
  1.2033 +     kDescription + "data of compositionupdate was changed (window) #8");
  1.2034 +  is(windowEventLocale["compositionupdate"], "composing locale",
  1.2035 +     kDescription + "locale of compositionupdate was changed (window) #8");
  1.2036 +  is(inputEventCounts["compositionupdate"], 1,
  1.2037 +     kDescription + "compositionupdate hasn't been handled by input #8");
  1.2038 +  is(inputEventData["compositionupdate"], "composing string",
  1.2039 +     kDescription + "data of compositionupdate was changed (input) #8");
  1.2040 +  is(inputEventLocale["compositionupdate"], "composing locale",
  1.2041 +     kDescription + "locale of compositionupdate was changed (input) #8");
  1.2042 +
  1.2043 +  is(input.value, "value of input",
  1.2044 +     kDescription + "input value was changed #8");
  1.2045 +
  1.2046 +  var compositionupdate2 = document.createEvent("compositionEvent");
  1.2047 +  compositionupdate2.initCompositionEvent("compositionupdate",
  1.2048 +                                          true, false, document.defaultView,
  1.2049 +                                          "commit string", "commit locale");
  1.2050 +  is(compositionupdate2.type, "compositionupdate",
  1.2051 +     kDescription + "type doesn't match #9");
  1.2052 +  is(compositionupdate2.data, "commit string",
  1.2053 +     kDescription + "data doesn't match #9");
  1.2054 +  is(compositionupdate2.locale, "commit locale",
  1.2055 +     kDescription + "locale doesn't match #9");
  1.2056 +  is(compositionupdate2.detail, 0,
  1.2057 +     kDescription + "detail isn't 0 #9");
  1.2058 +
  1.2059 +  input.dispatchEvent(compositionupdate2);
  1.2060 +
  1.2061 +  is(windowEventCounts["compositionupdate"], 2,
  1.2062 +     kDescription + "compositionupdate hasn't been handled by window #9");
  1.2063 +  is(windowEventData["compositionupdate"], "commit string",
  1.2064 +     kDescription + "data of compositionupdate was changed (window) #9");
  1.2065 +  is(windowEventLocale["compositionupdate"], "commit locale",
  1.2066 +     kDescription + "locale of compositionupdate was changed (window) #9");
  1.2067 +  is(inputEventCounts["compositionupdate"], 2,
  1.2068 +     kDescription + "compositionupdate hasn't been handled by input #9");
  1.2069 +  is(inputEventData["compositionupdate"], "commit string",
  1.2070 +     kDescription + "data of compositionupdate was changed (input) #9");
  1.2071 +  is(inputEventLocale["compositionupdate"], "commit locale",
  1.2072 +     kDescription + "locale of compositionupdate was changed (input) #9");
  1.2073 +
  1.2074 +  is(input.value, "value of input",
  1.2075 +     kDescription + "input value was changed #9");
  1.2076 +
  1.2077 +  var compositionend = document.createEvent("Compositionevent");
  1.2078 +  compositionend.initCompositionEvent("compositionend",
  1.2079 +                                      true, false, document.defaultView,
  1.2080 +                                      "end data", "end locale");
  1.2081 +  is(compositionend.type, "compositionend",
  1.2082 +     kDescription + "type doesn't match #10");
  1.2083 +  is(compositionend.data, "end data",
  1.2084 +     kDescription + "data doesn't match #10");
  1.2085 +  is(compositionend.locale, "end locale",
  1.2086 +     kDescription + "locale doesn't match #10");
  1.2087 +  is(compositionend.detail, 0,
  1.2088 +     kDescription + "detail isn't 0 #10");
  1.2089 +
  1.2090 +  input.dispatchEvent(compositionend);
  1.2091 +
  1.2092 +  is(windowEventCounts["compositionend"], 1,
  1.2093 +     kDescription + "compositionend hasn't been handled by window #10");
  1.2094 +  is(windowEventData["compositionend"], "end data",
  1.2095 +     kDescription + "data of compositionend was changed (window) #10");
  1.2096 +  is(windowEventLocale["compositionend"], "end locale",
  1.2097 +     kDescription + "locale of compositionend was changed (window) #10");
  1.2098 +  is(inputEventCounts["compositionend"], 1,
  1.2099 +     kDescription + "compositionend hasn't been handled by input #10");
  1.2100 +  is(inputEventData["compositionend"], "end data",
  1.2101 +     kDescription + "data of compositionend was changed (input) #10");
  1.2102 +  is(inputEventLocale["compositionend"], "end locale",
  1.2103 +     kDescription + "locale of compositionend was changed (input) #10");
  1.2104 +
  1.2105 +  is(input.value, "value of input",
  1.2106 +     kDescription + "input value was changed #10");
  1.2107 +
  1.2108 +  window.removeEventListener("compositionstart",
  1.2109 +                             compositionEventHandlerForWindow, true);
  1.2110 +  window.removeEventListener("compositionend",
  1.2111 +                             compositionEventHandlerForWindow, true);
  1.2112 +  window.removeEventListener("compositionupdate",
  1.2113 +                             compositionEventHandlerForWindow, true);
  1.2114 +  window.removeEventListener("input",
  1.2115 +                             formEventHandlerForWindow, true);
  1.2116 +
  1.2117 +  input.removeEventListener("compositionstart",
  1.2118 +                            compositionEventHandlerForInput, true);
  1.2119 +  input.removeEventListener("compositionend",
  1.2120 +                            compositionEventHandlerForInput, true);
  1.2121 +  input.removeEventListener("compositionupdate",
  1.2122 +                            compositionEventHandlerForInput, true);
  1.2123 +  input.removeEventListener("input",
  1.2124 +                            formEventHandlerForInput, true);
  1.2125 +}
  1.2126 +
  1.2127 +function runCharAtPointTest(aFocusedEditor, aTargetName)
  1.2128 +{
  1.2129 +  aFocusedEditor.value = "This is a test of the\nContent Events";
  1.2130 +                       // 012345678901234567890  12345678901234
  1.2131 +                       // 0         1         2           3    
  1.2132 +
  1.2133 +  aFocusedEditor.focus();
  1.2134 +
  1.2135 +  const kNone = -1;
  1.2136 +  const kTestingOffset   = [     0, 10,    20, 21 + kLFLen, 34 + kLFLen];
  1.2137 +  const kLeftSideOffset  = [ kNone,  9,    19,       kNone, 33 + kLFLen];
  1.2138 +  const kRightSideOffset = [     1, 11, kNone, 22 + kLFLen,       kNone];
  1.2139 +
  1.2140 +  var editorRect = synthesizeQueryEditorRect();
  1.2141 +  if (!checkQueryContentResult(editorRect,
  1.2142 +        "runCharAtPointTest (" + aTargetName + "): editorRect")) {
  1.2143 +    return;
  1.2144 +  }
  1.2145 +
  1.2146 +  for (var i = 0; i < kTestingOffset.length; i++) {
  1.2147 +    var textRect = synthesizeQueryTextRect(kTestingOffset[i], 1);
  1.2148 +    if (!checkQueryContentResult(textRect,
  1.2149 +          "runCharAtPointTest (" + aTargetName + "): textRect: i=" + i)) {
  1.2150 +      continue;
  1.2151 +    }
  1.2152 +
  1.2153 +    checkRectContainsRect(textRect, editorRect,
  1.2154 +      "runCharAtPointTest (" + aTargetName +
  1.2155 +      "): the text rect isn't in the editor");
  1.2156 +
  1.2157 +    // Test #1, getting same character rect by the point near the top-left.
  1.2158 +    var charAtPt1 = synthesizeCharAtPoint(textRect.left + 1,
  1.2159 +                                          textRect.top + 1);
  1.2160 +    if (checkQueryContentResult(charAtPt1,
  1.2161 +          "runCharAtPointTest (" + aTargetName + "): charAtPt1: i=" + i)) {
  1.2162 +      ok(!charAtPt1.notFound,
  1.2163 +         "runCharAtPointTest (" + aTargetName + "): charAtPt1 isn't found: i=" + i);
  1.2164 +      if (!charAtPt1.notFound) {
  1.2165 +        is(charAtPt1.offset, kTestingOffset[i],
  1.2166 +           "runCharAtPointTest (" + aTargetName + "): charAtPt1 offset is wrong: i=" + i);
  1.2167 +        checkRect(charAtPt1, textRect, "runCharAtPointTest (" + aTargetName +
  1.2168 +                  "): charAtPt1 left is wrong: i=" + i);
  1.2169 +      }
  1.2170 +    }
  1.2171 +
  1.2172 +    // Test #2, getting same character rect by the point near the bottom-right.
  1.2173 +    var charAtPt2 = synthesizeCharAtPoint(textRect.left + textRect.width - 2,
  1.2174 +                                          textRect.top + textRect.height - 2);
  1.2175 +    if (checkQueryContentResult(charAtPt2,
  1.2176 +          "runCharAtPointTest (" + aTargetName + "): charAtPt2: i=" + i)) {
  1.2177 +      ok(!charAtPt2.notFound,
  1.2178 +         "runCharAtPointTest (" + aTargetName + "): charAtPt2 isn't found: i=" + i);
  1.2179 +      if (!charAtPt2.notFound) {
  1.2180 +        is(charAtPt2.offset, kTestingOffset[i],
  1.2181 +           "runCharAtPointTest (" + aTargetName + "): charAtPt2 offset is wrong: i=" + i);
  1.2182 +        checkRect(charAtPt2, textRect, "runCharAtPointTest (" + aTargetName +
  1.2183 +                  "): charAtPt1 left is wrong: i=" + i);
  1.2184 +      }
  1.2185 +    }
  1.2186 +
  1.2187 +    // Test #3, getting left character offset.
  1.2188 +    var charAtPt3 = synthesizeCharAtPoint(textRect.left - 2,
  1.2189 +                                          textRect.top + 1);
  1.2190 +    if (checkQueryContentResult(charAtPt3,
  1.2191 +          "runCharAtPointTest (" + aTargetName + "): charAtPt3: i=" + i)) {
  1.2192 +      is(charAtPt3.notFound, kLeftSideOffset[i] == kNone,
  1.2193 +         kLeftSideOffset[i] == kNone ?
  1.2194 +           "runCharAtPointTest (" + aTargetName + "): charAtPt3 is found: i=" + i :
  1.2195 +           "runCharAtPointTest (" + aTargetName + "): charAtPt3 isn't found: i=" + i);
  1.2196 +      if (!charAtPt3.notFound) {
  1.2197 +        is(charAtPt3.offset, kLeftSideOffset[i],
  1.2198 +           "runCharAtPointTest (" + aTargetName + "): charAtPt3 offset is wrong: i=" + i);
  1.2199 +      }
  1.2200 +    }
  1.2201 +
  1.2202 +    // Test #4, getting right character offset.
  1.2203 +    var charAtPt4 = synthesizeCharAtPoint(textRect.left + textRect.width + 1,
  1.2204 +                                          textRect.top + textRect.height - 2);
  1.2205 +    if (checkQueryContentResult(charAtPt4,
  1.2206 +          "runCharAtPointTest (" + aTargetName + "): charAtPt4: i=" + i)) {
  1.2207 +      is(charAtPt4.notFound, kRightSideOffset[i] == kNone,
  1.2208 +         kRightSideOffset[i] == kNone ?
  1.2209 +           "runCharAtPointTest (" + aTargetName + "): charAtPt4 is found: i=" + i :
  1.2210 +           "runCharAtPointTest (" + aTargetName + "): charAtPt4 isn't found: i=" + i);
  1.2211 +      if (!charAtPt4.notFound) {
  1.2212 +        is(charAtPt4.offset, kRightSideOffset[i],
  1.2213 +           "runCharAtPointTest (" + aTargetName + "): charAtPt4 offset is wrong: i=" + i);
  1.2214 +      }
  1.2215 +    }
  1.2216 +  }
  1.2217 +}
  1.2218 +
  1.2219 +function runCharAtPointAtOutsideTest()
  1.2220 +{
  1.2221 +  textarea.focus();
  1.2222 +  textarea.value = "some text";
  1.2223 +  var editorRect = synthesizeQueryEditorRect();
  1.2224 +  if (!checkQueryContentResult(editorRect,
  1.2225 +        "runCharAtPointAtOutsideTest: editorRect")) {
  1.2226 +    return;
  1.2227 +  }
  1.2228 +  // Check on a text node which is at the outside of editor.
  1.2229 +  var charAtPt = synthesizeCharAtPoint(editorRect.left + 20,
  1.2230 +                                       editorRect.top - 10);
  1.2231 +  if (checkQueryContentResult(charAtPt,
  1.2232 +        "runCharAtPointAtOutsideTest: charAtPt")) {
  1.2233 +    ok(charAtPt.notFound,
  1.2234 +       "runCharAtPointAtOutsideTest: charAtPt is found on outside of editor");
  1.2235 +  }
  1.2236 +}
  1.2237 +
  1.2238 +function runBug722639Test()
  1.2239 +{
  1.2240 +  textarea.focus();
  1.2241 +  textarea.value = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  1.2242 +  textarea.value += textarea.value;
  1.2243 +  textarea.value += textarea.value; // 80 characters
  1.2244 +
  1.2245 +  var firstLine = synthesizeQueryTextRect(0, 1);
  1.2246 +  if (!checkQueryContentResult(firstLine,
  1.2247 +        "runBug722639Test: firstLine")) {
  1.2248 +    return;
  1.2249 +  }
  1.2250 +  var secondLine = synthesizeQueryTextRect(kLFLen, 1);
  1.2251 +  if (!checkQueryContentResult(secondLine,
  1.2252 +        "runBug722639Test: secondLine")) {
  1.2253 +    return;
  1.2254 +  }
  1.2255 +  var lineHeight = secondLine.top -  firstLine.top;
  1.2256 +  ok(lineHeight > 0,
  1.2257 +     "runBug722639Test: lineHeight must be positive");
  1.2258 +  is(secondLine.left, firstLine.left,
  1.2259 +     "runBug722639Test: the left value must be always same value");
  1.2260 +  var previousTop = secondLine.top;
  1.2261 +  for (var i = 2; i < textarea.value.length; i++) {
  1.2262 +    var currentLine = synthesizeQueryTextRect(kLFLen * i, 1);
  1.2263 +    if (!checkQueryContentResult(currentLine,
  1.2264 +           "runBug722639Test: " + i + "th currentLine")) {
  1.2265 +      return;
  1.2266 +    }
  1.2267 +    // NOTE: the top position may be 1px larger or smaller than other lines
  1.2268 +    //       due to sub pixel positioning.
  1.2269 +    if (Math.abs(currentLine.top - (previousTop + lineHeight)) <= 1) {
  1.2270 +      ok(true, "runBug722639Test: " + i + "th line's top is expected");
  1.2271 +    } else {
  1.2272 +      is(currentLine.top, previousTop + lineHeight,
  1.2273 +         "runBug722639Test: " + i + "th line's top is unexpected");
  1.2274 +    }
  1.2275 +    is(currentLine.left, firstLine.left,
  1.2276 +       "runBug722639Test: " + i + "th line's left is unexpected");
  1.2277 +    previousTop = currentLine.top;
  1.2278 +  }
  1.2279 +}
  1.2280 +
  1.2281 +function runForceCommitTest()
  1.2282 +{
  1.2283 +  var events;
  1.2284 +  function eventHandler(aEvent)
  1.2285 +  {
  1.2286 +    events.push(aEvent);
  1.2287 +  }
  1.2288 +  window.addEventListener("compositionstart", eventHandler, true);
  1.2289 +  window.addEventListener("compositionupdate", eventHandler, true);
  1.2290 +  window.addEventListener("compositionend", eventHandler, true);
  1.2291 +  window.addEventListener("input", eventHandler, true);
  1.2292 +  window.addEventListener("text", eventHandler, true);
  1.2293 +
  1.2294 +  // Make the composition in textarea commit by click in the textarea
  1.2295 +  textarea.focus();
  1.2296 +  textarea.value = "";
  1.2297 +
  1.2298 +  events = [];
  1.2299 +  synthesizeComposition({ type: "compositionstart" });
  1.2300 +
  1.2301 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2302 +  synthesizeText(
  1.2303 +    { "composition":
  1.2304 +      { "string": "\u306E",
  1.2305 +        "clauses":
  1.2306 +        [
  1.2307 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2308 +        ]
  1.2309 +      },
  1.2310 +      "caret": { "start": 1, "length": 0 }
  1.2311 +    });
  1.2312 +
  1.2313 +  is(events.length, 4,
  1.2314 +     "runForceCommitTest: wrong event count #1");
  1.2315 +  is(events[0].type, "compositionstart",
  1.2316 +     "runForceCommitTest: the 1st event must be compositionstart #1");
  1.2317 +  is(events[1].type, "compositionupdate",
  1.2318 +     "runForceCommitTest: the 2nd event must be compositionupdate #1");
  1.2319 +  is(events[2].type, "text",
  1.2320 +     "runForceCommitTest: the 3rd event must be text #1");
  1.2321 +  is(events[3].type, "input",
  1.2322 +     "runForceCommitTest: the 4th event must be input #1");
  1.2323 +
  1.2324 +  events = [];
  1.2325 +  synthesizeMouseAtCenter(textarea, {});
  1.2326 +
  1.2327 +  is(events.length, 3,
  1.2328 +     "runForceCommitTest: wrong event count #2");
  1.2329 +  is(events[0].type, "text",
  1.2330 +     "runForceCommitTest: the 1st event must be text #2");
  1.2331 +  is(events[1].type, "compositionend",
  1.2332 +     "runForceCommitTest: the 2nd event must be compositionend #2");
  1.2333 +  is(events[2].type, "input",
  1.2334 +     "runForceCommitTest: the 3rd event must be input #2");
  1.2335 +  is(events[1].data, "\u306E",
  1.2336 +     "runForceCommitTest: compositionend has wrong data #2");
  1.2337 +  is(events[0].target, textarea,
  1.2338 +     "runForceCommitTest: The 1st event was fired on wrong event target #2");
  1.2339 +  is(events[1].target, textarea,
  1.2340 +     "runForceCommitTest: The 2nd event was fired on wrong event target #2");
  1.2341 +  is(events[2].target, textarea,
  1.2342 +     "runForceCommitTest: The 3rd event was fired on wrong event target #2");
  1.2343 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2344 +     "runForceCommitTest: the textarea still has composition #2");
  1.2345 +  is(textarea.value, "\u306E",
  1.2346 +     "runForceCommitTest: the textarea doesn't have the committed text #2");
  1.2347 +
  1.2348 +  // Make the composition in textarea commit by click in another editor (input)
  1.2349 +  textarea.focus();
  1.2350 +  textarea.value = "";
  1.2351 +  input.value = "";
  1.2352 +
  1.2353 +  synthesizeComposition({ type: "compositionstart" });
  1.2354 +
  1.2355 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2356 +  synthesizeText(
  1.2357 +    { "composition":
  1.2358 +      { "string": "\u306E",
  1.2359 +        "clauses":
  1.2360 +        [
  1.2361 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2362 +        ]
  1.2363 +      },
  1.2364 +      "caret": { "start": 1, "length": 0 }
  1.2365 +    });
  1.2366 +
  1.2367 +  events = [];
  1.2368 +  synthesizeMouseAtCenter(input, {});
  1.2369 +
  1.2370 +  is(events.length, 3,
  1.2371 +     "runForceCommitTest: wrong event count #3");
  1.2372 +  is(events[0].type, "text",
  1.2373 +     "runForceCommitTest: the 1st event must be text #3");
  1.2374 +  is(events[1].type, "compositionend",
  1.2375 +     "runForceCommitTest: the 2nd event must be compositionend #3");
  1.2376 +  is(events[2].type, "input",
  1.2377 +     "runForceCommitTest: the 3rd event must be input #3");
  1.2378 +  is(events[1].data, "\u306E",
  1.2379 +     "runForceCommitTest: compositionend has wrong data #3");
  1.2380 +  is(events[0].target, textarea,
  1.2381 +     "runForceCommitTest: The 1st event was fired on wrong event target #3");
  1.2382 +  is(events[1].target, textarea,
  1.2383 +     "runForceCommitTest: The 2nd event was fired on wrong event target #3");
  1.2384 +  is(events[2].target, textarea,
  1.2385 +     "runForceCommitTest: The 3rd event was fired on wrong event target #3");
  1.2386 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2387 +     "runForceCommitTest: the textarea still has composition #3");
  1.2388 +  ok(!getEditorIMESupport(input).isComposing,
  1.2389 +     "runForceCommitTest: the input has composition #3");
  1.2390 +  is(textarea.value, "\u306E",
  1.2391 +     "runForceCommitTest: the textarea doesn't have the committed text #3");
  1.2392 +  is(input.value, "",
  1.2393 +     "runForceCommitTest: the input has the committed text? #3");
  1.2394 +
  1.2395 +  // Make the composition in textarea commit by blur()
  1.2396 +  textarea.focus();
  1.2397 +  textarea.value = "";
  1.2398 +
  1.2399 +  synthesizeComposition({ type: "compositionstart" });
  1.2400 +
  1.2401 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2402 +  synthesizeText(
  1.2403 +    { "composition":
  1.2404 +      { "string": "\u306E",
  1.2405 +        "clauses":
  1.2406 +        [
  1.2407 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2408 +        ]
  1.2409 +      },
  1.2410 +      "caret": { "start": 1, "length": 0 }
  1.2411 +    });
  1.2412 +
  1.2413 +  events = [];
  1.2414 +  textarea.blur();
  1.2415 +
  1.2416 +  is(events.length, 3,
  1.2417 +     "runForceCommitTest: wrong event count #4");
  1.2418 +  is(events[0].type, "text",
  1.2419 +     "runForceCommitTest: the 1st event must be text #4");
  1.2420 +  is(events[1].type, "compositionend",
  1.2421 +     "runForceCommitTest: the 2nd event must be compositionend #4");
  1.2422 +  is(events[2].type, "input",
  1.2423 +     "runForceCommitTest: the 3rd event must be input #4");
  1.2424 +  is(events[1].data, "\u306E",
  1.2425 +     "runForceCommitTest: compositionend has wrong data #4");
  1.2426 +  is(events[0].target, textarea,
  1.2427 +     "runForceCommitTest: The 1st event was fired on wrong event target #4");
  1.2428 +  is(events[1].target, textarea,
  1.2429 +     "runForceCommitTest: The 2nd event was fired on wrong event target #4");
  1.2430 +  is(events[2].target, textarea,
  1.2431 +     "runForceCommitTest: The 3rd event was fired on wrong event target #4");
  1.2432 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2433 +     "runForceCommitTest: the textarea still has composition #4");
  1.2434 +  is(textarea.value, "\u306E",
  1.2435 +     "runForceCommitTest: the textarea doesn't have the committed text #4");
  1.2436 +
  1.2437 +  // Make the composition in textarea commit by input.focus()
  1.2438 +  textarea.focus();
  1.2439 +  textarea.value = "";
  1.2440 +  input.value = "";
  1.2441 +
  1.2442 +  synthesizeComposition({ type: "compositionstart" });
  1.2443 +
  1.2444 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2445 +  synthesizeText(
  1.2446 +    { "composition":
  1.2447 +      { "string": "\u306E",
  1.2448 +        "clauses":
  1.2449 +        [
  1.2450 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2451 +        ]
  1.2452 +      },
  1.2453 +      "caret": { "start": 1, "length": 0 }
  1.2454 +    });
  1.2455 +
  1.2456 +  events = [];
  1.2457 +  input.focus();
  1.2458 +
  1.2459 +  is(events.length, 3,
  1.2460 +     "runForceCommitTest: wrong event count #5");
  1.2461 +  is(events[0].type, "text",
  1.2462 +     "runForceCommitTest: the 1st event must be text #5");
  1.2463 +  is(events[1].type, "compositionend",
  1.2464 +     "runForceCommitTest: the 2nd event must be compositionend #5");
  1.2465 +  is(events[2].type, "input",
  1.2466 +     "runForceCommitTest: the 3rd event must be input #5");
  1.2467 +  is(events[1].data, "\u306E",
  1.2468 +     "runForceCommitTest: compositionend has wrong data #5");
  1.2469 +  is(events[0].target, textarea,
  1.2470 +     "runForceCommitTest: The 1st event was fired on wrong event target #5");
  1.2471 +  is(events[1].target, textarea,
  1.2472 +     "runForceCommitTest: The 2nd event was fired on wrong event target #5");
  1.2473 +  is(events[2].target, textarea,
  1.2474 +     "runForceCommitTest: The 3rd event was fired on wrong event target #5");
  1.2475 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2476 +     "runForceCommitTest: the textarea still has composition #5");
  1.2477 +  ok(!getEditorIMESupport(input).isComposing,
  1.2478 +     "runForceCommitTest: the input has composition #5");
  1.2479 +  is(textarea.value, "\u306E",
  1.2480 +     "runForceCommitTest: the textarea doesn't have the committed text #5");
  1.2481 +  is(input.value, "",
  1.2482 +     "runForceCommitTest: the input has the committed text? #5");
  1.2483 +
  1.2484 +  // Make the composition in textarea commit by click in another document's editor
  1.2485 +  textarea.focus();
  1.2486 +  textarea.value = "";
  1.2487 +  textareaInFrame.value = "";
  1.2488 +
  1.2489 +  synthesizeComposition({ type: "compositionstart" });
  1.2490 +
  1.2491 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2492 +  synthesizeText(
  1.2493 +    { "composition":
  1.2494 +      { "string": "\u306E",
  1.2495 +        "clauses":
  1.2496 +        [
  1.2497 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2498 +        ]
  1.2499 +      },
  1.2500 +      "caret": { "start": 1, "length": 0 }
  1.2501 +    });
  1.2502 +
  1.2503 +  events = [];
  1.2504 +  synthesizeMouseAtCenter(textareaInFrame, {}, iframe.contentWindow);
  1.2505 +
  1.2506 +  is(events.length, 3,
  1.2507 +     "runForceCommitTest: wrong event count #6");
  1.2508 +  is(events[0].type, "text",
  1.2509 +     "runForceCommitTest: the 1st event must be text #6");
  1.2510 +  is(events[1].type, "compositionend",
  1.2511 +     "runForceCommitTest: the 2nd event must be compositionend #6");
  1.2512 +  is(events[2].type, "input",
  1.2513 +     "runForceCommitTest: the 3rd event must be input #6");
  1.2514 +  is(events[1].data, "\u306E",
  1.2515 +     "runForceCommitTest: compositionend has wrong data #6");
  1.2516 +  is(events[0].target, textarea,
  1.2517 +     "runForceCommitTest: The 1st event was fired on wrong event target #6");
  1.2518 +  is(events[1].target, textarea,
  1.2519 +     "runForceCommitTest: The 2nd event was fired on wrong event target #6");
  1.2520 +  is(events[2].target, textarea,
  1.2521 +     "runForceCommitTest: The 3rd event was fired on wrong event target #6");
  1.2522 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2523 +     "runForceCommitTest: the textarea still has composition #6");
  1.2524 +  ok(!getEditorIMESupport(textareaInFrame).isComposing,
  1.2525 +     "runForceCommitTest: the textarea in frame has composition #6");
  1.2526 +  is(textarea.value, "\u306E",
  1.2527 +     "runForceCommitTest: the textarea doesn't have the committed text #6");
  1.2528 +  is(textareaInFrame.value, "",
  1.2529 +     "runForceCommitTest: the textarea in frame has the committed text? #6");
  1.2530 +
  1.2531 +  // Make the composition in textarea commit by another document's editor's focus()
  1.2532 +  textarea.focus();
  1.2533 +  textarea.value = "";
  1.2534 +  textareaInFrame.value = "";
  1.2535 +
  1.2536 +  synthesizeComposition({ type: "compositionstart" });
  1.2537 +
  1.2538 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2539 +  synthesizeText(
  1.2540 +    { "composition":
  1.2541 +      { "string": "\u306E",
  1.2542 +        "clauses":
  1.2543 +        [
  1.2544 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2545 +        ]
  1.2546 +      },
  1.2547 +      "caret": { "start": 1, "length": 0 }
  1.2548 +    });
  1.2549 +
  1.2550 +  events = [];
  1.2551 +  textareaInFrame.focus();
  1.2552 +
  1.2553 +  is(events.length, 3,
  1.2554 +     "runForceCommitTest: wrong event count #7");
  1.2555 +  is(events[0].type, "text",
  1.2556 +     "runForceCommitTest: the 1st event must be text #7");
  1.2557 +  is(events[1].type, "compositionend",
  1.2558 +     "runForceCommitTest: the 2nd event must be compositionend #7");
  1.2559 +  is(events[2].type, "input",
  1.2560 +     "runForceCommitTest: the 3rd event must be input #7");
  1.2561 +  is(events[1].data, "\u306E",
  1.2562 +     "runForceCommitTest: compositionend has wrong data #7");
  1.2563 +  is(events[0].target, textarea,
  1.2564 +     "runForceCommitTest: The 1st event was fired on wrong event target #7");
  1.2565 +  is(events[1].target, textarea,
  1.2566 +     "runForceCommitTest: The 2nd event was fired on wrong event target #7");
  1.2567 +  is(events[2].target, textarea,
  1.2568 +     "runForceCommitTest: The 3rd event was fired on wrong event target #7");
  1.2569 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2570 +     "runForceCommitTest: the textarea still has composition #7");
  1.2571 +  ok(!getEditorIMESupport(textareaInFrame).isComposing,
  1.2572 +     "runForceCommitTest: the textarea in frame has composition #7");
  1.2573 +  is(textarea.value, "\u306E",
  1.2574 +     "runForceCommitTest: the textarea doesn't have the committed text #7");
  1.2575 +  is(textareaInFrame.value, "",
  1.2576 +     "runForceCommitTest: the textarea in frame has the committed text? #7");
  1.2577 +
  1.2578 +  // Make the composition in a textarea commit by click in another editable document
  1.2579 +  textarea.focus();
  1.2580 +  textarea.value = "";
  1.2581 +  iframe2.contentDocument.body.innerHTML = "Text in the Body";
  1.2582 +  var iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  1.2583 +
  1.2584 +  synthesizeComposition({ type: "compositionstart" });
  1.2585 +
  1.2586 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2587 +  synthesizeText(
  1.2588 +    { "composition":
  1.2589 +      { "string": "\u306E",
  1.2590 +        "clauses":
  1.2591 +        [
  1.2592 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2593 +        ]
  1.2594 +      },
  1.2595 +      "caret": { "start": 1, "length": 0 }
  1.2596 +    });
  1.2597 +
  1.2598 +  events = [];
  1.2599 +  synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
  1.2600 +
  1.2601 +  is(events.length, 3,
  1.2602 +     "runForceCommitTest: wrong event count #8");
  1.2603 +  is(events[0].type, "text",
  1.2604 +     "runForceCommitTest: the 1st event must be text #8");
  1.2605 +  is(events[1].type, "compositionend",
  1.2606 +     "runForceCommitTest: the 2nd event must be compositionend #8");
  1.2607 +  is(events[2].type, "input",
  1.2608 +     "runForceCommitTest: the 3rd event must be input #8");
  1.2609 +  is(events[1].data, "\u306E",
  1.2610 +     "runForceCommitTest: compositionend has wrong data #8");
  1.2611 +  is(events[0].target, textarea,
  1.2612 +     "runForceCommitTest: The 1st event was fired on wrong event target #8");
  1.2613 +  is(events[1].target, textarea,
  1.2614 +     "runForceCommitTest: The 2nd event was fired on wrong event target #8");
  1.2615 +  is(events[2].target, textarea,
  1.2616 +     "runForceCommitTest: The 3rd event was fired on wrong event target #8");
  1.2617 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2618 +     "runForceCommitTest: the textarea still has composition #8");
  1.2619 +  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  1.2620 +     "runForceCommitTest: the editable document has composition #8");
  1.2621 +  is(textarea.value, "\u306E",
  1.2622 +     "runForceCommitTest: the textarea doesn't have the committed text #8");
  1.2623 +  is(iframe2.contentDocument.body.innerHTML, iframe2BodyInnerHTML,
  1.2624 +     "runForceCommitTest: the editable document has the committed text? #8");
  1.2625 +
  1.2626 +  // Make the composition in an editable document commit by click in it
  1.2627 +  iframe2.contentWindow.focus();
  1.2628 +  iframe2.contentDocument.body.innerHTML = "Text in the Body";
  1.2629 +  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  1.2630 +
  1.2631 +  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  1.2632 +
  1.2633 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  1.2634 +  synthesizeText(
  1.2635 +    { "composition":
  1.2636 +      { "string": "\u306E",
  1.2637 +        "clauses":
  1.2638 +        [
  1.2639 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2640 +        ]
  1.2641 +      },
  1.2642 +      "caret": { "start": 1, "length": 0 }
  1.2643 +    }, iframe2.contentWindow);
  1.2644 +
  1.2645 +  events = [];
  1.2646 +  synthesizeMouseAtCenter(iframe2.contentDocument.body, {}, iframe2.contentWindow);
  1.2647 +
  1.2648 +  is(events.length, 3,
  1.2649 +     "runForceCommitTest: wrong event count #9");
  1.2650 +  is(events[0].type, "text",
  1.2651 +     "runForceCommitTest: the 1st event must be text #9");
  1.2652 +  is(events[1].type, "compositionend",
  1.2653 +     "runForceCommitTest: the 2nd event must be compositionend #9");
  1.2654 +  is(events[2].type, "input",
  1.2655 +     "runForceCommitTest: the 3rd event must be input #9");
  1.2656 +  is(events[1].data, "\u306E",
  1.2657 +     "runForceCommitTest: compositionend has wrong data #9");
  1.2658 +  is(events[0].target, iframe2.contentDocument.body,
  1.2659 +     "runForceCommitTest: The 1st event was fired on wrong event target #9");
  1.2660 +  is(events[1].target, iframe2.contentDocument.body,
  1.2661 +     "runForceCommitTest: The 2nd event was fired on wrong event target #9");
  1.2662 +  is(events[2].target, iframe2.contentDocument.body,
  1.2663 +     "runForceCommitTest: The 3rd event was fired on wrong event target #9");
  1.2664 +  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  1.2665 +     "runForceCommitTest: the editable document still has composition #9");
  1.2666 +  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  1.2667 +     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  1.2668 +     "runForceCommitTest: the editable document doesn't have the committed text #9");
  1.2669 +
  1.2670 +  // Make the composition in an editable document commit by click in another document's editor
  1.2671 +  textarea.value = "";
  1.2672 +  iframe2.contentWindow.focus();
  1.2673 +  iframe2.contentDocument.body.innerHTML = "Text in the Body";
  1.2674 +  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  1.2675 +
  1.2676 +  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  1.2677 +
  1.2678 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  1.2679 +  synthesizeText(
  1.2680 +    { "composition":
  1.2681 +      { "string": "\u306E",
  1.2682 +        "clauses":
  1.2683 +        [
  1.2684 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2685 +        ]
  1.2686 +      },
  1.2687 +      "caret": { "start": 1, "length": 0 }
  1.2688 +    }, iframe2.contentWindow);
  1.2689 +
  1.2690 +  events = [];
  1.2691 +  synthesizeMouseAtCenter(textarea, {});
  1.2692 +
  1.2693 +  is(events.length, 3,
  1.2694 +     "runForceCommitTest: wrong event count #10");
  1.2695 +  is(events[0].type, "text",
  1.2696 +     "runForceCommitTest: the 1st event must be text #10");
  1.2697 +  is(events[1].type, "compositionend",
  1.2698 +     "runForceCommitTest: the 2nd event must be compositionend #10");
  1.2699 +  is(events[2].type, "input",
  1.2700 +     "runForceCommitTest: the 3rd event must be input #10");
  1.2701 +  is(events[1].data, "\u306E",
  1.2702 +     "runForceCommitTest: compositionend has wrong data #10");
  1.2703 +  is(events[0].target, iframe2.contentDocument.body,
  1.2704 +     "runForceCommitTest: The 1st event was fired on wrong event target #10");
  1.2705 +  is(events[1].target, iframe2.contentDocument.body,
  1.2706 +     "runForceCommitTest: The 2nd event was fired on wrong event target #10");
  1.2707 +  is(events[2].target, iframe2.contentDocument.body,
  1.2708 +     "runForceCommitTest: The 3rd event was fired on wrong event target #10");
  1.2709 +  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  1.2710 +     "runForceCommitTest: the editable document still has composition #10");
  1.2711 +  ok(!getEditorIMESupport(textarea).isComposing,
  1.2712 +     "runForceCommitTest: the textarea has composition #10");
  1.2713 +  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  1.2714 +     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  1.2715 +     "runForceCommitTest: the editable document doesn't have the committed text #10");
  1.2716 +  is(textarea.value, "",
  1.2717 +     "runForceCommitTest: the textarea has the committed text? #10");
  1.2718 +
  1.2719 +  // Make the composition in an editable document commit by click in the another editable document
  1.2720 +  iframe2.contentWindow.focus();
  1.2721 +  iframe2.contentDocument.body.innerHTML = "Text in the Body";
  1.2722 +  iframe2BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  1.2723 +  iframe3.contentDocument.body.innerHTML = "Text in the Body";
  1.2724 +  iframe3BodyInnerHTML = iframe2.contentDocument.body.innerHTML;
  1.2725 +
  1.2726 +  synthesizeComposition({ type: "compositionstart" }, iframe2.contentWindow);
  1.2727 +
  1.2728 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" }, iframe2.contentWindow);
  1.2729 +  synthesizeText(
  1.2730 +    { "composition":
  1.2731 +      { "string": "\u306E",
  1.2732 +        "clauses":
  1.2733 +        [
  1.2734 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2735 +        ]
  1.2736 +      },
  1.2737 +      "caret": { "start": 1, "length": 0 }
  1.2738 +    }, iframe2.contentWindow);
  1.2739 +
  1.2740 +  events = [];
  1.2741 +  synthesizeMouseAtCenter(iframe3.contentDocument.body, {}, iframe3.contentWindow);
  1.2742 +
  1.2743 +  is(events.length, 3,
  1.2744 +     "runForceCommitTest: wrong event count #11");
  1.2745 +  is(events[0].type, "text",
  1.2746 +     "runForceCommitTest: the 1st event must be text #11");
  1.2747 +  is(events[1].type, "compositionend",
  1.2748 +     "runForceCommitTest: the 2nd event must be compositionend #11");
  1.2749 +  is(events[2].type, "input",
  1.2750 +     "runForceCommitTest: the 3rd event must be input #11");
  1.2751 +  is(events[1].data, "\u306E",
  1.2752 +     "runForceCommitTest: compositionend has wrong data #11");
  1.2753 +  is(events[0].target, iframe2.contentDocument.body,
  1.2754 +     "runForceCommitTest: The 1st event was fired on wrong event target #11");
  1.2755 +  is(events[1].target, iframe2.contentDocument.body,
  1.2756 +     "runForceCommitTest: The 2nd event was fired on wrong event target #11");
  1.2757 +  is(events[2].target, iframe2.contentDocument.body,
  1.2758 +     "runForceCommitTest: The 3rd event was fired on wrong event target #11");
  1.2759 +  ok(!getHTMLEditorIMESupport(iframe2.contentWindow).isComposing,
  1.2760 +     "runForceCommitTest: the editable document still has composition #11");
  1.2761 +  ok(!getHTMLEditorIMESupport(iframe3.contentWindow).isComposing,
  1.2762 +     "runForceCommitTest: the other editable document has composition #11");
  1.2763 +  ok(iframe2.contentDocument.body.innerHTML != iframe2BodyInnerHTML &&
  1.2764 +     iframe2.contentDocument.body.innerHTML.indexOf("\u306E") >= 0,
  1.2765 +     "runForceCommitTest: the editable document doesn't have the committed text #11");
  1.2766 +  is(iframe3.contentDocument.body.innerHTML, iframe3BodyInnerHTML,
  1.2767 +     "runForceCommitTest: the other editable document has the committed text? #11");
  1.2768 +
  1.2769 +  window.removeEventListener("compositionstart", eventHandler, true);
  1.2770 +  window.removeEventListener("compositionupdate", eventHandler, true);
  1.2771 +  window.removeEventListener("compositionend", eventHandler, true);
  1.2772 +  window.removeEventListener("input", eventHandler, true);
  1.2773 +  window.removeEventListener("text", eventHandler, true);
  1.2774 +}
  1.2775 +
  1.2776 +function runBug811755Test()
  1.2777 +{
  1.2778 +  iframe2.contentDocument.body.innerHTML = "<div>content<br/></div>";
  1.2779 +  iframe2.contentWindow.focus();
  1.2780 +  // Query everything
  1.2781 +  var textContent = synthesizeQueryTextContent(0, 10);
  1.2782 +  if (!checkQueryContentResult(textContent, "runBug811755Test: synthesizeQueryTextContent #1")) {
  1.2783 +    return false;
  1.2784 +  }
  1.2785 +  // Query everything but specify exact end offset, which should be immediately after the <br> node
  1.2786 +  // If PreContentIterator is used, the next node after <br> is the node after </div>.
  1.2787 +  // If ContentIterator is used, the next node is the <div> node itself. In this case, the end
  1.2788 +  // node ends up being before the start node, and an empty string is returned.
  1.2789 +  var queryContent = synthesizeQueryTextContent(0, textContent.text.length);
  1.2790 +  if (!checkQueryContentResult(queryContent, "runBug811755Test: synthesizeQueryTextContent #2")) {
  1.2791 +    return false;
  1.2792 +  }
  1.2793 +  is(queryContent.text, textContent.text, "runBug811755Test: two queried texts don't match");
  1.2794 +  return queryContent.text == textContent.text;
  1.2795 +}
  1.2796 +
  1.2797 +function runIsComposingTest()
  1.2798 +{
  1.2799 +  var expectedIsComposing = false;
  1.2800 +  var descriptionBase = "runIsComposingTest: ";
  1.2801 +  var description = "";
  1.2802 +
  1.2803 +  function eventHandler(aEvent)
  1.2804 +  {
  1.2805 +    if (aEvent.type == "keydown" || aEvent.type == "keyup") {
  1.2806 +      is(aEvent.isComposing, expectedIsComposing,
  1.2807 +         "runIsComposingTest: " + description + " (type=" + aEvent.type + ", key=" + aEvent.key + ")");
  1.2808 +    } else {
  1.2809 +      is(aEvent.isComposing, expectedIsComposing,
  1.2810 +         "runIsComposingTest: " + description + " (type=" + aEvent.type + ")");
  1.2811 +    }
  1.2812 +  }
  1.2813 +
  1.2814 +  textarea.addEventListener("keydown", eventHandler, true);
  1.2815 +  textarea.addEventListener("keypress", eventHandler, true);
  1.2816 +  textarea.addEventListener("keyup", eventHandler, true);
  1.2817 +  textarea.addEventListener("input", eventHandler, true);
  1.2818 +
  1.2819 +  textarea.focus();
  1.2820 +  textarea.value = "";
  1.2821 +
  1.2822 +  // XXX These cases shouldn't occur in actual native key events because we
  1.2823 +  //     don't dispatch key events while composition (bug 354358).
  1.2824 +  expectedIsComposing = false;
  1.2825 +  description = "events before dispatching compositionstart";
  1.2826 +  synthesizeKey("VK_LEFT", {});
  1.2827 +
  1.2828 +  synthesizeKey("a", { type: "keydown" });
  1.2829 +  synthesizeComposition({ type: "compositionstart" });
  1.2830 +  expectedIsComposing = true;
  1.2831 +  description = "events after dispatching compositionstart";
  1.2832 +  synthesizeComposition({ type: "compositionupdate", data: "\u3042" });
  1.2833 +  synthesizeText(
  1.2834 +    { "composition":
  1.2835 +      { "string": "\u3042",
  1.2836 +        "clauses":
  1.2837 +        [
  1.2838 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2839 +        ]
  1.2840 +      },
  1.2841 +      "caret": { "start": 1, "length": 0 }
  1.2842 +    });
  1.2843 +  synthesizeKey("a", { type: "keyup" });
  1.2844 +
  1.2845 +  // Although, firing keypress event during composition is a bug.
  1.2846 +  synthesizeKey("VK_INSERT", {});
  1.2847 +
  1.2848 +  description = "events for committing composition string";
  1.2849 +  synthesizeKey("VK_RETURN", { type: "keydown" });
  1.2850 +  synthesizeText(
  1.2851 +    { "composition":
  1.2852 +      { "string": "\u3042",
  1.2853 +        "clauses":
  1.2854 +        [
  1.2855 +          { "length": 0, "attr": 0 }
  1.2856 +        ]
  1.2857 +      },
  1.2858 +      "caret": { "start": 1, "length": 0 }
  1.2859 +    });
  1.2860 +
  1.2861 +  // input event will be fired by synthesizing compositionend event.
  1.2862 +  // Then, its isComposing should be false.
  1.2863 +  expectedIsComposing = false;
  1.2864 +  description = "events after dispatching compositionend";
  1.2865 +  synthesizeComposition({ type: "compositionend" });
  1.2866 +  synthesizeKey("VK_RETURN", { type: "keyup" });
  1.2867 +
  1.2868 +  textarea.removeEventListener("keydown", eventHandler, true);
  1.2869 +  textarea.removeEventListener("keypress", eventHandler, true);
  1.2870 +  textarea.removeEventListener("keyup", eventHandler, true);
  1.2871 +  textarea.removeEventListener("input", eventHandler, true);
  1.2872 +
  1.2873 +  textarea.value = "";
  1.2874 +}
  1.2875 +
  1.2876 +function runRemoveContentTest(aCallback)
  1.2877 +{
  1.2878 +  var events = [];
  1.2879 +  function eventHandler(aEvent)
  1.2880 +  {
  1.2881 +    events.push(aEvent);
  1.2882 +  }
  1.2883 +  textarea.addEventListener("compositionstart", eventHandler, true);
  1.2884 +  textarea.addEventListener("compositionupdate", eventHandler, true);
  1.2885 +  textarea.addEventListener("compositionend", eventHandler, true);
  1.2886 +  textarea.addEventListener("input", eventHandler, true);
  1.2887 +  textarea.addEventListener("text", eventHandler, true);
  1.2888 +
  1.2889 +  textarea.focus();
  1.2890 +  textarea.value = "";
  1.2891 +
  1.2892 +  synthesizeComposition({ type: "compositionstart" });
  1.2893 +
  1.2894 +  synthesizeComposition({ type: "compositionupdate", data: "\u306E" });
  1.2895 +  synthesizeText(
  1.2896 +    { "composition":
  1.2897 +      { "string": "\u306E",
  1.2898 +        "clauses":
  1.2899 +        [
  1.2900 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.2901 +        ]
  1.2902 +      },
  1.2903 +      "caret": { "start": 1, "length": 0 }
  1.2904 +    });
  1.2905 +
  1.2906 +  var nextSibling = textarea.nextSibling;
  1.2907 +  var parent = textarea.parentElement;
  1.2908 +
  1.2909 +  events = [];
  1.2910 +  parent.removeChild(textarea);
  1.2911 +
  1.2912 +  hitEventLoop(function () {
  1.2913 +    // XXX Currently, "input" event isn't fired on removed content.
  1.2914 +    is(events.length, 3,
  1.2915 +       "runRemoveContentTest: wrong event count #1");
  1.2916 +    is(events[0].type, "compositionupdate",
  1.2917 +       "runRemoveContentTest: the 1st event must be compositionupdate #1");
  1.2918 +    is(events[1].type, "text",
  1.2919 +       "runRemoveContentTest: the 2nd event must be text #1");
  1.2920 +    is(events[2].type, "compositionend",
  1.2921 +       "runRemoveContentTest: the 3rd event must be compositionend #1");
  1.2922 +    is(events[0].data, "",
  1.2923 +       "runRemoveContentTest: compositionupdate has wrong data #1");
  1.2924 +    is(events[2].data, "",
  1.2925 +       "runRemoveContentTest: compositionend has wrong data #1");
  1.2926 +    is(events[0].target, textarea,
  1.2927 +       "runRemoveContentTest: The 1st event was fired on wrong event target #1");
  1.2928 +    is(events[1].target, textarea,
  1.2929 +       "runRemoveContentTest: The 2nd event was fired on wrong event target #1");
  1.2930 +    is(events[2].target, textarea,
  1.2931 +       "runRemoveContentTest: The 3rd event was fired on wrong event target #1");
  1.2932 +    ok(!getEditorIMESupport(textarea).isComposing,
  1.2933 +       "runRemoveContentTest: the textarea still has composition #1");
  1.2934 +    todo_is(textarea.value, "",
  1.2935 +       "runRemoveContentTest: the textarea has the committed text? #1");
  1.2936 +
  1.2937 +    parent.insertBefore(textarea, nextSibling);
  1.2938 +
  1.2939 +    textarea.focus();
  1.2940 +    textarea.value = "";
  1.2941 +
  1.2942 +    synthesizeComposition({ type: "compositionstart" });
  1.2943 +
  1.2944 +    events = [];
  1.2945 +    parent.removeChild(textarea);
  1.2946 +
  1.2947 +    hitEventLoop(function () {
  1.2948 +      // XXX Currently, "input" event isn't fired on removed content.
  1.2949 +      is(events.length, 1,
  1.2950 +         "runRemoveContentTest: wrong event count #2");
  1.2951 +      is(events[0].type, "compositionend",
  1.2952 +         "runRemoveContentTest: the 1st event must be compositionend #2");
  1.2953 +      is(events[0].data, "",
  1.2954 +         "runRemoveContentTest: compositionupdate has wrong data #2");
  1.2955 +      is(events[0].target, textarea,
  1.2956 +         "runRemoveContentTest: The 1st event was fired on wrong event target #2");
  1.2957 +      ok(!getEditorIMESupport(textarea).isComposing,
  1.2958 +         "runRemoveContentTest: the textarea still has composition #2");
  1.2959 +      is(textarea.value, "",
  1.2960 +         "runRemoveContentTest: the textarea has the committed text? #2");
  1.2961 +
  1.2962 +      parent.insertBefore(textarea, nextSibling);
  1.2963 +
  1.2964 +      textarea.removeEventListener("compositionstart", eventHandler, true);
  1.2965 +      textarea.removeEventListener("compositionupdate", eventHandler, true);
  1.2966 +      textarea.removeEventListener("compositionend", eventHandler, true);
  1.2967 +      textarea.removeEventListener("input", eventHandler, true);
  1.2968 +      textarea.removeEventListener("text", eventHandler, true);
  1.2969 +
  1.2970 +      SimpleTest.executeSoon(aCallback);
  1.2971 +    }, 50);
  1.2972 +  }, 50);
  1.2973 +}
  1.2974 +
  1.2975 +function runTestOnAnotherContext(aPanelOrFrame, aFocusedEditor, aTestName)
  1.2976 +{
  1.2977 +  aFocusedEditor.value = "";
  1.2978 +
  1.2979 +  var editorRect = synthesizeQueryEditorRect();
  1.2980 +  if (!checkQueryContentResult(editorRect, aTestName + ": editorRect")) {
  1.2981 +    return;
  1.2982 +  }
  1.2983 +
  1.2984 +  var r = aPanelOrFrame.getBoundingClientRect();
  1.2985 +  var parentRect = { "left": r.left, "top": r.top, "width": r.right - r.left,
  1.2986 +                     "height": r.bottom - r.top };
  1.2987 +  checkRectContainsRect(editorRect, parentRect, aTestName +
  1.2988 +                        ": the editor rect coordinates are wrong");
  1.2989 +
  1.2990 +  // start composition
  1.2991 +  synthesizeComposition({ type: "compositionstart" });
  1.2992 +
  1.2993 +  // input characters
  1.2994 +  synthesizeComposition({ type: "compositionupdate",
  1.2995 +                          data: "\u3078\u3093\u3057\u3093" });
  1.2996 +  synthesizeText(
  1.2997 +    { "composition":
  1.2998 +      { "string": "\u3078\u3093\u3057\u3093",
  1.2999 +        "clauses":
  1.3000 +        [
  1.3001 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3002 +        ]
  1.3003 +      },
  1.3004 +      "caret": { "start": 4, "length": 0 }
  1.3005 +    });
  1.3006 +
  1.3007 +  if (!checkContent("\u3078\u3093\u3057\u3093", aTestName, "#1-1") ||
  1.3008 +      !checkSelection(4, "", aTestName, "#1-1")) {
  1.3009 +    return;
  1.3010 +  }
  1.3011 +
  1.3012 +  // convert them #1
  1.3013 +  synthesizeComposition({ type: "compositionupdate", data: "\u8FD4\u4FE1" });
  1.3014 +  synthesizeText(
  1.3015 +    { "composition":
  1.3016 +      { "string": "\u8FD4\u4FE1",
  1.3017 +        "clauses":
  1.3018 +        [
  1.3019 +          { "length": 2,
  1.3020 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
  1.3021 +        ]
  1.3022 +      },
  1.3023 +      "caret": { "start": 2, "length": 0 }
  1.3024 +    });
  1.3025 +
  1.3026 +  if (!checkContent("\u8FD4\u4FE1", aTestName, "#1-2") ||
  1.3027 +      !checkSelection(2, "", aTestName, "#1-2")) {
  1.3028 +    return;
  1.3029 +  }
  1.3030 +
  1.3031 +  // convert them #2
  1.3032 +  synthesizeComposition({ type: "compositionupdate", data: "\u5909\u8EAB" });
  1.3033 +  synthesizeText(
  1.3034 +    { "composition":
  1.3035 +      { "string": "\u5909\u8EAB",
  1.3036 +        "clauses":
  1.3037 +        [
  1.3038 +          { "length": 2,
  1.3039 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
  1.3040 +        ]
  1.3041 +      },
  1.3042 +      "caret": { "start": 2, "length": 0 }
  1.3043 +    });
  1.3044 +
  1.3045 +  if (!checkContent("\u5909\u8EAB", aTestName, "#1-3") ||
  1.3046 +      !checkSelection(2, "", aTestName, "#1-3")) {
  1.3047 +    return;
  1.3048 +  }
  1.3049 +
  1.3050 +  // commit them
  1.3051 +  synthesizeText(
  1.3052 +    { "composition":
  1.3053 +      { "string": "\u5909\u8EAB",
  1.3054 +        "clauses":
  1.3055 +        [
  1.3056 +          { "length": 0, "attr": 0 }
  1.3057 +        ]
  1.3058 +      },
  1.3059 +      "caret": { "start": 2, "length": 0 }
  1.3060 +    });
  1.3061 +
  1.3062 +  if (!checkContent("\u5909\u8EAB", aTestName, "#1-4") ||
  1.3063 +      !checkSelection(2, "", aTestName, "#1-4")) {
  1.3064 +    return;
  1.3065 +  }
  1.3066 +
  1.3067 +  synthesizeComposition({ type: "compositionend", data: "\u5909\u8EAB" });
  1.3068 +
  1.3069 +  is(aFocusedEditor.value, "\u5909\u8EAB",
  1.3070 +     aTestName + ": composition isn't in the focused editor");
  1.3071 +  if (aFocusedEditor.value != "\u5909\u8EAB") {
  1.3072 +    return;
  1.3073 +  }
  1.3074 +
  1.3075 +  var textRect = synthesizeQueryTextRect(0, 1);
  1.3076 +  var caretRect = synthesizeQueryCaretRect(2);
  1.3077 +  if (!checkQueryContentResult(textRect,
  1.3078 +                               aTestName + ": synthesizeQueryTextRect") ||
  1.3079 +      !checkQueryContentResult(caretRect,
  1.3080 +                               aTestName + ": synthesizeQueryCaretRect")) {
  1.3081 +    return;
  1.3082 +  }
  1.3083 +  checkRectContainsRect(textRect, editorRect, aTestName + ":testRect");
  1.3084 +  checkRectContainsRect(caretRect, editorRect, aTestName + ":caretRect");
  1.3085 +}
  1.3086 +
  1.3087 +function runFrameTest()
  1.3088 +{
  1.3089 +  textareaInFrame.focus();
  1.3090 +  runTestOnAnotherContext(iframe, textareaInFrame, "runFrameTest");
  1.3091 +  runCharAtPointTest(textareaInFrame, "textarea in the iframe");
  1.3092 +}
  1.3093 +
  1.3094 +var gPanelShown = false;
  1.3095 +var gPanelFocused = false;
  1.3096 +function onPanelShown(aEvent)
  1.3097 +{
  1.3098 +  gPanelShown = true;
  1.3099 +  textbox.focus();
  1.3100 +  setTimeout(doPanelTest, 0);
  1.3101 +}
  1.3102 +
  1.3103 +function onFocusPanelTextbox(aEvent)
  1.3104 +{
  1.3105 +  gPanelFocused = true;
  1.3106 +  setTimeout(doPanelTest, 0);
  1.3107 +}
  1.3108 +
  1.3109 +var gIsPanelHiding = false;
  1.3110 +var gIsRunPanelTestInternal = false;
  1.3111 +function doPanelTest()
  1.3112 +{
  1.3113 +  if (!gPanelFocused || !gPanelShown) {
  1.3114 +    return;
  1.3115 +  }
  1.3116 +  if (gIsRunPanelTestInternal) {
  1.3117 +    return;
  1.3118 +  }
  1.3119 +  gIsRunPanelTestInternal = true;
  1.3120 +  runTestOnAnotherContext(panel, textbox, "runPanelTest");
  1.3121 +  runCharAtPointTest(textbox, "textbox in the panel");
  1.3122 +  gIsPanelHiding = true;
  1.3123 +  panel.hidePopup();
  1.3124 +}
  1.3125 +
  1.3126 +function onPanelHidden(aEvent)
  1.3127 +{
  1.3128 +  panel.hidden = true;
  1.3129 +  ok(gIsPanelHiding, "runPanelTest: the panel is hidden unexpectedly");
  1.3130 +  finish();
  1.3131 +}
  1.3132 +
  1.3133 +function runPanelTest()
  1.3134 +{
  1.3135 +  panel.hidden = false;
  1.3136 +  panel.openPopupAtScreen(window.screenX + window.outerWidth, 0, false);
  1.3137 +}
  1.3138 +
  1.3139 +function runMaxLengthTest()
  1.3140 +{
  1.3141 +  input.maxLength = 1;
  1.3142 +  input.value = "";
  1.3143 +  input.focus();
  1.3144 +
  1.3145 +  var kDesc ="runMaxLengthTest";
  1.3146 +
  1.3147 +  // start composition
  1.3148 +  synthesizeComposition({ type: "compositionstart" });
  1.3149 +
  1.3150 +  // input first character
  1.3151 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
  1.3152 +  synthesizeText(
  1.3153 +    { "composition":
  1.3154 +      { "string": "\u3089",
  1.3155 +        "clauses":
  1.3156 +        [
  1.3157 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3158 +        ]
  1.3159 +      },
  1.3160 +      "caret": { "start": 1, "length": 0 }
  1.3161 +    });
  1.3162 +
  1.3163 +  if (!checkContent("\u3089", kDesc, "#1-1") ||
  1.3164 +      !checkSelection(1, "", kDesc, "#1-1")) {
  1.3165 +    return;
  1.3166 +  }
  1.3167 +
  1.3168 +  // input second character
  1.3169 +  synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
  1.3170 +  synthesizeText(
  1.3171 +    { "composition":
  1.3172 +      { "string": "\u3089\u30FC",
  1.3173 +        "clauses":
  1.3174 +        [
  1.3175 +          { "length": 2, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3176 +        ]
  1.3177 +      },
  1.3178 +      "caret": { "start": 2, "length": 0 }
  1.3179 +    });
  1.3180 +
  1.3181 +  if (!checkContent("\u3089\u30FC", kDesc, "#1-2") ||
  1.3182 +      !checkSelection(2, "", kDesc, "#1-2")) {
  1.3183 +    return;
  1.3184 +  }
  1.3185 +
  1.3186 +  // input third character
  1.3187 +  synthesizeComposition({ type: "compositionupdate",
  1.3188 +                          data: "\u3089\u30FC\u3081" });
  1.3189 +  synthesizeText(
  1.3190 +    { "composition":
  1.3191 +      { "string": "\u3089\u30FC\u3081",
  1.3192 +        "clauses":
  1.3193 +        [
  1.3194 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3195 +        ]
  1.3196 +      },
  1.3197 +      "caret": { "start": 3, "length": 0 }
  1.3198 +    });
  1.3199 +
  1.3200 +  if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-3") ||
  1.3201 +      !checkSelection(3, "", kDesc, "#1-3")) {
  1.3202 +    return;
  1.3203 +  }
  1.3204 +
  1.3205 +  // input fourth character
  1.3206 +  synthesizeComposition({ type: "compositionupdate",
  1.3207 +                          data: "\u3089\u30FC\u3081\u3093" });
  1.3208 +  synthesizeText(
  1.3209 +    { "composition":
  1.3210 +      { "string": "\u3089\u30FC\u3081\u3093",
  1.3211 +        "clauses":
  1.3212 +        [
  1.3213 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3214 +        ]
  1.3215 +      },
  1.3216 +      "caret": { "start": 4, "length": 0 }
  1.3217 +    });
  1.3218 +
  1.3219 +  if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-4") ||
  1.3220 +      !checkSelection(4, "", kDesc, "#1-4")) {
  1.3221 +    return;
  1.3222 +  }
  1.3223 +
  1.3224 +
  1.3225 +  // backspace
  1.3226 +  synthesizeComposition({ type: "compositionupdate",
  1.3227 +                          data: "\u3089\u30FC\u3081" });
  1.3228 +  synthesizeText(
  1.3229 +    { "composition":
  1.3230 +      { "string": "\u3089\u30FC\u3081",
  1.3231 +        "clauses":
  1.3232 +        [
  1.3233 +          { "length": 3, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3234 +        ]
  1.3235 +      },
  1.3236 +      "caret": { "start": 3, "length": 0 }
  1.3237 +    });
  1.3238 +
  1.3239 +  if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-5") ||
  1.3240 +      !checkSelection(3, "", kDesc, "#1-5")) {
  1.3241 +    return;
  1.3242 +  }
  1.3243 +
  1.3244 +  // re-input
  1.3245 +  synthesizeComposition({ type: "compositionupdate",
  1.3246 +                          data: "\u3089\u30FC\u3081\u3093" });
  1.3247 +  synthesizeText(
  1.3248 +    { "composition":
  1.3249 +      { "string": "\u3089\u30FC\u3081\u3093",
  1.3250 +        "clauses":
  1.3251 +        [
  1.3252 +          { "length": 4, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3253 +        ]
  1.3254 +      },
  1.3255 +      "caret": { "start": 4, "length": 0 }
  1.3256 +    });
  1.3257 +
  1.3258 +  if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-6") ||
  1.3259 +      !checkSelection(4, "", kDesc, "#1-6")) {
  1.3260 +    return;
  1.3261 +  }
  1.3262 +
  1.3263 +  synthesizeComposition({ type: "compositionupdate",
  1.3264 +                          data: "\u3089\u30FC\u3081\u3093\u3055" });
  1.3265 +  synthesizeText(
  1.3266 +    { "composition":
  1.3267 +      { "string": "\u3089\u30FC\u3081\u3093\u3055",
  1.3268 +        "clauses":
  1.3269 +        [
  1.3270 +          { "length": 5, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3271 +        ]
  1.3272 +      },
  1.3273 +      "caret": { "start": 5, "length": 0 }
  1.3274 +    });
  1.3275 +
  1.3276 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", kDesc, "#1-7") ||
  1.3277 +      !checkSelection(5, "", kDesc, "#1-7")) {
  1.3278 +    return;
  1.3279 +  }
  1.3280 +
  1.3281 +  synthesizeComposition({ type: "compositionupdate",
  1.3282 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
  1.3283 +  synthesizeText(
  1.3284 +    { "composition":
  1.3285 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
  1.3286 +        "clauses":
  1.3287 +        [
  1.3288 +          { "length": 6, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3289 +        ]
  1.3290 +      },
  1.3291 +      "caret": { "start": 6, "length": 0 }
  1.3292 +    });
  1.3293 +
  1.3294 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", kDesc, "#1-8") ||
  1.3295 +      !checkSelection(6, "", kDesc, "#1-8")) {
  1.3296 +    return;
  1.3297 +  }
  1.3298 +
  1.3299 +  synthesizeComposition({ type: "compositionupdate",
  1.3300 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
  1.3301 +  synthesizeText(
  1.3302 +    { "composition":
  1.3303 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
  1.3304 +        "clauses":
  1.3305 +        [
  1.3306 +          { "length": 7, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3307 +        ]
  1.3308 +      },
  1.3309 +      "caret": { "start": 7, "length": 0 }
  1.3310 +    });
  1.3311 +
  1.3312 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
  1.3313 +                    kDesc, "#1-8") ||
  1.3314 +      !checkSelection(7, "", kDesc, "#1-8")) {
  1.3315 +    return;
  1.3316 +  }
  1.3317 +
  1.3318 +  synthesizeComposition({ type: "compositionupdate",
  1.3319 +                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
  1.3320 +  synthesizeText(
  1.3321 +    { "composition":
  1.3322 +      { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
  1.3323 +        "clauses":
  1.3324 +        [
  1.3325 +          { "length": 8, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3326 +        ]
  1.3327 +      },
  1.3328 +      "caret": { "start": 8, "length": 0 }
  1.3329 +    });
  1.3330 +
  1.3331 +  if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
  1.3332 +                    kDesc, "#1-9") ||
  1.3333 +      !checkSelection(8, "", kDesc, "#1-9")) {
  1.3334 +    return;
  1.3335 +  }
  1.3336 +
  1.3337 +  // convert
  1.3338 +  synthesizeComposition({ type: "compositionupdate",
  1.3339 +                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
  1.3340 +  synthesizeText(
  1.3341 +    { "composition":
  1.3342 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
  1.3343 +        "clauses":
  1.3344 +        [
  1.3345 +          { "length": 4,
  1.3346 +            "attr": COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
  1.3347 +          { "length": 2,
  1.3348 +            "attr": COMPOSITION_ATTR_CONVERTEDTEXT }
  1.3349 +        ]
  1.3350 +      },
  1.3351 +      "caret": { "start": 4, "length": 0 }
  1.3352 +    });
  1.3353 +
  1.3354 +  if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8", kDesc, "#1-10") ||
  1.3355 +      !checkSelection(4, "", kDesc, "#1-10")) {
  1.3356 +    return;
  1.3357 +  }
  1.3358 +
  1.3359 +  // commit the composition string
  1.3360 +  synthesizeText(
  1.3361 +    { "composition":
  1.3362 +      { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
  1.3363 +        "clauses":
  1.3364 +        [
  1.3365 +          { "length": 0, "attr": 0 }
  1.3366 +        ]
  1.3367 +      },
  1.3368 +      "caret": { "start": 6, "length": 0 }
  1.3369 +    });
  1.3370 +
  1.3371 +  if (!checkContent("\u30E9", kDesc, "#1-11") ||
  1.3372 +      !checkSelection(1, "", kDesc, "#1-11")) {
  1.3373 +    return;
  1.3374 +  }
  1.3375 +
  1.3376 +  synthesizeComposition({ type: "compositionend",
  1.3377 +                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
  1.3378 +
  1.3379 +  // restart composition
  1.3380 +  synthesizeComposition({ type: "compositionstart" });
  1.3381 +
  1.3382 +  // input characters
  1.3383 +  synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
  1.3384 +  synthesizeText(
  1.3385 +    { "composition":
  1.3386 +      { "string": "\u3057",
  1.3387 +        "clauses":
  1.3388 +        [
  1.3389 +          { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
  1.3390 +        ]
  1.3391 +      },
  1.3392 +      "caret": { "start": 1, "length": 0 }
  1.3393 +    });
  1.3394 +
  1.3395 +  if (!checkContent("\u30E9\u3057", kDesc, "#2-1") ||
  1.3396 +      !checkSelection(1 + 1, "", kDesc, "#2-1")) {
  1.3397 +    return;
  1.3398 +  }
  1.3399 +
  1.3400 +  // commit the composition string
  1.3401 +  synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
  1.3402 +  synthesizeText(
  1.3403 +    { "composition":
  1.3404 +      { "string": "\u3058",
  1.3405 +        "clauses":
  1.3406 +        [
  1.3407 +          { "length": 0, "attr": 0 }
  1.3408 +        ]
  1.3409 +      },
  1.3410 +      "caret": { "start": 1, "length": 0 }
  1.3411 +    });
  1.3412 +
  1.3413 +  if (!checkContent("\u30E9", kDesc, "#2-2") ||
  1.3414 +      !checkSelection(1 + 0, "", kDesc, "#2-2")) {
  1.3415 +    return;
  1.3416 +  }
  1.3417 +
  1.3418 +  synthesizeComposition({ type: "compositionend", data: "\u3058" });
  1.3419 +
  1.3420 +  // Undo
  1.3421 +  synthesizeKey("Z", {accelKey: true});
  1.3422 +
  1.3423 +  // XXX this is unexpected behavior, see bug 258291
  1.3424 +  if (!checkContent("\u30E9", kDesc, "#3-1") ||
  1.3425 +      !checkSelection(1 + 0, "", kDesc, "#3-1")) {
  1.3426 +    return;
  1.3427 +  }
  1.3428 +
  1.3429 +  // Undo
  1.3430 +  synthesizeKey("Z", {accelKey: true});
  1.3431 +  if (!checkContent("", kDesc, "#3-2") ||
  1.3432 +      !checkSelection(0, "", kDesc, "#3-2")) {
  1.3433 +    return;
  1.3434 +  }
  1.3435 +
  1.3436 +  // Redo
  1.3437 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
  1.3438 +  if (!checkContent("\u30E9", kDesc, "#3-3") ||
  1.3439 +      !checkSelection(1, "", kDesc, "#3-3")) {
  1.3440 +    return;
  1.3441 +  }
  1.3442 +
  1.3443 +  // Redo
  1.3444 +  synthesizeKey("Z", {accelKey: true, shiftKey: true});
  1.3445 +  if (!checkContent("\u30E9", kDesc, "#3-4") ||
  1.3446 +      !checkSelection(1 + 0, "", kDesc, "#3-4")) {
  1.3447 +    return;
  1.3448 +  }
  1.3449 +}
  1.3450 +
  1.3451 +function runTest()
  1.3452 +{
  1.3453 +  textareaInFrame = iframe.contentDocument.getElementById("textarea");
  1.3454 +
  1.3455 +  runUndoRedoTest();
  1.3456 +  runCompositionTest();
  1.3457 +  runCompositionEventTest();
  1.3458 +  runCharAtPointTest(textarea, "textarea in the document");
  1.3459 +  runCharAtPointAtOutsideTest();
  1.3460 +  runBug722639Test();
  1.3461 +  runForceCommitTest();
  1.3462 +  runBug811755Test();
  1.3463 +  runIsComposingTest();
  1.3464 +  runRemoveContentTest(function () {
  1.3465 +    runFrameTest();
  1.3466 +    runPanelTest();
  1.3467 +    runMaxLengthTest();
  1.3468 +  });
  1.3469 +}
  1.3470 +
  1.3471 +]]>
  1.3472 +</script>
  1.3473 +
  1.3474 +</window>

mercurial