Bug 988143 - Enable Gecko Touch in Fennec, TouchCaret Scroll mods, r=ehsan
authorMark Capella <markcapella@twcny.rr.com>
Thu, 14 May 2015 22:06:13 -0400
changeset 244024 35cab4c3e81d05d783d1b0623f63b1c0b207b63e
parent 244023 0f3dc51af81675c0cc43a54671a19d497d933bb2
child 244025 b672dd2d3693644514b2180fa0072af94be6a1a1
push id59820
push usercbook@mozilla.com
push dateFri, 15 May 2015 15:41:47 +0000
treeherdermozilla-inbound@5943d32f3515 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs988143
milestone41.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 988143 - Enable Gecko Touch in Fennec, TouchCaret Scroll mods, r=ehsan
layout/base/SelectionCarets.cpp
layout/base/TouchCaret.cpp
layout/base/TouchCaret.h
layout/base/nsPresShell.cpp
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -52,18 +52,16 @@ static const char* kSelectionCaretsLogMo
 #define SELECTIONCARETS_LOG_STATIC(message, ...)                               \
   PR_LOG(gSelectionCaretsLog, PR_LOG_DEBUG,                                    \
          ("SelectionCarets: %s:%d : " message "\n", __FUNCTION__, __LINE__,    \
           ##__VA_ARGS__));
 
 // We treat mouse/touch move as "REAL" move event once its move distance
 // exceed this value, in CSS pixel.
 static const int32_t kMoveStartTolerancePx = 5;
-// Time for trigger scroll end event, in miliseconds.
-static const int32_t kScrollEndTimerDelay = 300;
 
 NS_IMPL_ISUPPORTS(SelectionCarets,
                   nsIReflowObserver,
                   nsISelectionListener,
                   nsIScrollObserver,
                   nsISupportsWeakReference)
 
 /*static*/ int32_t SelectionCarets::sSelectionCaretsInflateSize = 0;
@@ -1281,20 +1279,21 @@ void
 SelectionCarets::LaunchScrollEndDetector()
 {
   if (!mScrollEndDetectorTimer) {
     mScrollEndDetectorTimer = do_CreateInstance("@mozilla.org/timer;1");
   }
 
   MOZ_ASSERT(mScrollEndDetectorTimer);
 
-  SELECTIONCARETS_LOG("Will fire scroll end after %d ms", kScrollEndTimerDelay);
+  SELECTIONCARETS_LOG("Will fire scroll end after %d ms",
+    TouchCaret::sScrollEndTimerDelay);
   mScrollEndDetectorTimer->InitWithFuncCallback(FireScrollEnd,
                                                 this,
-                                                kScrollEndTimerDelay,
+                                                TouchCaret::sScrollEndTimerDelay,
                                                 nsITimer::TYPE_ONE_SHOT);
 }
 
 void
 SelectionCarets::CancelScrollEndDetector()
 {
   if (!mScrollEndDetectorTimer) {
     return;
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -51,29 +51,33 @@ static const char* kTouchCaretLogModuleN
          ("TouchCaret: %s:%d : " message "\n", __FUNCTION__, __LINE__,         \
           ##__VA_ARGS__));
 
 // Click on the boundary of input/textarea will place the caret at the
 // front/end of the content. To advoid this, we need to deflate the content
 // boundary by 61 app units (1 pixel + 1 app unit).
 static const int32_t kBoundaryAppUnits = 61;
 
-NS_IMPL_ISUPPORTS(TouchCaret, nsISelectionListener)
+NS_IMPL_ISUPPORTS(TouchCaret,
+                  nsISelectionListener,
+                  nsIScrollObserver,
+                  nsISupportsWeakReference)
 
 /*static*/ int32_t TouchCaret::sTouchCaretInflateSize = 0;
 /*static*/ int32_t TouchCaret::sTouchCaretExpirationTime = 0;
 /*static*/ bool TouchCaret::sCaretManagesAndroidActionbar = false;
 /*static*/ bool TouchCaret::sTouchcaretExtendedvisibility = false;
 
 /*static*/ uint32_t TouchCaret::sActionBarViewCount = 0;
 
 TouchCaret::TouchCaret(nsIPresShell* aPresShell)
   : mState(TOUCHCARET_NONE),
     mActiveTouchId(-1),
     mCaretCenterToDownPointOffsetY(0),
+    mInAsyncPanZoomGesture(false),
     mVisible(false),
     mIsValidTap(false),
     mActionBarViewID(0)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gTouchCaretLog) {
     gTouchCaretLog = PR_NewLogModule(kTouchCaretLogModuleName);
@@ -94,16 +98,53 @@ TouchCaret::TouchCaret(nsIPresShell* aPr
     addedTouchCaretPref = true;
   }
 
   // The presshell owns us, so no addref.
   mPresShell = do_GetWeakReference(aPresShell);
   MOZ_ASSERT(mPresShell, "Hey, pres shell should support weak refs");
 }
 
+void
+TouchCaret::Init()
+{
+  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
+  if (!presShell) {
+    return;
+  }
+
+  nsPresContext* presContext = presShell->GetPresContext();
+  MOZ_ASSERT(presContext, "PresContext should be given in PresShell::Init()");
+
+  nsIDocShell* docShell = presContext->GetDocShell();
+  if (!docShell) {
+    return;
+  }
+
+  docShell->AddWeakScrollObserver(this);
+  mDocShell = static_cast<nsDocShell*>(docShell);
+}
+
+void
+TouchCaret::Terminate()
+{
+  nsRefPtr<nsDocShell> docShell(mDocShell.get());
+  if (docShell) {
+    docShell->RemoveWeakScrollObserver(this);
+  }
+
+  if (mScrollEndDetectorTimer) {
+    mScrollEndDetectorTimer->Cancel();
+    mScrollEndDetectorTimer = nullptr;
+  }
+
+  mDocShell = WeakPtr<nsDocShell>();
+  mPresShell = nullptr;
+}
+
 TouchCaret::~TouchCaret()
 {
   TOUCHCARET_LOG("Destructor");
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mTouchCaretExpirationTimer) {
     mTouchCaretExpirationTimer->Cancel();
     mTouchCaretExpirationTimer = nullptr;
@@ -422,16 +463,86 @@ TouchCaret::NotifySelectionChanged(nsIDO
         }
       }
     }
   }
 
   return NS_OK;
 }
 
+/**
+ * Used to update caret position after PanZoom stops for
+ * extended caret visibility. Never needed by MOZ_WIDGET_GONK.
+ */
+void
+TouchCaret::AsyncPanZoomStarted()
+{
+  if (mVisible) {
+    if (sTouchcaretExtendedvisibility) {
+      mInAsyncPanZoomGesture = true;
+    }
+  }
+}
+
+void
+TouchCaret::AsyncPanZoomStopped()
+{
+  if (mInAsyncPanZoomGesture) {
+    mInAsyncPanZoomGesture = false;
+    UpdatePosition();
+  }
+}
+
+/**
+ * Used to update caret position after Scroll stops for
+ * extended caret visibility. Never needed by MOZ_WIDGET_GONK.
+ */
+void
+TouchCaret::ScrollPositionChanged()
+{
+  if (mVisible) {
+    if (sTouchcaretExtendedvisibility) {
+      // Launch scroll end detector.
+      LaunchScrollEndDetector();
+    }
+  }
+}
+
+void
+TouchCaret::LaunchScrollEndDetector()
+{
+  if (!mScrollEndDetectorTimer) {
+    mScrollEndDetectorTimer = do_CreateInstance("@mozilla.org/timer;1");
+  }
+  MOZ_ASSERT(mScrollEndDetectorTimer);
+
+  mScrollEndDetectorTimer->InitWithFuncCallback(FireScrollEnd,
+                                                this,
+                                                sScrollEndTimerDelay,
+                                                nsITimer::TYPE_ONE_SHOT);
+}
+
+void
+TouchCaret::CancelScrollEndDetector()
+{
+  if (mScrollEndDetectorTimer) {
+    mScrollEndDetectorTimer->Cancel();
+  }
+}
+
+
+/* static */void
+TouchCaret::FireScrollEnd(nsITimer* aTimer, void* aTouchCaret)
+{
+  nsRefPtr<TouchCaret> self = static_cast<TouchCaret*>(aTouchCaret);
+  NS_PRECONDITION(aTimer == self->mScrollEndDetectorTimer,
+                  "Unexpected timer");
+  self->UpdatePosition();
+}
+
 void
 TouchCaret::SyncVisibilityWithCaret()
 {
   TOUCHCARET_LOG("SyncVisibilityWithCaret");
 
   if (!IsDisplayable()) {
     SetVisibility(false);
     return;
--- a/layout/base/TouchCaret.h
+++ b/layout/base/TouchCaret.h
@@ -22,28 +22,35 @@ class nsIPresShell;
 namespace mozilla {
 
 /**
  * The TouchCaret places a touch caret according to caret position when the
  * caret is shown.
  * TouchCaret is also responsible for touch caret visibility. Touch caret
  * won't be shown when timer expires or while key event causes selection change.
  */
-class TouchCaret final : public nsISelectionListener
+class TouchCaret final : public nsISelectionListener,
+                         public nsIScrollObserver,
+                         public nsSupportsWeakReference
 {
 public:
   explicit TouchCaret(nsIPresShell* aPresShell);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISELECTIONLISTENER
 
-  void Terminate()
-  {
-    mPresShell = nullptr;
-  }
+  void Init();
+  void Terminate();
+
+  // nsIScrollObserver
+  virtual void ScrollPositionChanged() override;
+
+  // AsyncPanZoom started/stopped callbacks from nsIScrollObserver
+  virtual void AsyncPanZoomStarted() override;
+  virtual void AsyncPanZoomStopped() override;
 
   /**
    * Handle mouse and touch event only.
    * Depends on visibility and position of touch caret, HandleEvent may consume
    * that input event and return nsEventStatus_eConsumeNoDefault to the caller.
    * In that case, caller should stop bubble up that input event.
    */
   nsEventStatus HandleEvent(WidgetEvent* aEvent);
@@ -268,17 +275,31 @@ private:
    */
   static int32_t TouchCaretInflateSize() { return sTouchCaretInflateSize; }
 
   static int32_t TouchCaretExpirationTime()
   {
     return sTouchCaretExpirationTime;
   }
 
+  void LaunchScrollEndDetector();
+  void CancelScrollEndDetector();
+  static void FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets);
+
+  // This timer is used for detecting scroll end. We don't have
+  // scroll end event now, so we will fire this event with a
+  // const time when we scroll. So when timer triggers, we treat it
+  // as scroll end event.
+  nsCOMPtr<nsITimer> mScrollEndDetectorTimer;
+
   nsWeakPtr mPresShell;
+  WeakPtr<nsDocShell> mDocShell;
+
+  // True if AsyncPanZoom is started
+  bool mInAsyncPanZoomGesture;
 
   // Touch caret visibility
   bool mVisible;
   // Use for detecting single tap on touch caret.
   bool mIsValidTap;
   // Touch caret timer
   nsCOMPtr<nsITimer> mTouchCaretExpirationTimer;
 
@@ -286,15 +307,17 @@ private:
   static int32_t sTouchCaretInflateSize;
   static int32_t sTouchCaretExpirationTime;
   static bool sCaretManagesAndroidActionbar;
   static bool sTouchcaretExtendedvisibility;
 
   // The auto scroll timer's interval in miliseconds.
   friend class SelectionCarets;
   static const int32_t sAutoScrollTimerDelay = 30;
+  // Time for trigger scroll end event, in miliseconds.
+  static const int32_t sScrollEndTimerDelay = 300;
 
   // Unique ID of current Mobile ActionBar view.
   static uint32_t sActionBarViewCount;
   uint32_t mActionBarViewID;
 };
 } //namespace mozilla
 #endif //mozilla_TouchCaret_h__
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -894,16 +894,17 @@ PresShell::Init(nsIDocument* aDocument,
 
   // setup the preference style rules (no forced reflow), and do it
   // before creating any frames.
   SetPreferenceStyleRules(false);
 
   if (TouchCaretPrefEnabled() && !AccessibleCaretEnabled()) {
     // Create touch caret handle
     mTouchCaret = new TouchCaret(this);
+    mTouchCaret->Init();
   }
 
   if (SelectionCaretPrefEnabled() && !AccessibleCaretEnabled()) {
     // Create selection caret handle
     mSelectionCarets = new SelectionCarets(this);
     mSelectionCarets->Init();
   }