Bug 998188 part.4 nsIDOMWindowUtils.sendQueryContentEvent() and .sendSelectionSetEvent() should take additional flags with its argument for making callers selectable native line break mode or XP line break mode r=smaug, sr=jst
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 26 Apr 2014 08:52:13 +0900
changeset 180704 776018f74fed4a2dfd144781e62160f77e5439e2
parent 180703 ac566b771d7b77652c910e45cb210386c56b303b
child 180705 8305804b3099e068fa7f9dcf66c2836f8183c736
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewerssmaug, jst
bugs998188
milestone31.0a1
Bug 998188 part.4 nsIDOMWindowUtils.sendQueryContentEvent() and .sendSelectionSetEvent() should take additional flags with its argument for making callers selectable native line break mode or XP line break mode r=smaug, sr=jst
dom/base/nsDOMWindowUtils.cpp
dom/base/test/chrome.ini
dom/base/test/test_sendQueryContentAndSelectionSetEvent.html
dom/interfaces/base/nsIDOMWindowUtils.idl
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2198,16 +2198,17 @@ nsDOMWindowUtils::CreateCompositionStrin
   NS_ADDREF(*aResult = new CompositionStringSynthesizer(window));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType,
                                         uint32_t aOffset, uint32_t aLength,
                                         int32_t aX, int32_t aY,
+                                        uint32_t aAdditionalFlags,
                                         nsIQueryContentEventResult **aResult)
 {
   *aResult = nullptr;
 
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
@@ -2236,19 +2237,23 @@ nsDOMWindowUtils::SendQueryContentEvent(
       aType != NS_QUERY_EDITOR_RECT &&
       aType != NS_QUERY_CHARACTER_AT_POINT) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsIWidget> targetWidget = widget;
   LayoutDeviceIntPoint pt(aX, aY);
 
+  bool useNativeLineBreak =
+    !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+
   if (aType == QUERY_CHARACTER_AT_POINT) {
     // Looking for the widget at the point.
     WidgetQueryContentEvent dummyEvent(true, NS_QUERY_CONTENT_STATE, widget);
+    dummyEvent.mUseNativeLineBreak = useNativeLineBreak;
     InitEvent(dummyEvent, &pt);
     nsIFrame* popupFrame =
       nsLayoutUtils::GetPopupFrameForEventCoordinates(presContext->GetRootPresContext(), &dummyEvent);
 
     nsIntRect widgetBounds;
     nsresult rv = widget->GetClientBounds(widgetBounds);
     NS_ENSURE_SUCCESS(rv, rv);
     widgetBounds.MoveTo(0, 0);
@@ -2268,23 +2273,26 @@ nsDOMWindowUtils::SendQueryContentEvent(
   pt += LayoutDeviceIntPoint::FromUntyped(
     widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset());
 
   WidgetQueryContentEvent queryEvent(true, aType, targetWidget);
   InitEvent(queryEvent, &pt);
 
   switch (aType) {
     case NS_QUERY_TEXT_CONTENT:
-      queryEvent.InitForQueryTextContent(aOffset, aLength);
+      queryEvent.InitForQueryTextContent(aOffset, aLength, useNativeLineBreak);
       break;
     case NS_QUERY_CARET_RECT:
-      queryEvent.InitForQueryCaretRect(aOffset);
+      queryEvent.InitForQueryCaretRect(aOffset, useNativeLineBreak);
       break;
     case NS_QUERY_TEXT_RECT:
-      queryEvent.InitForQueryTextRect(aOffset, aLength);
+      queryEvent.InitForQueryTextRect(aOffset, aLength, useNativeLineBreak);
+      break;
+    default:
+      queryEvent.mUseNativeLineBreak = useNativeLineBreak;
       break;
   }
 
   nsEventStatus status;
   nsresult rv = targetWidget->DispatchEvent(&queryEvent, status);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsQueryContentEventResult* result = new nsQueryContentEventResult();
@@ -2292,17 +2300,17 @@ nsDOMWindowUtils::SendQueryContentEvent(
   result->SetEventResult(widget, queryEvent);
   NS_ADDREF(*aResult = result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset,
                                         uint32_t aLength,
-                                        bool aReverse,
+                                        uint32_t aAdditionalFlags,
                                         bool *aResult)
 {
   *aResult = false;
 
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
@@ -2312,17 +2320,19 @@ nsDOMWindowUtils::SendSelectionSetEvent(
     return NS_ERROR_FAILURE;
   }
 
   WidgetSelectionEvent selectionEvent(true, NS_SELECTION_SET, widget);
   InitEvent(selectionEvent);
 
   selectionEvent.mOffset = aOffset;
   selectionEvent.mLength = aLength;
-  selectionEvent.mReversed = aReverse;
+  selectionEvent.mReversed = (aAdditionalFlags & SELECTION_SET_FLAG_REVERSE);
+  selectionEvent.mUseNativeLineBreak =
+    !(aAdditionalFlags & SELECTION_SET_FLAG_USE_XP_LINE_BREAK);
 
   nsEventStatus status;
   nsresult rv = widget->DispatchEvent(&selectionEvent, status);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aResult = selectionEvent.mSucceeded;
   return NS_OK;
 }
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -3,8 +3,9 @@ support-files =
   file_url.jsm
 
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
 [test_url.xul]
 [test_console.xul]
 [test_navigator_resolve_identity_xrays.xul]
+[test_sendQueryContentAndSelectionSetEvent.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_sendQueryContentAndSelectionSetEvent.html
@@ -0,0 +1,224 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for nsIDOMWindowUtils.sendQueryContentEvent() and .sendSelectionSetEvent()</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<div id="editor" contenteditable>abc<br>def</div>
+<pre id="test">
+<script type="application/javascript">
+
+var editor = document.getElementById("editor");
+
+SimpleTest.waitForExplicitFinish();
+
+const kIsWin = navigator.platform.indexOf("Win") == 0;
+const kIsMac = navigator.platform.indexOf("Mac") == 0;
+
+const kLineBreak = kIsWin ? "\r\n" : kIsMac ? "\r" : "\n";
+
+var gUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+function escape(aStr)
+{
+  var result = aStr.replace("\n", "\\n");
+  return result.replace("\r", "\\r");
+}
+
+function runTests()
+{
+  editor.focus();
+
+  // NOTE: For compatibility, calling without flags should work as with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK.
+
+  // QueryTextContent
+  var expectedStr = escape(("abc" + kLineBreak + "def").substr(2, 4));
+  var result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0,
+                                            gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  is(escape(result.text), expectedStr,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) got unexpected string");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT) should succeed");
+  is(escape(result.text), expectedStr,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT) should return same string as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+  expectedStr = escape(("abc\ndef").substr(2, 4));
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_CONTENT, 2, 4, 0, 0,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+  is(escape(result.text), expectedStr,
+     "sendQueryContentEvent(QUERY_TEXT_CONTENT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) got unexpected string");
+
+  // QueryCaretRect
+  window.getSelection().collapse(editor.firstChild, 0);
+
+  var caretNative = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6, 0, 0, 0,
+                                                 gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(caretNative.succeeded,
+     "sendQueryContentEvent(QUERY_CARET_RECT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  var caretXP = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6 - kLineBreak.length + 1, 0, 0, 0,
+                                             gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(caretXP.succeeded,
+     "sendQueryContentEvent(QUERY_CARET_RECT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+
+  is(caretXP.top, caretNative.top,
+     "The caret top should be same");
+  is(caretXP.left, caretNative.left,
+     "The caret left should be same");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_CARET_RECT, 6, 0, 0, 0);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_CARET_RECT) should succeed");
+  is(result.top, caretNative.top,
+     "sendQueryContentEvent(QUERY_CARET_RECT) should return same top as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.left, caretNative.left,
+     "sendQueryContentEvent(QUERY_CARET_RECT) should return same left as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+  // QueryTextRect
+  var textRectNative = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6, 1, 0, 0,
+                                                    gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(textRectNative.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_RECT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  var textRectXP = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6 - kLineBreak.length + 1, 1, 0, 0,
+                                                gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(textRectXP.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_RECT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+
+  is(textRectXP.top, textRectNative.top,
+     "The text top should be same");
+  is(textRectXP.left, textRectNative.left,
+     "The text left should be same");
+  is(textRectXP.height, textRectNative.height,
+     "The text height should be same");
+  is(textRectXP.width, textRectNative.width,
+     "The text width should be same");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_TEXT_RECT, 6, 1, 0, 0);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_TEXT_RECT) should succeed");
+  is(result.top, textRectNative.top,
+     "sendQueryContentEvent(QUERY_TEXT_RECT) should return same top as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.left, textRectNative.left,
+     "sendQueryContentEvent(QUERY_TEXT_RECT) should return same left as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.height, textRectNative.height,
+     "sendQueryContentEvent(QUERY_TEXT_RECT) should return same height as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.width, textRectNative.width,
+     "sendQueryContentEvent(QUERY_TEXT_RECT) should return same width as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+  // QueryCharacterAtOffset
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectNative.left + 1, textRectNative.top + 1,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  is(result.top, textRectNative.top,
+     "The character top is wrong");
+  is(result.left, textRectNative.left,
+     "The character left is wrong");
+  is(result.height, textRectNative.height,
+     "The character height is wrong");
+  is(result.width, textRectNative.width,
+     "The character width is wrong");
+  is(result.offset, 6,
+     "The character offset is wrong");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectNative.left + 1, textRectNative.top + 1);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT) should succeed");
+  is(result.top, textRectNative.top,
+     "The character top should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.left, textRectNative.left,
+     "The character left should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.height, textRectNative.height,
+     "The character height should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.width, textRectNative.width,
+     "The character width should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+  is(result.offset, 6,
+     "The character offset should be same as calling with QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_CHARACTER_AT_POINT, 0, 0, textRectXP.left + 1, textRectXP.top + 1,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_CHARACTER_AT_POINT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+  is(result.top, textRectXP.top,
+     "The character top is wrong");
+  is(result.left, textRectXP.left,
+     "The character left is wrong");
+  is(result.height, textRectXP.height,
+     "The character height is wrong");
+  is(result.width, textRectXP.width,
+     "The character width is wrong");
+  is(result.offset, 6 - kLineBreak.length + 1,
+     "The character offset is wrong");
+
+  // SelectionSet and QuerySelectedText
+  var selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(selectionSet,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  expectedStr = escape(("abc" + kLineBreak + "def").substr(0, 6));
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  ok(!result.reversed,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should set non-reversed selection");
+  is(escape(result.text), expectedStr,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) got unexpected string");
+
+  selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_XP_LINE_BREAK);
+  ok(selectionSet,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK) should succeed");
+  expectedStr = escape(("abc\ndef").substr(0, 6));
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+  ok(!result.reversed,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK) should set non-reversed selection");
+  is(escape(result.text), expectedStr,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) got unexpected string");
+
+  var selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK | gUtils.SELECTION_SET_FLAG_REVERSE);
+  ok(selectionSet,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK) should succeed");
+  ok(result.reversed,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should set reversed selection");
+
+  selectionSet = gUtils.sendSelectionSetEvent(0, 6, gUtils.SELECTION_SET_FLAG_USE_XP_LINE_BREAK | gUtils.SELECTION_SET_FLAG_REVERSE);
+  ok(selectionSet,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should succeed");
+
+  result = gUtils.sendQueryContentEvent(gUtils.QUERY_SELECTED_TEXT, 0, 0, 0, 0,
+                                        gUtils.QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
+  ok(result.succeeded,
+     "sendQueryContentEvent(QUERY_SELECTED_TEXT, QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK) should succeed");
+  ok(result.reversed,
+     "sendSelectionSetEvent(0, 6, SELECTION_SET_FLAG_USE_XP_LINE_BREAK | SELECTION_SET_FLAG_REVERSE) should set reversed selection");
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(runTests);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -38,17 +38,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 
-[scriptable, uuid(926c7450-ab88-11e3-a5e2-0800200c9a66)]
+[scriptable, uuid(9376bafe-e7b1-48e7-87e2-1e64a7b5d54d)]
 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.
@@ -1016,27 +1016,41 @@ interface nsIDOMWindowUtils : nsISupport
    * Creating synthesizer of composition string on the window.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
    * Will throw a DOM security error if called without chrome privileges.
    */
   nsICompositionStringSynthesizer createCompositionStringSynthesizer();
 
   /**
+   * If sendQueryContentEvent()'s aAdditionalFlags argument is
+   * QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK, plain text generated from content
+   * is created with "\n".
+   * Otherwise, platform dependent.  E.g., on Windows, "\r\n" is used.
+   * aOffset and aLength are offset and length in/of the plain text content.
+   * This flag also affects the result values such as offset, length and string.
+   */
+  const unsigned long QUERY_CONTENT_FLAG_USE_NATIVE_LINE_BREAK = 0x0000;
+  const unsigned long QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK     = 0x0001;
+
+  /**
    * Synthesize a query content event. Note that the result value returned here
    * is in LayoutDevice pixels rather than CSS pixels.
    *
    * @param aType  One of the following const values.  And see also each comment
    *               for the other parameters and the result.
+   * @param aAdditionalFlags See the description of QUERY_CONTENT_FLAG_*.
    */
-  nsIQueryContentEventResult sendQueryContentEvent(in unsigned long aType,
-                                                   in unsigned long aOffset,
-                                                   in unsigned long aLength,
-                                                   in long aX,
-                                                   in long aY);
+  nsIQueryContentEventResult sendQueryContentEvent(
+                               in unsigned long aType,
+                               in unsigned long aOffset,
+                               in unsigned long aLength,
+                               in long aX,
+                               in long aY,
+                               [optional] in unsigned long aAdditionalFlags);
 
   // NOTE: following values are same as NS_QUERY_* in BasicEvents.h
 
   /**
    * QUERY_SELECTED_TEXT queries the first selection range's information.
    *
    * @param aOffset   Not used.
    * @param aLength   Not used.
@@ -1139,31 +1153,45 @@ interface nsIDOMWindowUtils : nsISupport
 
   /**
    * Called when the child frame has fully exit fullscreen, so that the parent
    * process can also fully exit.
    */
   void exitFullscreen();
 
   /**
+   * If sendQueryContentEvent()'s aAdditionalFlags argument is
+   * SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK, aOffset and aLength are offset
+   * and length in/of plain text generated from content is created with "\n".
+   * Otherwise, platform dependent.  E.g., on Windows, "\r\n" is used.
+   */
+  const unsigned long SELECTION_SET_FLAG_USE_NATIVE_LINE_BREAK = 0x0000;
+  const unsigned long SELECTION_SET_FLAG_USE_XP_LINE_BREAK     = 0x0001;
+
+  /**
+   * If SELECTION_SET_FLAG_REVERSE is set, the selection is set from
+   * |aOffset + aLength| to |aOffset|.  Otherwise, it's set from |aOffset| to
+   * |aOffset + aLength|.
+   */
+  const unsigned long SELECTION_SET_FLAG_REVERSE               = 0x0002;
+
+  /**
    * Synthesize a selection set event to the window.
    *
    * This sets the selection as the specified information.
    *
    * @param aOffset  The caret offset of the selection start.
    * @param aLength  The length of the selection.  If this is too long, the
    *                 extra length is ignored.
-   * @param aReverse If true, the selection set from |aOffset + aLength| to
-   *                 |aOffset|.  Otherwise, set from |aOffset| to
-   *                 |aOffset + aLength|.
+   * @param aAdditionalFlags See the description of SELECTION_SET_FLAG_*.
    * @return True, if succeeded.  Otherwise, false.
    */
   boolean sendSelectionSetEvent(in unsigned long aOffset,
                                 in unsigned long aLength,
-                                in boolean aReverse);
+                                [optional] in unsigned long aAdditionalFlags);
 
   /* Selection behaviors - mirror nsIFrame's nsSelectionAmount constants */
   const unsigned long SELECT_CHARACTER   = 0;
   const unsigned long SELECT_CLUSTER     = 1;
   const unsigned long SELECT_WORD        = 2;
   const unsigned long SELECT_LINE        = 3;
   const unsigned long SELECT_BEGINLINE   = 4;
   const unsigned long SELECT_ENDLINE     = 5;