Bug 1200194 - Add UpdateCaretsHint to guide appearance changing. r=roc draft
authorTing-Yu Lin <tlin@mozilla.com>
Tue, 08 Sep 2015 17:04:26 +0800
changeset 290882 1af64c81b8ecd5b34daa48d923bf1a9a3da0b129
parent 290881 5aaf92fa20d3295b9d16d525a6b5136773214cdd
child 290883 97b98bf244e17e1d781951e69e016b02bb548def
push id5185
push usertlin@mozilla.com
push dateTue, 08 Sep 2015 09:19:58 +0000
reviewersroc
bugs1200194
milestone43.0a1
Bug 1200194 - Add UpdateCaretsHint to guide appearance changing. r=roc This is the patch which fixed the bug. When calling OnScrollPositionChanged in cursor mode, we want the appearance of the caret to be preserved since the caret might be hidden due to timeout. We should respect the old appearance of the caret.
layout/base/AccessibleCaretManager.cpp
layout/base/AccessibleCaretManager.h
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -92,35 +92,35 @@ AccessibleCaretManager::HideCarets()
     mFirstCaret->SetAppearance(Appearance::None);
     mSecondCaret->SetAppearance(Appearance::None);
     DispatchCaretStateChangedEvent(CaretChangedReason::Visibilitychange);
     CancelCaretTimeoutTimer();
   }
 }
 
 void
-AccessibleCaretManager::UpdateCarets()
+AccessibleCaretManager::UpdateCarets(UpdateCaretsHint aHint)
 {
   mCaretMode = GetCaretMode();
 
   switch (mCaretMode) {
   case CaretMode::None:
     HideCarets();
     break;
   case CaretMode::Cursor:
-    UpdateCaretsForCursorMode();
+    UpdateCaretsForCursorMode(aHint);
     break;
   case CaretMode::Selection:
-    UpdateCaretsForSelectionMode();
+    UpdateCaretsForSelectionMode(aHint);
     break;
   }
 }
 
 void
-AccessibleCaretManager::UpdateCaretsForCursorMode()
+AccessibleCaretManager::UpdateCaretsForCursorMode(UpdateCaretsHint aHint)
 {
   AC_LOG("%s, selection: %p", __FUNCTION__, GetSelection());
 
   nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
   if (!caret || !caret->IsVisible()) {
     HideCarets();
     return;
   }
@@ -143,21 +143,30 @@ AccessibleCaretManager::UpdateCaretsForC
   PositionChangedResult result = mFirstCaret->SetPosition(frame, offset);
 
   switch (result) {
     case PositionChangedResult::NotChanged:
       // Do nothing
       break;
 
     case PositionChangedResult::Changed:
-      if (nsContentUtils::HasNonEmptyTextContent(
-            editingHost, nsContentUtils::eRecurseIntoChildren)) {
-        mFirstCaret->SetAppearance(Appearance::Normal);
-      } else {
-        mFirstCaret->SetAppearance(Appearance::NormalNotShown);
+      switch (aHint) {
+        case UpdateCaretsHint::Default:
+          if (nsContentUtils::HasNonEmptyTextContent(
+                editingHost, nsContentUtils::eRecurseIntoChildren) ) {
+            mFirstCaret->SetAppearance(Appearance::Normal);
+          } else {
+            mFirstCaret->SetAppearance(Appearance::NormalNotShown);
+          }
+          break;
+
+        case UpdateCaretsHint::RespectOldAppearance:
+          // Do nothing to prevent the appearance of the caret being
+          // changed from NormalNotShown to Normal.
+          break;
       }
       break;
 
     case PositionChangedResult::Invisible:
       mFirstCaret->SetAppearance(Appearance::NormalNotShown);
       break;
   }
 
@@ -168,17 +177,17 @@ AccessibleCaretManager::UpdateCaretsForC
 
   if ((result != PositionChangedResult::NotChanged || oldSecondCaretVisible) &&
       !mActiveCaret) {
     DispatchCaretStateChangedEvent(CaretChangedReason::Updateposition);
   }
 }
 
 void
-AccessibleCaretManager::UpdateCaretsForSelectionMode()
+AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
 {
   AC_LOG("%s: selection: %p", __FUNCTION__, GetSelection());
 
   int32_t startOffset = 0;
   nsIFrame* startFrame = FindFirstNodeWithFrame(false, &startOffset);
 
   int32_t endOffset = 0;
   nsIFrame* endFrame = FindFirstNodeWithFrame(true, &endOffset);
@@ -424,18 +433,18 @@ AccessibleCaretManager::OnScrolling()
 
 void
 AccessibleCaretManager::OnScrollPositionChanged()
 {
   if (mCaretMode != GetCaretMode()) {
     return;
   }
 
-  AC_LOG("%s: UpdateCarets()", __FUNCTION__);
-  UpdateCarets();
+  AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
+  UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
 }
 
 void
 AccessibleCaretManager::OnReflow()
 {
   if (mCaretMode != GetCaretMode()) {
     return;
   }
--- a/layout/base/AccessibleCaretManager.h
+++ b/layout/base/AccessibleCaretManager.h
@@ -73,17 +73,18 @@ public:
   virtual void OnScrollStart();
 
   // Handle scroll-end event.
   virtual void OnScrollEnd();
 
   // Handle NS_WHEEL_WHEEL event.
   virtual void OnScrolling();
 
-  // Handle ScrollPositionChanged from nsIScrollObserver.
+  // Handle ScrollPositionChanged from nsIScrollObserver. This might be called
+  // at anytime, not necessary between OnScrollStart and OnScrollEnd.
   virtual void OnScrollPositionChanged();
 
   // Handle reflow event from nsIReflowObserver.
   virtual void OnReflow();
 
   // Handle blur event from nsFocusManager.
   virtual void OnBlur();
 
@@ -103,21 +104,30 @@ protected:
     // One caret, i.e. the selection is collapsed.
     Cursor,
 
     // Two carets, i.e. the selection is not collapsed.
     Selection
   };
   CaretMode GetCaretMode() const;
 
-  void UpdateCarets();
+  enum class UpdateCaretsHint : uint8_t {
+    // Update everything including appearance and position.
+    Default,
+
+    // Update everything while respecting the old appearance. For example, if
+    // the caret in cursor mode is hidden due to timeout, do not change its
+    // appearance to Normal.
+    RespectOldAppearance
+  };
+  void UpdateCarets(UpdateCaretsHint aHint = UpdateCaretsHint::Default);
   void HideCarets();
 
-  void UpdateCaretsForCursorMode();
-  void UpdateCaretsForSelectionMode();
+  void UpdateCaretsForCursorMode(UpdateCaretsHint aHint);
+  void UpdateCaretsForSelectionMode(UpdateCaretsHint aHint);
   void UpdateCaretsForTilt();
 
   // Get the nearest enclosing focusable frame of aFrame.
   // @return focusable frame if there is any; nullptr otherwise.
   nsIFrame* GetFocusableFrame(nsIFrame* aFrame) const;
 
   // Change focus to aFrame if it isn't nullptr. Otherwise, clear the old focus
   // then re-focus the window.