Bug 1343037 part 11. Implement a SetSelectionRange function on nsTextEditorState. r=ehsan
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 09 Mar 2017 14:44:05 -0500
changeset 397585 b3416e9f0d5cf21b653bc1e9c2c457d7125a1fc9
parent 397584 ebe6ea1d1332505a35158dca7041af37d6e394e8
child 397586 69da5429c4b4ecb2423132f0e33df1c67a55e771
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1343037
milestone55.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 1343037 part 11. Implement a SetSelectionRange function on nsTextEditorState. r=ehsan MozReview-Commit-ID: 5xUkcnkptwQ
dom/html/nsTextEditorState.cpp
dom/html/nsTextEditorState.h
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1640,16 +1640,79 @@ nsTextEditorState::GetSelectionDirection
   if (direction == eDirNext) {
     return nsITextControlFrame::eForward;
   }
 
   MOZ_ASSERT(direction == eDirPrevious);
   return nsITextControlFrame::eBackward;
 }
 
+void
+nsTextEditorState::SetSelectionRange(int32_t aStart, int32_t aEnd,
+                                     nsITextControlFrame::SelectionDirection aDirection,
+                                     ErrorResult& aRv)
+{
+  MOZ_ASSERT(IsSelectionCached() || mBoundFrame,
+             "How can we have a non-cached selection but no frame?");
+
+  if (aStart > aEnd) {
+    aStart = aEnd;
+  }
+
+  bool changed = false;
+  nsresult rv = NS_OK; // For the ScrollSelectionIntoView() return value.
+  if (IsSelectionCached()) {
+    nsAutoString value;
+    // XXXbz is "false" the right thing to pass here?  Hard to tell, given the
+    // various mismatches between our impl and the spec.
+    GetValue(value, false);
+    uint32_t length = value.Length();
+    if (uint32_t(aStart) > length) {
+      aStart = length;
+    }
+    if (uint32_t(aEnd) > length) {
+      aEnd = length;
+    }
+    SelectionProperties& props = GetSelectionProperties();
+    changed = props.GetStart() != aStart ||
+              props.GetEnd() != aEnd ||
+              props.GetDirection() != aDirection;
+    props.SetStart(aStart);
+    props.SetEnd(aEnd);
+    props.SetDirection(aDirection);
+  } else {
+    aRv = mBoundFrame->SetSelectionRange(aStart, aEnd, aDirection);
+    if (aRv.Failed()) {
+      return;
+    }
+    rv = mBoundFrame->ScrollSelectionIntoView();
+    // Press on to firing the event even if that failed, like our old code did.
+    // But is that really what we want?  Firing the event _and_ throwing from
+    // here is weird.  Maybe we should just ignore ScrollSelectionIntoView
+    // failures?
+
+    // XXXbz This is preserving our current behavior of firing a "select" event
+    // on all mutations when we have an editor, but we should really consider
+    // fixing that...
+    changed = true;
+  }
+
+  if (changed) {
+    // It sure would be nice if we had an existing Element* or so to work with.
+    nsCOMPtr<nsINode> node = do_QueryInterface(mTextCtrlElement);
+    RefPtr<AsyncEventDispatcher> asyncDispatcher =
+      new AsyncEventDispatcher(node, NS_LITERAL_STRING("select"), true, false);
+    asyncDispatcher->PostDOMEvent();
+  }
+
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+}
+
 HTMLInputElement*
 nsTextEditorState::GetParentNumberControl(nsFrame* aFrame) const
 {
   MOZ_ASSERT(aFrame);
   nsIContent* content = aFrame->GetContent();
   MOZ_ASSERT(content);
   nsIContent* parent = content->GetParent();
   if (!parent) {
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -276,16 +276,32 @@ public:
   // Get the selection range start and end points in our text.
   void GetSelectionRange(int32_t* aSelectionStart, int32_t* aSelectionEnd,
                          mozilla::ErrorResult& aRv);
 
   // Get the selection direction
   nsITextControlFrame::SelectionDirection
     GetSelectionDirection(mozilla::ErrorResult& aRv);
 
+  // Set the selection range (start, end, direction).  aEnd is allowed to be
+  // smaller than aStart; in that case aStart will be reset to the same value as
+  // aEnd.  This basically implements
+  // https://html.spec.whatwg.org/multipage/forms.html#set-the-selection-range
+  // but with the start/end already coerced to zero if null (and without the
+  // special infinity value), and the direction already converted to a
+  // SelectionDirection.
+  //
+  // If we have a frame, this method will scroll the selection into view.
+  //
+  // XXXbz This should really take uint32_t, but none of our guts (either the
+  // frame or our cached selection state) work with uint32_t at the moment...
+  void SetSelectionRange(int32_t aStart, int32_t aEnd,
+                         nsITextControlFrame::SelectionDirection aDirection,
+                         mozilla::ErrorResult& aRv);
+
   void UpdateEditableState(bool aNotify) {
     if (mRootNode) {
       mRootNode->UpdateEditableState(aNotify);
     }
   }
 
 private:
   friend class RestoreSelectionState;