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 78627 df8272331d537e4c3577eae41e5c5bc3c506f42f
parent 78626 54fbf5eda91483e9770ed039b7378a82335d9a4a
child 78628 cc42e81d78b22bd7834a06347b32b323a4be52d8
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, roc
bugs543789
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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;