Bug 1321623 - Implement DOM Selection.setBaseAndExtent(). r=smaug
authorMats Palmgren <mats@mozilla.com>
Mon, 19 Dec 2016 16:48:37 +0100
changeset 326511 c389436be671
parent 326510 07f8e09df411
child 326512 ddfcb1823adc
push id31106
push userkwierso@gmail.com
push dateTue, 20 Dec 2016 19:42:03 +0000
treeherdermozilla-central@7083c0d30e75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1321623
milestone53.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 1321623 - Implement DOM Selection.setBaseAndExtent(). r=smaug
dom/base/nsRange.cpp
dom/webidl/Selection.webidl
layout/generic/Selection.h
layout/generic/nsSelection.cpp
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -289,16 +289,18 @@ nsRange::CreateRange(nsIDOMNode* aStartP
   MOZ_ASSERT(aRange);
   *aRange = nullptr;
 
   nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
   NS_ENSURE_ARG_POINTER(startParent);
 
   RefPtr<nsRange> range = new nsRange(startParent);
 
+  // XXX this can be optimized by inlining SetStart/End and calling
+  // DoSetRange *once*.
   nsresult rv = range->SetStart(startParent, aStartOffset);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = range->SetEnd(aEndParent, aEndOffset);
   NS_ENSURE_SUCCESS(rv, rv);
 
   range.forget(aRange);
   return NS_OK;
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -40,16 +40,22 @@ interface Selection {
   [Throws]
   void               removeRange(Range range);
   [Throws]
   void               removeAllRanges();
 
   [Throws]
   boolean            containsNode(Node node, boolean allowPartialContainment);
 
+  [Throws]
+  void               setBaseAndExtent(Node anchorNode,
+                                      unsigned long anchorOffset,
+                                      Node focusNode,
+                                      unsigned long focusOffset);
+
   stringifier;
 };
 
 // Additional methods not currently in the spec
 partial interface Selection {
   [Throws]
   void modify(DOMString alter, DOMString direction,
               DOMString granularity);
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -190,16 +190,20 @@ public:
    * in any one of them.
    * @param aPoint The point to check, relative to the root frame.
    */
   bool ContainsPoint(const nsPoint& aPoint);
 
   void Modify(const nsAString& aAlter, const nsAString& aDirection,
               const nsAString& aGranularity, mozilla::ErrorResult& aRv);
 
+  void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
+                        nsINode& aFocusNode, uint32_t aFocusOffset,
+                        mozilla::ErrorResult& aRv);
+
   bool GetInterlinePosition(mozilla::ErrorResult& aRv);
   void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
 
   Nullable<int16_t> GetCaretBidiLevel(mozilla::ErrorResult& aRv) const;
   void SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv);
 
   void ToStringWithFormat(const nsAString& aFormatType,
                           uint32_t aFlags,
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -6426,16 +6426,65 @@ Selection::Modify(const nsAString& aAlte
     nsCOMPtr<nsISelectionController> shell =
       do_QueryInterface(mFrameSelection->GetShell());
     if (!shell)
       return;
     shell->CompleteMove(forward, extend);
   }
 }
 
+void
+Selection::SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
+                            nsINode& aFocusNode, uint32_t aFocusOffset,
+                            ErrorResult& aRv)
+{
+  if (!mFrameSelection) {
+    return;
+  }
+
+  SelectionBatcher batch(this);
+
+  int32_t relativePosition =
+    nsContentUtils::ComparePoints(&aAnchorNode, aAnchorOffset,
+                                  &aFocusNode, aFocusOffset);
+  nsINode* start = &aAnchorNode;
+  nsINode* end = &aFocusNode;
+  uint32_t startOffset = aAnchorOffset;
+  uint32_t endOffset = aFocusOffset;
+  if (relativePosition > 0) {
+    start = &aFocusNode;
+    end = &aAnchorNode;
+    startOffset = aFocusOffset;
+    endOffset = aAnchorOffset;
+  }
+
+  RefPtr<nsRange> newRange;
+  nsresult rv = nsRange::CreateRange(start, startOffset, end, endOffset,
+                                     getter_AddRefs(newRange));
+  // CreateRange returns IndexSizeError if any offset is out of bounds.
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  rv = RemoveAllRanges();
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  rv = AddRange(newRange);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  SetDirection(relativePosition > 0 ? eDirPrevious : eDirNext);
+}
+
 /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  *  @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  */
 NS_IMETHODIMP
 Selection::SelectionLanguageChange(bool aLangRTL)
 {
   if (!mFrameSelection)
     return NS_ERROR_NOT_INITIALIZED; // Can't do selection