Bug 562447 - when navigating in gmail sometimes get a screen full of white; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 May 2010 18:12:21 -0400
changeset 42170 cfa870bf8e382f2a4c9925d5d53b8dc5b6267c72
parent 42169 e50f79c0570a223f49d2e3c73dffb870417c8f87
child 42171 6a779c75c7bff36632a57a1830e4edb55eeb9644
push id13212
push usereakhgari@mozilla.com
push dateTue, 11 May 2010 21:24:24 +0000
treeherdermozilla-central@36b3e529f9db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs562447
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 562447 - when navigating in gmail sometimes get a screen full of white; r=roc
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
layout/forms/test/Makefile.in
layout/forms/test/test_bug562447.html
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1068,16 +1068,17 @@ nsTextControlFrame::PreDestroy()
           }
         }
       }
     }
   }
 
   mUseEditor = PR_FALSE;
   mEditor = nsnull;
+  mScrollEvent.Revoke();
   if (mSelCon) {
     mSelCon->SetScrollableFrame(nsnull);
     mSelCon = nsnull;
   }
   if (mFrameSel) {
     mFrameSel->DisconnectFromPresShell();
     mFrameSel = nsnull;
   }
@@ -1882,19 +1883,34 @@ nsTextControlFrame::IsCollapsed(nsBoxLay
 }
 
 PRBool
 nsTextControlFrame::IsLeaf() const
 {
   return PR_TRUE;
 }
 
+NS_IMETHODIMP
+nsTextControlFrame::ScrollOnFocusEvent::Run()
+{
+  if (mFrame && mFrame->mSelCon) {
+    mFrame->mScrollEvent.Forget();
+    mFrame->mSelCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
+                                             nsISelectionController::SELECTION_FOCUS_REGION,
+                                             PR_TRUE);
+  }
+  return NS_OK;
+}
+
 //IMPLEMENTING NS_IFORMCONTROLFRAME
 void nsTextControlFrame::SetFocus(PRBool aOn, PRBool aRepaint)
 {
+  // Revoke the previous scroll event if one exists
+  mScrollEvent.Revoke();
+
   if (!aOn) {
     nsWeakFrame weakFrame(this);
 
     nsAutoString valueString;
     GetValue(valueString, PR_TRUE);
     if (valueString.IsEmpty())
       ShowPlaceholder();
 
@@ -1918,19 +1934,21 @@ void nsTextControlFrame::SetFocus(PRBool
   {
     return;
   }
 
   if (NS_SUCCEEDED(InitFocusedValue()))
     MaybeBeginSecureKeyboardInput();
 
   // Scroll the current selection into view
-  mSelCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
-                                   nsISelectionController::SELECTION_FOCUS_REGION,
-                                   PR_FALSE);
+  nsRefPtr<ScrollOnFocusEvent> event = new ScrollOnFocusEvent(this);
+  nsresult rv = NS_DispatchToCurrentThread(event);
+  if (NS_SUCCEEDED(rv)) {
+    mScrollEvent = event;
+  }
 
   // tell the caret to use our selection
 
   nsCOMPtr<nsISelection> ourSel;
   mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, 
     getter_AddRefs(ourSel));
   if (!ourSel) return;
 
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -46,16 +46,17 @@
 #include "nsIEditor.h"
 #include "nsITextControlFrame.h"
 #include "nsIFontMetrics.h"
 #include "nsWeakReference.h" //for service and presshell pointers
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsIScrollableFrame.h"
 #include "nsStubMutationObserver.h"
+#include "nsThreadUtils.h"
 
 class nsIEditor;
 class nsISelectionController;
 class nsTextInputSelectionImpl;
 class nsTextInputListener;
 class nsIDOMCharacterData;
 #ifdef ACCESSIBILITY
 class nsIAccessible;
@@ -262,16 +263,34 @@ protected:
       return NS_OK;
     }
 
   private:
     nsWeakFrame mWeakFrame;
     nsTextControlFrame* mFrame;
   };
 
+  class ScrollOnFocusEvent;
+  friend class ScrollOnFocusEvent;
+
+  class ScrollOnFocusEvent : public nsRunnable {
+  public:
+    ScrollOnFocusEvent(nsTextControlFrame* aFrame) :
+      mFrame(aFrame) {}
+
+    NS_DECL_NSIRUNNABLE
+
+    void Revoke() {
+      mFrame = nsnull;
+    }
+
+  private:
+    nsTextControlFrame* mFrame;
+  };
+
   nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
   nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
 
   /**
    * Find out whether this control is scrollable (i.e. if it is not a single
    * line text control)
    * @return whether this control is scrollable
    */
@@ -372,13 +391,14 @@ private:
 #endif
 
   nsRefPtr<nsTextInputSelectionImpl> mSelCon;
   nsCOMPtr<nsFrameSelection> mFrameSel;
   nsTextInputListener* mTextListener;
   nsString mFocusedValue;
   nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
   nsRefPtr<nsAnonDivObserver> mMutationObserver;
+  nsRevocableEventPtr<ScrollOnFocusEvent> mScrollEvent;
 };
 
 #endif
 
 
--- a/layout/forms/test/Makefile.in
+++ b/layout/forms/test/Makefile.in
@@ -60,13 +60,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug477700.html \
 		     bug477700_subframe.html \
 		test_textarea_resize.html \
 		test_bug478219.xhtml \
 		test_bug542914.html \
 		test_bug536567.html \
 		     bug536567_subframe.html \
 		test_bug549170.html \
+		test_bug562447.html \
 		test_bug563642.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/layout/forms/test/test_bug562447.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=562447
+-->
+<head>
+  <title>Test for Bug 562447</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+</head>
+<body>
+<p><a target="_blank" href="https://bugzilla.mozilla.org/show_bug?id=562447">Mozilla Bug 562447</a>
+
+<input id="WhyDoYouFocusMe"
+       style="position: absolute; left: -50px; top: 10000px;">
+
+<pre id="test">
+<script>
+addLoadEvent(function() {
+  // Scroll down a bit
+  window.scrollTo(0, 5000);
+
+  setTimeout(function() {
+    // Make sure that we're scrolled by 5000px
+    is(window.pageYOffset, 5000, "Make sure we're scrolled correctly");
+
+    // Scroll back up, and mess with the input box along the way
+    var input = document.getElementById("WhyDoYouFocusMe");
+    input.focus();
+    input.blur();
+    window.scrollTo(0, 0);
+
+    setTimeout(function() {
+      is(window.pageYOffset, 0, "Make sure we're scrolled back up correctly");
+
+      // Scroll back up
+      window.scrollTo(0, 5000);
+
+      setTimeout(function() {
+        is(window.pageYOffset, 5000, "Sanity check");
+
+        window.scrollTo(0, 0);
+        input.focus();
+        input.blur();
+
+        setTimeout(function() {
+          isnot(window.pageYOffset, 0, "This time we shouldn't be scrolled up");
+
+          SimpleTest.finish();
+        }, 0);
+      }, 0);
+    }, 0);
+  }, 0);
+});
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+
+</body>
+</html>