Bug 573689 key events lost while page is loading r=smaug, sr=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 03 Jul 2010 15:27:09 +0900
changeset 47198 443b653e6b2e5b417e160ad57956149e20d32564
parent 47197 2e0a75bcb159bc6b381b064248a3c7e522eb1bb8
child 47199 d048a5c7195faeebb3f4ceef2e9566ed23ba3b23
push idunknown
push userunknown
push dateunknown
reviewerssmaug, roc
bugs573689
milestone2.0b2pre
Bug 573689 key events lost while page is loading r=smaug, sr=roc
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -92,16 +92,17 @@ class nsISelection;
 template<class E> class nsCOMArray;
 class nsWeakFrame;
 class nsIScrollableFrame;
 class gfxASurface;
 class gfxContext;
 class nsIDOMEvent;
 class nsDisplayList;
 class nsDisplayListBuilder;
+class nsPIDOMWindow;
 
 typedef short SelectionType;
 typedef PRUint64 nsFrameState;
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
@@ -124,18 +125,18 @@ typedef struct CapturingContentInfo {
   nsIContent* mContent;
 
   CapturingContentInfo() :
     mAllowed(PR_FALSE), mRetargetToElement(PR_FALSE), mPreventDrag(PR_FALSE),
     mContent(nsnull) { }
 } CapturingContentInfo;
 
 #define NS_IPRESSHELL_IID     \
-  { 0x7ae0e29f, 0x4d2e, 0x4acd, \
-    { 0xb5, 0x74, 0xb6, 0x40, 0x8a, 0xca, 0xb8, 0x4d } }
+  { 0x6b32e1ca, 0xb295, 0x406d, \
+    { 0xb2, 0x8b, 0x73, 0xda, 0xc3, 0x66, 0xc2, 0xa7 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -998,16 +999,21 @@ public:
   /**
    * Keep track of how many times this presshell has been rendered to
    * a window.
    */
   PRUint64 GetPaintCount() { return mPaintCount; }
   void IncrementPaintCount() { ++mPaintCount; }
 
   /**
+   * Get the root DOM window of this presShell.
+   */
+  virtual already_AddRefed<nsPIDOMWindow> GetRootWindow() = 0;
+
+  /**
    * Refresh observer management.
    */
 protected:
   virtual PRBool AddRefreshObserverExternal(nsARefreshObserver* aObserver,
                                             mozFlushType aFlushType);
   PRBool AddRefreshObserverInternal(nsARefreshObserver* aObserver,
                                     mozFlushType aFlushType);
   virtual PRBool RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -803,16 +803,18 @@ public:
                                                    nsIntRegion* aRegion,
                                                    nsIntPoint& aPoint,
                                                    nsIntRect* aScreenRect);
 
   virtual already_AddRefed<gfxASurface> RenderSelection(nsISelection* aSelection,
                                                         nsIntPoint& aPoint,
                                                         nsIntRect* aScreenRect);
 
+  virtual already_AddRefed<nsPIDOMWindow> GetRootWindow();
+
   //nsIViewObserver interface
 
   NS_IMETHOD Paint(nsIView* aDisplayRoot,
                    nsIView* aViewToPaint,
                    nsIWidget* aWidget,
                    const nsRegion& aDirtyRegion,
                    PRBool aPaintDefaultBackground);
   NS_IMETHOD ComputeRepaintRegionForCopy(nsIView*      aRootView,
@@ -1242,16 +1244,17 @@ protected:
 
   // false if a check should be done for key/ime events that should be
   // retargeted to the currently focused presshell
   static PRBool sDontRetargetEvents;
 
 private:
 
   PRBool InZombieDocument(nsIContent *aContent);
+  already_AddRefed<nsIPresShell> GetParentPresShell();
   nsresult RetargetEventToParent(nsGUIEvent* aEvent,
                                  nsEventStatus*  aEventStatus);
 
   //helper funcs for event handling
 protected:
   //protected because nsPresShellEventCB needs this.
   nsIFrame* GetCurrentEventFrame();
 private:
@@ -6008,47 +6011,70 @@ PRBool PresShell::InZombieDocument(nsICo
   // about to be replaced by a newly loading document.
   // Such documents cannot handle DOM events.
   // It might actually be in a node not attached to any document,
   // in which case there is not parent presshell to retarget it to.
   nsIDocument *doc = aContent->GetDocument();
   return !doc || !doc->GetWindow();
 }
 
-nsresult PresShell::RetargetEventToParent(nsGUIEvent*     aEvent,
-                                          nsEventStatus*  aEventStatus)
+already_AddRefed<nsPIDOMWindow>
+PresShell::GetRootWindow()
+{
+  nsCOMPtr<nsPIDOMWindow> window =
+    do_QueryInterface(mDocument->GetWindow());
+  if (window) {
+    nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
+    NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL");
+    return rootWindow.forget();
+  }
+
+  // If we don't have DOM window, we're zombie, we should find the root window
+  // with our parent shell.
+  nsCOMPtr<nsIPresShell> parent = GetParentPresShell();
+  NS_ENSURE_TRUE(parent, nsnull);
+  return parent->GetRootWindow();
+}
+
+already_AddRefed<nsIPresShell>
+PresShell::GetParentPresShell()
+{
+  NS_ENSURE_TRUE(mPresContext, nsnull);
+  nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
+  if (!container) {
+    container = do_QueryReferent(mForwardingContainer);
+  }
+
+  // Now, find the parent pres shell and send the event there
+  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
+  // Might have gone away, or never been around to start with
+  NS_ENSURE_TRUE(treeItem, nsnull);
+
+  nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
+  treeItem->GetParent(getter_AddRefs(parentTreeItem));
+  nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem);
+  NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nsnull);
+
+  nsIPresShell* parentPresShell = nsnull;
+  parentDocShell->GetPresShell(&parentPresShell);
+  return parentPresShell;
+}
+
+nsresult
+PresShell::RetargetEventToParent(nsGUIEvent*     aEvent,
+                                 nsEventStatus*  aEventStatus)
 {
   // Send this events straight up to the parent pres shell.
   // We do this for keystroke events in zombie documents or if either a frame
   // or a root content is not present.
   // That way at least the UI key bindings can work.
 
   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
-  nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
-  if (!container)
-    container = do_QueryReferent(mForwardingContainer);
-
-  // Now, find the parent pres shell and send the event there
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = 
-    do_QueryInterface(container);
-  if (!treeItem) {
-    // Might have gone away, or never been around to start with
-    return NS_ERROR_FAILURE;
-  }
-  
-  nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
-  treeItem->GetParent(getter_AddRefs(parentTreeItem));
-  nsCOMPtr<nsIDocShell> parentDocShell = 
-    do_QueryInterface(parentTreeItem);
-  if (!parentDocShell || treeItem == parentTreeItem) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIPresShell> parentPresShell;
-  parentDocShell->GetPresShell(getter_AddRefs(parentPresShell));
+  nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShell();
+  NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE);
   nsCOMPtr<nsIViewObserver> parentViewObserver = 
     do_QueryInterface(parentPresShell);
   if (!parentViewObserver) {
     return NS_ERROR_FAILURE;
   }
 
   // Fake the event as though it'ss from the parent pres shell's root view.
   nsIView *parentRootView;
@@ -6064,21 +6090,17 @@ void
 PresShell::DisableNonTestMouseEvents(PRBool aDisable)
 {
   sDisableNonTestMouseEvents = aDisable;
 }
 
 already_AddRefed<nsPIDOMWindow>
 PresShell::GetFocusedDOMWindowInOurWindow()
 {
-  nsCOMPtr<nsPIDOMWindow> window =
-    do_QueryInterface(mDocument->GetWindow());
-  NS_ENSURE_TRUE(window, nsnull);
-
-  nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
+  nsCOMPtr<nsPIDOMWindow> rootWindow = GetRootWindow();
   NS_ENSURE_TRUE(rootWindow, nsnull);
   nsPIDOMWindow* focusedWindow;
   nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
   return focusedWindow;
 }
 
 NS_IMETHODIMP
 PresShell::HandleEvent(nsIView         *aView,