Bug 543789 part.7 Dispatch compositionupdate event and set data value of compositionend event in all IME handling tests r=smaug, sr=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 22 Sep 2011 18:17:41 +0900
changeset 77316 df8272331d537e4c3577eae41e5c5bc3c506f42f
parent 77315 54fbf5eda91483e9770ed039b7378a82335d9a4a
child 77317 cc42e81d78b22bd7834a06347b32b323a4be52d8
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewerssmaug, roc
bugs543789
milestone9.0a1
Bug 543789 part.7 Dispatch compositionupdate event and set data value of compositionend event in all IME handling tests r=smaug, sr=roc
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
editor/libeditor/html/tests/test_contenteditable_text_input_handling.html
layout/base/tests/bug613807-1.html
mobile/chrome/tests/browser_awesomescreen.js
testing/mochitest/tests/SimpleTest/EventUtils.js
testing/mochitest/tests/test_sanityEventUtils.html
widget/tests/test_imestate.html
widget/tests/test_input_events_on_deactive_window.xul
widget/tests/window_composition_text_querycontent.xul
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1137,39 +1137,46 @@ InitEvent(nsGUIEvent &aEvent, nsIntPoint
 {
   if (aPt) {
     aEvent.refPoint = *aPt;
   }
   aEvent.time = PR_IntervalNow();
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType)
+nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType,
+                                       const nsAString& aData,
+                                       const nsAString& aLocale)
 {
   if (!IsUniversalXPConnectCapable()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // get the widget to send the event to
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return NS_ERROR_FAILURE;
   }
 
   PRUint32 msg;
   if (aType.EqualsLiteral("compositionstart")) {
     msg = NS_COMPOSITION_START;
   } else if (aType.EqualsLiteral("compositionend")) {
     msg = NS_COMPOSITION_END;
+  } else if (aType.EqualsLiteral("compositionupdate")) {
+    msg = NS_COMPOSITION_UPDATE;
   } else {
     return NS_ERROR_FAILURE;
   }
 
   nsCompositionEvent compositionEvent(PR_TRUE, msg, widget);
   InitEvent(compositionEvent);
+  if (msg != NS_COMPOSITION_START) {
+    compositionEvent.data = aData;
+  }
 
   nsEventStatus status;
   nsresult rv = widget->DispatchEvent(&compositionEvent, status);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -61,17 +61,17 @@ interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 
-[scriptable, uuid(d95fac68-4f0d-430f-9580-6dd8041f177e)]
+[scriptable, uuid(748746a7-a6f4-41d6-bc82-1788981b2623)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -574,19 +574,26 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Synthesize a composition event to the window.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
    * Will throw a DOM security error if called without UniversalXPConnect
    * privileges.
    *
-   * @param aType The event type: "compositionstart" or "compositionend".
+   * @param aType     The event type: "compositionstart", "compositionend" or
+   *                  "compositionupdate".
+   * @param aData     The data property value.  Note that this isn't applied
+   *                  for compositionstart event because its value is the
+   *                  selected text which is automatically computed.
+   * @param aLocale   The locale property value.
    */
-  void sendCompositionEvent(in AString aType);
+  void sendCompositionEvent(in AString aType,
+                            in AString aData,
+                            in AString aLocale);
 
   /**
    * Synthesize a text event to the window.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
    * Will throw a DOM security error if called without UniversalXPConnect
    * privileges.
    *
--- a/editor/libeditor/html/tests/test_contenteditable_text_input_handling.html
+++ b/editor/libeditor/html/tests/test_contenteditable_text_input_handling.html
@@ -216,18 +216,19 @@ function runTests()
 
     if (!aFocus._isEditable) {
       return;
     }
 
     // IME
     const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
     // start composition
-    synthesizeComposition(true);
+    synthesizeComposition({ type: "compositionstart" });
     // input first character
+    synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
     synthesizeText(
       { "composition":
         { "string": "\u3089",
           "clauses":
           [
             { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
           ]
         },
@@ -291,17 +292,17 @@ function runTests()
       return;
     }
     is(querySelectedText.offset, 1,
        "query selected text event returns wrong offset after commit" + when);
     is(querySelectedText.text, "",
        "query selected text event returns wrong selected text after commit" +
          when);
     // end composition
-    synthesizeComposition(false);
+    synthesizeComposition({ type: "compositionend", data: "\u3089" });
 
     checkValue(staticContent, "\u3089");
     checkValue(inputInStatic, "\u3089");
     checkValue(textareaInStatic, "\u3089");
     checkValue(editor, "\u3089");
     checkValue(inputInEditor, "\u3089");
     checkValue(textareaInEditor, "\u3089");
 
--- a/layout/base/tests/bug613807-1.html
+++ b/layout/base/tests/bug613807-1.html
@@ -43,39 +43,42 @@
   addLoadEvent(function() {
     var area = document.getElementById('t');
     area.focus();
 
     netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
 
     // start composition
-    synthesizeComposition(true);
+    synthesizeComposition({ type: "compositionstart" });
 
     // input raw characters
+    synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
     synthesizeText(
       { composition:
         { string: "\u306D",
           clauses: [
             { length: 1, attr: nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
           ]
         },
         caret: { start: 1, length: 0 }
       });
+    synthesizeComposition({ type: "compositionupdate", data: "\u306D\u3053" });
     synthesizeText(
       { composition:
         { string: "\u306D\u3053",
           clauses: [
             { length: 2, attr: nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
           ]
         },
         caret: { start: 2, length: 0 }
       });
 
     // convert
+    synthesizeComposition({ type: "compositionupdate", data: "\u732B" });
     synthesizeText(
       { composition:
         { string: "\u732B",
           clauses: [
             { length: 1, attr: nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
           ]
         },
         caret: { start: 1, length: 0 }
@@ -88,17 +91,17 @@
           clauses: [
             { length: 0, attr: 0 }
           ]
         },
         caret: { start: 1, length: 0 }
       });
 
     // end composition
-    synthesizeComposition(false);
+    synthesizeComposition({ type: "compositionend", data: "\u732B" });
 
     document.body.clientWidth;
 
     // undo
     synthesizeKey("Z", {accelKey: true});
   });
 </script>
 </body>
--- a/mobile/chrome/tests/browser_awesomescreen.js
+++ b/mobile/chrome/tests/browser_awesomescreen.js
@@ -394,27 +394,27 @@ gTests.push({
 
   onPopupReady: function() {
     gCurrentTest._checkState();
 
     window.addEventListener("compositionstart", function() {
       window.removeEventListener("compositionstart", arguments.callee, false);
       setTimeout(gCurrentTest.onCompositionStart, 0)
     }, false);
-    Browser.windowUtils.sendCompositionEvent("compositionstart");
+    Browser.windowUtils.sendCompositionEvent("compositionstart", "", "");
   },
 
   onCompositionStart: function() {
     gCurrentTest._checkState();
 
     window.addEventListener("compositionend", function() {
       window.removeEventListener("compositionend", arguments.callee, false);
       setTimeout(gCurrentTest.onCompositionEnd, 0)
     }, false);
-    Browser.windowUtils.sendCompositionEvent("compositionend");
+    Browser.windowUtils.sendCompositionEvent("compositionend", "", "");
   },
 
   onCompositionEnd: function() {
     /* TODO: This is currently failing (bug 642771)
     gCurrentTest._checkState();
 
     let isHiddenHeader = function() {
       return gCurrentTest.popupHeader.hidden;
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -547,31 +547,38 @@ function _getDOMWindowUtils(aWindow)
   }
   return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
                  getInterface(Components.interfaces.nsIDOMWindowUtils);
 }
 
 /**
  * Synthesize a composition event.
  *
- * @param aIsCompositionStart  If true, this synthesize compositionstart event.
- *                             Otherwise, compositionend event.
+ * @param aEvent               The composition event information.  This must
+ *                             have |type| member.  The value must be
+ *                             "compositionstart", "compositionend" or
+ *                             "compositionupdate".
+ *                             And also this may have |data| and |locale| which
+ *                             would be used for the value of each property of
+ *                             the composition event.  Note that the data would
+ *                             be ignored if the event type were
+ *                             "compositionstart".
  * @param aWindow              Optional (If null, current |window| will be used)
  */
-function synthesizeComposition(aIsCompositionStart, aWindow)
+function synthesizeComposition(aEvent, aWindow)
 {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   var utils = _getDOMWindowUtils(aWindow);
   if (!utils) {
     return;
   }
 
-  utils.sendCompositionEvent(aIsCompositionStart ?
-                               "compositionstart" : "compositionend");
+  utils.sendCompositionEvent(aEvent.type, aEvent.data ? aEvent.data : "",
+                             aEvent.locale ? aEvent.locale : "");
 }
 
 /**
  * Synthesize a text event.
  *
  * @param aEvent   The text event's information, this has |composition|
  *                 and |caret| members.  |composition| has |string| and
  *                 |clauses| members.  |clauses| must be array object.  Each
--- a/testing/mochitest/tests/test_sanityEventUtils.html
+++ b/testing/mochitest/tests/test_sanityEventUtils.html
@@ -110,22 +110,27 @@ function starttest() {
       synthesizeKeyExpectEvent("a", {}, $("testKeyEvent"), "keypress");
       is($("testKeyEvent").value, "a", "synthesizeKey should work");
       is(check, true, "synthesizeKey should dispatch keyPress");
       $("testKeyEvent").value = "";
     
       /* test synthesizeComposition */
       check = false;
       window.addEventListener("compositionstart", function() { check = true; }, false);
-      synthesizeComposition(true);
-      is(check, true, 'synthesizeComposition(true) should dispatch compositionstart');
+      synthesizeComposition({ type: "compositionstart" });
+      is(check, true, 'synthesizeComposition() should dispatch compositionstart');
+    
+      check = false;
+      window.addEventListener("compositionupdate", function() { check = true; }, false);
+      synthesizeComposition({ type: "compositionupdate" });
+      is(check, true, 'synthesizeComposition() should dispatch compositionupdate');
     
       check = false;
       window.addEventListener("compositionend", function() { check = true; }, false);
-      synthesizeComposition();
+      synthesizeComposition({ type: "compositionend" });
       is(check, true, 'synthesizeComposition() should dispatch compositionend');
       check = false;
     
       $("textBoxB").focus();
       const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
       synthesizeText(
         { "composition":
           { "string": "a",
--- a/widget/tests/test_imestate.html
+++ b/widget/tests/test_imestate.html
@@ -1106,19 +1106,21 @@ function runEditorFlagChangeTests()
     window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
       getInterface(Components.interfaces.nsIWebNavigation).
       QueryInterface(Components.interfaces.nsIEditorDocShell).editor;
   var editorIMESupport =
     editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
   var flags = editor.flags;
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input characters
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3078\u3093\u3057\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3078\u3093\u3057\u3093",
         "clauses":
         [
           { "length": 4, "attr": gUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1139,28 +1141,29 @@ function runEditorFlagChangeTests()
 
   editor.flags = flags;
   ok(editorIMESupport.composing,
      description + "#3 IME composition was committed unexpectedly");
   is(gUtils.IMEStatus, gUtils.IME_STATUS_ENABLED,
      description + "#3 IME isn't enabled on HTML editor");
 
   // cancel the composition
+  synthesizeComposition({ type: "compositionupdate", data: "" });
   synthesizeText(
     { "composition":
       { "string": "",
         "clauses":
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 0, "length": 0 }
     });
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "" });
 
   container.removeAttribute("contenteditable");
 }
 
 function runEditableSubframeTests()
 {
   window.open("window_imestate_iframes.html", "_blank",
               "width=600,height=600");
--- a/widget/tests/test_input_events_on_deactive_window.xul
+++ b/widget/tests/test_input_events_on_deactive_window.xul
@@ -61,52 +61,56 @@ function startTests()
   isnot(fm.focusedWindow, window, "we're not deactive");
   if (fm.focusedWindow == window) {
     otherWindow.close();
     SimpleTest.finish();
     return;
   }
 
   var keydownHandled, keypressHandled, keyupHandled, compositionstartHandled,
-      compositionendHandled, inputHandled;
+      compositionendHandled, compositionupdateHandled, inputHandled;
 
   function clear()
   {
     keydownHandled = false;
     keypressHandled = false;
     keyupHandled = false;
     compositionstartHandled = false;
     compositionendHandled = false;
+    compositionupdateHandled = false;
     inputHandled = false;
   }
 
   function onEvent(aEvent)
   {
     if (aEvent.type == "keydown") {
       keydownHandled = true;
     } else if (aEvent.type == "keypress") {
       keypressHandled = true;
     } else if (aEvent.type == "keyup") {
       keyupHandled = true;
     } else if (aEvent.type == "compositionstart") {
       compositionstartHandled = true;
     } else if (aEvent.type == "compositionend") {
       compositionendHandled = true;
+    } else if (aEvent.type == "compositionupdate") {
+      compositionupdateHandled = true;
     } else if (aEvent.type == "input") {
       inputHandled = true;
     } else {
       ok(false, "handled unknown event: " + aEvent.type);
     }
   }
 
   textarea.addEventListener("keydown", onEvent, false);
   textarea.addEventListener("keypress", onEvent, false);
   textarea.addEventListener("keyup", onEvent, false);
   textarea.addEventListener("compositionstart", onEvent, false);
   textarea.addEventListener("compositionend", onEvent, false);
+  textarea.addEventListener("compositionupdate", onEvent, false);
   textarea.addEventListener("input", onEvent, false);
 
   startTestsInternal();
 
   function startTestsInternal()
   {
     // key events
     function checkKeyEvents(aKeydown, aKeypress, aKeyup, aInput, aDescription)
@@ -116,22 +120,24 @@ function startTests()
       is(keypressHandled, aKeypress,
          "keypress event is (not) handled: " + aDescription);
       is(keyupHandled, aKeyup,
          "keyup event is (not) handled: " + aDescription);
       is(inputHandled, aInput,
          "input event is (not) handled: " + aDescription);
     }
 
-    function checkCompositionEvents(aStart, aEnd, aInput, aDescription)
+    function checkCompositionEvents(aStart, aEnd, aUpdate, aInput, aDescription)
     {
       is(compositionstartHandled, aStart,
          "compositionstart event is (not) handled: " + aDescription);
       is(compositionendHandled, aEnd,
          "compositionend event is (not) handled: " + aDescription);
+      is(compositionupdateHandled, aUpdate,
+         "compositionupdate event is (not) handled: " + aDescription);
       is(inputHandled, aInput,
          "input event is (not) handled: " + aDescription);
     }
 
     clear();
     synthesizeKey("a", { type: "keydown" });
     checkKeyEvents(true, false, false, false, "a keydown");
     clear();
@@ -145,31 +151,32 @@ function startTests()
     synthesizeKey("VK_BACK_SPACE", {});
     checkKeyEvents(true, true, true, true, "VK_BACK_SPACE key events");
     is(textarea.value, "", "textarea value isn't empty");
 
     // IME events
     const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
     clear();
     // start composition
-    synthesizeComposition(true);
-    checkCompositionEvents(true, false, false, "compositionstart");
+    synthesizeComposition({ type: "compositionstart" });
+    checkCompositionEvents(true, false, false, false, "compositionstart");
     clear();
     // input first character
+    synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
     synthesizeText(
       { "composition":
         { "string": "\u3089",
           "clauses":
           [
             { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
           ]
         },
         "caret": { "start": 1, "length": 0 }
       });
-    checkCompositionEvents(false, false, false, "composing");
+    checkCompositionEvents(false, false, true, false, "composing");
     var queryText = synthesizeQueryTextContent(0, 100);
     ok(queryText, "query text event result is null");
     if (!queryText) {
       return;
     }
     ok(queryText.succeeded, "query text event failed");
     if (!queryText.succeeded) {
       return;
@@ -195,17 +202,17 @@ function startTests()
         { "string": "\u3089",
           "clauses":
           [
             { "length": 0, "attr": 0 }
           ]
         },
         "caret": { "start": 1, "length": 0 }
       });
-    checkCompositionEvents(false, false, false, "commit composition");
+    checkCompositionEvents(false, false, false, false, "commit composition");
     queryText = synthesizeQueryTextContent(0, 100);
     ok(queryText, "query text event result is null after commit");
     if (!queryText) {
       return;
     }
     ok(queryText.succeeded, "query text event failed after commit");
     if (!queryText.succeeded) {
       return;
@@ -223,24 +230,25 @@ function startTests()
       return;
     }
     is(querySelectedText.offset, 1,
        "query selected text event returns wrong offset after commit");
     is(querySelectedText.text, "",
        "query selected text event returns wrong selected text after commit");
     clear();
     // end composition
-    synthesizeComposition(false);
-    checkCompositionEvents(false, true, true, "compositionend");
+    synthesizeComposition({ type: "compositionend", data: "\u3089" });
+    checkCompositionEvents(false, true, false, true, "compositionend");
   }
 
   textarea.removeEventListener("keydown", onEvent, false);
   textarea.removeEventListener("keypress", onEvent, false);
   textarea.removeEventListener("keyup", onEvent, false);
   textarea.removeEventListener("compositionstart", onEvent, false);
+  textarea.removeEventListener("compositionupdate", onEvent, false);
   textarea.removeEventListener("compositionend", onEvent, false);
   textarea.removeEventListener("input", onEvent, false);
 
   otherWindow.close();
 
   SimpleTest.finish();
 }
 
--- a/widget/tests/window_composition_text_querycontent.xul
+++ b/widget/tests/window_composition_text_querycontent.xul
@@ -149,42 +149,45 @@ function checkRectContainsRect(aRect, aC
 }
 
 function runUndoRedoTest()
 {
   textarea.value = "";
   textarea.focus();
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input raw characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u306D" });
   synthesizeText(
     { "composition":
       { "string": "\u306D",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u306D\u3053" });
   synthesizeText(
     { "composition":
       { "string": "\u306D\u3053",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 2, "length": 0 }
     });
 
   // convert
+  synthesizeComposition({ type: "compositionupdate", data: "\u732B" });
   synthesizeText(
     { "composition":
       { "string": "\u732B",
         "clauses":
         [
           { "length": 1,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
         ]
@@ -200,86 +203,93 @@ function runUndoRedoTest()
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
   // end composition
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u732B" });
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input raw characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u307E" });
   synthesizeText(
     { "composition":
       { "string": "\u307E",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
   // cancel the composition
+  synthesizeComposition({ type: "compositionupdate", data: "" });
   synthesizeText(
     { "composition":
       { "string": "",
         "clauses":
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 0, "length": 0 }
     });
 
   // end composition
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "" });
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input raw characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u3080" });
   synthesizeText(
     { "composition":
       { "string": "\u3080",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u3080\u3059" });
   synthesizeText(
     { "composition":
       { "string": "\u3080\u3059",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 2, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3080\u3059\u3081" });
   synthesizeText(
     { "composition":
       { "string": "\u3080\u3059\u3081",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 3, "length": 0 }
     });
 
   // convert
+  synthesizeComposition({ type: "compositionupdate", data: "\u5A18" });
   synthesizeText(
     { "composition":
       { "string": "\u5A18",
         "clauses":
         [
           { "length": 1,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
         ]
@@ -295,17 +305,17 @@ function runUndoRedoTest()
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
   // end composition
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u5A18" });
 
   synthesizeKey(" ", {});
   synthesizeKey("m", {});
   synthesizeKey("e", {});
   synthesizeKey("a", {});
   synthesizeKey("n", {});
   synthesizeKey("t", {});
   synthesizeKey("VK_BACK_SPACE", {});
@@ -331,64 +341,71 @@ function runUndoRedoTest()
   synthesizeKey(" ", {});
   synthesizeKey("i", {});
   synthesizeKey("s", {});
   synthesizeKey(" ", {});
   synthesizeKey("a", {});
   synthesizeKey(" ", {});
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input raw characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u3088" });
   synthesizeText(
     { "composition":
       { "string": "\u3088",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u3088\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u3088\u3046",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 2, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3088\u3046\u304b" });
   synthesizeText(
     { "composition":
       { "string": "\u3088\u3046\u304b",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 3, "length": 0 }
     });
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3088\u3046\u304b\u3044" });
   synthesizeText(
     { "composition":
       { "string": "\u3088\u3046\u304b\u3044",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 4, "length": 0 }
     });
 
   // convert
+  synthesizeComposition({ type: "compositionupdate", data: "\u5996\u602a" });
   synthesizeText(
     { "composition":
       { "string": "\u5996\u602a",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
         ]
       },
@@ -403,17 +420,17 @@ function runUndoRedoTest()
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 2, "length": 0 }
     });
 
   // end composition
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u5996\u602a" });
 
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
   synthesizeKey("VK_BACK_SPACE", {});
@@ -586,19 +603,20 @@ function runCompositionTest()
   var caretRect = synthesizeQueryCaretRect(0);
   if (!checkQueryContentResult(caretRect,
         "runCompositionTest: synthesizeQueryCaretRect #0")) {
     return false;
   }
   caretRects[0] = caretRect;
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input first character
+  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
   synthesizeText(
     { "composition":
       { "string": "\u3089",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -613,16 +631,17 @@ function runCompositionTest()
   caretRect = synthesizeQueryCaretRect(1);
   if (!checkQueryContentResult(caretRect,
         "runCompositionTest: synthesizeQueryCaretRect #1-1")) {
     return false;
   }
   caretRects[1] = caretRect;
 
   // input second character
+  synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -646,16 +665,18 @@ function runCompositionTest()
   is(caretRects[2].top, caretRects[1].top,
      "runCompositionTest: caret is moved to another line (#1-2)");
   is(caretRects[2].width, caretRects[1].width,
      "runCompositionTest: caret width is wrong (#1-2)");
   is(caretRects[2].height, caretRects[1].height,
      "runCompositionTest: caret width is wrong (#1-2)");
 
   // input third character
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -746,16 +767,18 @@ function runCompositionTest()
   is(caretRect.top, caretRects[1].top,
      "runCompositionTest: caret rects are different (#1-3-2, top)");
   // by bug 335359, the caret width depends on the right side's character.
   is(caretRect.width, caretRects[1].width + 1,
      "runCompositionTest: caret rects are different (#1-3-2, width)");
   is(caretRect.height, caretRects[1].height,
      "runCompositionTest: caret rects are different (#1-3-2, height)");
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -764,16 +787,18 @@ function runCompositionTest()
 
   if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-4") ||
       !checkSelection(4, "", "runCompositionTest", "#1-4")) {
     return;
   }
 
 
   // backspace
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -781,80 +806,90 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-5") ||
       !checkSelection(3, "", "runCompositionTest", "#1-5")) {
     return;
   }
 
   // re-input
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 4, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-6") ||
       !checkSelection(4, "", "runCompositionTest", "#1-6")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055",
         "clauses":
         [
           { "length": 5, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 5, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", "runCompositionTest", "#1-7") ||
       !checkSelection(5, "", "runCompositionTest", "#1-7")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
         "clauses":
         [
           { "length": 6, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 6, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", "runCompositionTest", "#1-8") ||
       !checkSelection(6, "", "runCompositionTest", "#1-8")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
         "clauses":
         [
           { "length": 7, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 7, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053", "runCompositionTest", "#1-8") ||
       !checkSelection(7, "", "runCompositionTest", "#1-8")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
         "clauses":
         [
           { "length": 8, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -863,16 +898,18 @@ function runCompositionTest()
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
                     "runCompositionTest", "#1-9") ||
       !checkSelection(8, "", "runCompositionTest", "#1-9")) {
     return;
   }
 
   // convert
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
   synthesizeText(
     { "composition":
       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
         "clauses":
         [
           { "length": 4,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
           { "length": 2,
@@ -905,16 +942,18 @@ function runCompositionTest()
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
                     "runCompositionTest", "#1-11") ||
       !checkSelection(6, "", "runCompositionTest", "#1-11")) {
     return;
   }
 
   // reset clauses
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
         "clauses":
         [
           { "length": 5,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
           { "length": 3,
@@ -953,35 +992,37 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
                     "runCompositionTest", "#1-13") ||
       !checkSelection(8, "", "runCompositionTest", "#1-13")) {
     return;
   }
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend",
+                          data: "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046" });
 
   var textRect3 = synthesizeQueryTextRect(0, 1);
   var textRect4 = synthesizeQueryTextRect(1, 1);
 
   if (!checkQueryContentResult(textRect3,
         "runCompositionTest: synthesizeQueryTextRect #1-13-1") ||
       !checkQueryContentResult(textRect4,
         "runCompositionTest: synthesizeQueryTextRect #1-13-2")) {
     return false;
   }
 
   checkRect(textRect3, textRect1, "runCompositionTest: textRect #1-13-1");
   checkRect(textRect4, textRect2, "runCompositionTest: textRect #1-13-2");
 
   // restart composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
   synthesizeText(
     { "composition":
       { "string": "\u3057",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -989,16 +1030,17 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3057",
                     "runCompositionTest", "#2-1") ||
       !checkSelection(8 + 1, "", "runCompositionTest", "#2-1")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
   synthesizeText(
     { "composition":
       { "string": "\u3058",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1006,16 +1048,17 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058",
                     "runCompositionTest", "#2-2") ||
       !checkSelection(8 + 1, "", "runCompositionTest", "#2-2")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u3058\u3087" });
   synthesizeText(
     { "composition":
       { "string": "\u3058\u3087",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1023,16 +1066,18 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087",
                     "runCompositionTest", "#2-3") ||
       !checkSelection(8 + 2, "", "runCompositionTest", "#2-3")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3058\u3087\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u3058\u3087\u3046",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1058,29 +1103,30 @@ function runCompositionTest()
     });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
                     "runCompositionTest", "#2-4") ||
       !checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
     return;
   }
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u3058\u3087\u3046" });
 
   // set selection
   var selectionSetTest = synthesizeSelectionSet(4, 7, false);
   ok(selectionSetTest, "runCompositionTest: selectionSetTest failed");
 
   if (!checkSelection(4, "\u3055\u884C\u3053\u3046\u3058\u3087\u3046", "runCompositionTest", "#3-1")) {
     return;
   }
 
   // start composition with selection
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
+  synthesizeComposition({ type: "compositionupdate", data: "\u304A" });
   synthesizeText(
     { "composition":
       { "string": "\u304A",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1089,16 +1135,17 @@ function runCompositionTest()
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u304A",
                     "runCompositionTest", "#3-2") ||
       !checkSelection(4 + 1, "", "runCompositionTest", "#3-2")) {
     return;
   }
 
   // remove the composition string
+  synthesizeComposition({ type: "compositionupdate", data: "" });
   synthesizeText(
     { "composition":
       { "string": "",
         "clauses":
         [
           { "length": 0, "attr": 0 }
         ]
       },
@@ -1107,16 +1154,17 @@ function runCompositionTest()
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
                     "runCompositionTest", "#3-3") ||
       !checkSelection(4, "", "runCompositionTest", "#3-3")) {
     return;
   }
 
   // re-input the composition string
+  synthesizeComposition({ type: "compositionupdate", data: "\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u3046",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1125,28 +1173,29 @@ function runCompositionTest()
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3046",
                     "runCompositionTest", "#3-4") ||
       !checkSelection(4 + 1, "", "runCompositionTest", "#3-4")) {
     return;
   }
 
   // cancel the composition
+  synthesizeComposition({ type: "compositionupdate", data: "" });
   synthesizeText(
     { "composition":
       { "string": "",
         "clauses":
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 0, "length": 0 }
     });
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "" });
 
   if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
                     "runCompositionTest", "#3-5") ||
       !checkSelection(4, "", "runCompositionTest", "#3-5")) {
     return;
   }
 }
 
@@ -1272,19 +1321,21 @@ function runTestOnAnotherContext(aPanelO
 
   var r = aPanelOrFrame.getBoundingClientRect();
   var parentRect = { "left": r.left, "top": r.top, "width": r.right - r.left,
                      "height": r.bottom - r.top };
   checkRectContainsRect(editorRect, parentRect, aTestName +
                         ": the editor rect coordinates are wrong");
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input characters
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3078\u3093\u3057\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3078\u3093\u3057\u3093",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1292,16 +1343,17 @@ function runTestOnAnotherContext(aPanelO
     });
 
   if (!checkContent("\u3078\u3093\u3057\u3093", aTestName, "#1-1") ||
       !checkSelection(4, "", aTestName, "#1-1")) {
     return;
   }
 
   // convert them #1
+  synthesizeComposition({ type: "compositionupdate", data: "\u8FD4\u4FE1" });
   synthesizeText(
     { "composition":
       { "string": "\u8FD4\u4FE1",
         "clauses":
         [
           { "length": 2,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
         ]
@@ -1310,16 +1362,17 @@ function runTestOnAnotherContext(aPanelO
     });
 
   if (!checkContent("\u8FD4\u4FE1", aTestName, "#1-2") ||
       !checkSelection(2, "", aTestName, "#1-2")) {
     return;
   }
 
   // convert them #2
+  synthesizeComposition({ type: "compositionupdate", data: "\u5909\u8EAB" });
   synthesizeText(
     { "composition":
       { "string": "\u5909\u8EAB",
         "clauses":
         [
           { "length": 2,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
         ]
@@ -1344,17 +1397,17 @@ function runTestOnAnotherContext(aPanelO
       "caret": { "start": 2, "length": 0 }
     });
 
   if (!checkContent("\u5909\u8EAB", aTestName, "#1-4") ||
       !checkSelection(2, "", aTestName, "#1-4")) {
     return;
   }
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u5909\u8EAB" });
 
   is(aFocusedEditor.value, "\u5909\u8EAB",
      aTestName + ": composition isn't in the focused editor");
   if (aFocusedEditor.value != "\u5909\u8EAB") {
     return;
   }
 
   var textRect = synthesizeQueryTextRect(0, 1);
@@ -1426,19 +1479,20 @@ function runMaxLengthTest()
 {
   input.maxLength = 1;
   input.value = "";
   input.focus();
 
   var kDesc ="runMaxLengthTest";
 
   // start composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input first character
+  synthesizeComposition({ type: "compositionupdate", data: "\u3089" });
   synthesizeText(
     { "composition":
       { "string": "\u3089",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1446,16 +1500,17 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u3089", kDesc, "#1-1") ||
       !checkSelection(1, "", kDesc, "#1-1")) {
     return;
   }
 
   // input second character
+  synthesizeComposition({ type: "compositionupdate", data: "\u3089\u30FC" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC",
         "clauses":
         [
           { "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1463,16 +1518,18 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u3089\u30FC", kDesc, "#1-2") ||
       !checkSelection(2, "", kDesc, "#1-2")) {
     return;
   }
 
   // input third character
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1480,16 +1537,18 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-3") ||
       !checkSelection(3, "", kDesc, "#1-3")) {
     return;
   }
 
   // input fourth character
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1498,16 +1557,18 @@ function runMaxLengthTest()
 
   if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-4") ||
       !checkSelection(4, "", kDesc, "#1-4")) {
     return;
   }
 
 
   // backspace
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081",
         "clauses":
         [
           { "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1515,64 +1576,72 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u3089\u30FC\u3081", kDesc, "#1-5") ||
       !checkSelection(3, "", kDesc, "#1-5")) {
     return;
   }
 
   // re-input
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093",
         "clauses":
         [
           { "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 4, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093", kDesc, "#1-6") ||
       !checkSelection(4, "", kDesc, "#1-6")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055",
         "clauses":
         [
           { "length": 5, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 5, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", kDesc, "#1-7") ||
       !checkSelection(5, "", kDesc, "#1-7")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
         "clauses":
         [
           { "length": 6, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
       "caret": { "start": 6, "length": 0 }
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", kDesc, "#1-8") ||
       !checkSelection(6, "", kDesc, "#1-8")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
         "clauses":
         [
           { "length": 7, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1580,16 +1649,18 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
                     kDesc, "#1-8") ||
       !checkSelection(7, "", kDesc, "#1-8")) {
     return;
   }
 
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046" });
   synthesizeText(
     { "composition":
       { "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
         "clauses":
         [
           { "length": 8, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1598,16 +1669,18 @@ function runMaxLengthTest()
 
   if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
                     kDesc, "#1-9") ||
       !checkSelection(8, "", kDesc, "#1-9")) {
     return;
   }
 
   // convert
+  synthesizeComposition({ type: "compositionupdate",
+                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
   synthesizeText(
     { "composition":
       { "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
         "clauses":
         [
           { "length": 4,
             "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
           { "length": 2,
@@ -1634,22 +1707,24 @@ function runMaxLengthTest()
       "caret": { "start": 8, "length": 0 }
     });
 
   if (!checkContent("\u30E9", kDesc, "#1-11") ||
       !checkSelection(1, "", kDesc, "#1-11")) {
     return;
   }
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend",
+                          data: "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8" });
 
   // restart composition
-  synthesizeComposition(true);
+  synthesizeComposition({ type: "compositionstart" });
 
   // input characters
+  synthesizeComposition({ type: "compositionupdate", data: "\u3057" });
   synthesizeText(
     { "composition":
       { "string": "\u3057",
         "clauses":
         [
           { "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
         ]
       },
@@ -1657,33 +1732,34 @@ function runMaxLengthTest()
     });
 
   if (!checkContent("\u30E9\u3057", kDesc, "#2-1") ||
       !checkSelection(1 + 1, "", kDesc, "#2-1")) {
     return;
   }
 
   // commit the composition string
+  synthesizeComposition({ type: "compositionupdate", data: "\u3058" });
   synthesizeText(
     { "composition":
       { "string": "\u3058",
         "clauses":
         [
           { "length": 0, "attr": 0 }
         ]
       },
       "caret": { "start": 1, "length": 0 }
     });
 
   if (!checkContent("\u30E9", kDesc, "#2-2") ||
       !checkSelection(1 + 0, "", kDesc, "#2-2")) {
     return;
   }
 
-  synthesizeComposition(false);
+  synthesizeComposition({ type: "compositionend", data: "\u3058" });
 
   // Undo
   synthesizeKey("Z", {accelKey: true});
 
   // XXX this is unexpected behavior, see bug 258291
   if (!checkContent("\u30E9", kDesc, "#3-1") ||
       !checkSelection(1 + 0, "", kDesc, "#3-1")) {
     return;