Bug 1404854 Part 3 - Fix page cannot be scrolled automatically when dragging caret. r=mtseng
authorTing-Yu Lin <tlin@mozilla.com>
Fri, 06 Oct 2017 15:54:23 +0800
changeset 385444 cc0c99d812fd1cb33e13450a1d025d1f7d69e244
parent 385443 d5fc6f59adce85c9f0e60fda16a03219540c85e3
child 385445 c63d0efbbcfd4a33e325ae4a41be043d6a247405
child 385467 a72bd6160609be2fa471be5f87955bdd47fafe22
push id53035
push usertlin@mozilla.com
push dateWed, 11 Oct 2017 05:32:09 +0000
treeherderautoland@cc0c99d812fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmtseng
bugs1404854
milestone58.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 1404854 Part 3 - Fix page cannot be scrolled automatically when dragging caret. r=mtseng The issue is: when we hit some failure conditions in DragCaretInternal() such as the frame is not selectable, or no frame is under the point, etc., we'll early return so that the auto scroll code is not being executed. The logic in StartSelectionAutoScrollTimer() is similar to how nsFrame::HandleDrag() handles the auto scrolling. MozReview-Commit-ID: FtXZ8BWp3BX
layout/base/AccessibleCaretManager.cpp
layout/base/AccessibleCaretManager.h
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -505,17 +505,21 @@ AccessibleCaretManager::DragCaret(const 
 {
   MOZ_ASSERT(mActiveCaret);
   MOZ_ASSERT(GetCaretMode() != CaretMode::None);
 
   if (!mPresShell || !mPresShell->GetRootFrame() || !GetSelection()) {
     return NS_ERROR_NULL_POINTER;
   }
 
+  StopSelectionAutoScrollTimer();
   DragCaretInternal(aPoint);
+
+  // We want to scroll the page even if we failed to drag the caret.
+  StartSelectionAutoScrollTimer(aPoint);
   UpdateCarets();
   return NS_OK;
 }
 
 nsresult
 AccessibleCaretManager::ReleaseCaret()
 {
   MOZ_ASSERT(mActiveCaret);
@@ -1248,45 +1252,26 @@ AccessibleCaretManager::DragCaretInterna
   }
 
   nsIFrame::ContentOffsets offsets =
     newFrame->GetContentOffsetsFromPoint(newPoint);
   if (offsets.IsNull()) {
     return NS_ERROR_FAILURE;
   }
 
-  Selection* selection = GetSelection();
-  MOZ_ASSERT(selection);
-
   if (GetCaretMode() == CaretMode::Selection &&
       !RestrictCaretDraggingOffsets(offsets)) {
     return NS_ERROR_FAILURE;
   }
 
   ClearMaintainedSelection();
 
-  nsIFrame* anchorFrame = nullptr;
-  selection->GetPrimaryFrameForAnchorNode(&anchorFrame);
-
-  nsIFrame* scrollable =
-    nsLayoutUtils::GetClosestFrameOfType(anchorFrame, LayoutFrameType::Scroll);
-  AutoWeakFrame weakScrollable = scrollable;
   fs->HandleClick(offsets.content, offsets.StartOffset(), offsets.EndOffset(),
                   GetCaretMode() == CaretMode::Selection, false,
                   offsets.associate);
-  if (!weakScrollable.IsAlive()) {
-    return NS_OK;
-  }
-
-  // Scroll scrolled frame.
-  nsIScrollableFrame* saf = do_QueryFrame(scrollable);
-  nsIFrame* capturingFrame = saf->GetScrolledFrame();
-  nsPoint ptInScrolled = point;
-  nsLayoutUtils::TransformPoint(rootFrame, capturingFrame, ptInScrolled);
-  fs->StartAutoScrollTimer(capturingFrame, ptInScrolled, kAutoScrollTimerDelay);
   return NS_OK;
 }
 
 nsRect
 AccessibleCaretManager::GetAllChildFrameRectsUnion(nsIFrame* aFrame) const
 {
   nsRect unionRect;
 
@@ -1371,16 +1356,61 @@ AccessibleCaretManager::AdjustDragBounda
       }
     }
   }
 
   return adjustedPoint;
 }
 
 void
+AccessibleCaretManager::StartSelectionAutoScrollTimer(
+  const nsPoint& aPoint) const
+{
+  Selection* selection = GetSelection();
+  MOZ_ASSERT(selection);
+
+  nsIFrame* anchorFrame = nullptr;
+  selection->GetPrimaryFrameForAnchorNode(&anchorFrame);
+  if (!anchorFrame) {
+    return;
+  }
+
+  nsIScrollableFrame* scrollFrame =
+    nsLayoutUtils::GetNearestScrollableFrame(
+      anchorFrame,
+      nsLayoutUtils::SCROLLABLE_SAME_DOC |
+      nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
+  if (!scrollFrame) {
+    return;
+  }
+
+  nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
+  if (!capturingFrame) {
+    return;
+  }
+
+  nsIFrame* rootFrame = mPresShell->GetRootFrame();
+  MOZ_ASSERT(rootFrame);
+  nsPoint ptInScrolled = aPoint;
+  nsLayoutUtils::TransformPoint(rootFrame, capturingFrame, ptInScrolled);
+
+  RefPtr<nsFrameSelection> fs = GetFrameSelection();
+  MOZ_ASSERT(fs);
+  fs->StartAutoScrollTimer(capturingFrame, ptInScrolled, kAutoScrollTimerDelay);
+}
+
+void
+AccessibleCaretManager::StopSelectionAutoScrollTimer() const
+{
+  RefPtr<nsFrameSelection> fs = GetFrameSelection();
+  MOZ_ASSERT(fs);
+  fs->StopAutoScrollTimer();
+}
+
+void
 AccessibleCaretManager::DispatchCaretStateChangedEvent(CaretChangedReason aReason) const
 {
   if (!mPresShell) {
     return;
   }
 
   FlushLayout();
   if (IsTerminated()) {
--- a/layout/base/AccessibleCaretManager.h
+++ b/layout/base/AccessibleCaretManager.h
@@ -186,16 +186,22 @@ protected:
   nsIFrame* GetFrameForFirstRangeStartOrLastRangeEnd(
     nsDirection aDirection,
     int32_t* aOutOffset,
     nsIContent** aOutContent = nullptr,
     int32_t* aOutContentOffset = nullptr) const;
 
   nsresult DragCaretInternal(const nsPoint& aPoint);
   nsPoint AdjustDragBoundary(const nsPoint& aPoint) const;
+
+  // Start the selection scroll timer if the caret is being dragged out of
+  // the scroll port.
+  void StartSelectionAutoScrollTimer(const nsPoint& aPoint) const;
+  void StopSelectionAutoScrollTimer() const;
+
   void ClearMaintainedSelection() const;
 
   // Caller is responsible to use IsTerminated() to check whether PresShell is
   // still valid.
   void FlushLayout() const;
 
   dom::Element* GetEditingHostForFrame(nsIFrame* aFrame) const;
   dom::Selection* GetSelection() const;