Backed out 4 changesets (bug 712130) for Android autofocus failures and for failing browser_formdata.js. on a CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Fri, 12 Jan 2018 22:46:22 +0200
changeset 719874 96acd76fdf71cfa850a55bc5b6340267f5830234
parent 719873 1572cddc9e46271f000627a6f0e259885bf069bc
child 719875 4a784880cad7f22108a56b141d22a0f80384511f
child 720020 de312c964b3a6b6a864f4ea987a61b820dae7ac1
push id95377
push userbmo:ttromey@mozilla.com
push dateFri, 12 Jan 2018 20:59:03 +0000
bugs712130
milestone59.0a1
backs oute7738f07edae521d7459d2ac759416005a4899cd
3774e90777a793f70cfb492b5a7726c9de098d16
a3cffbfc83950a3453bce4d446f677c6e0c2fbba
ba6c2fff9fd54ca8f836ce3e2f29aaa8a8d65bd2
Backed out 4 changesets (bug 712130) for Android autofocus failures and for failing browser_formdata.js. on a CLOSED TREE Backed out changeset e7738f07edae (bug 712130) Backed out changeset 3774e90777a7 (bug 712130) Backed out changeset a3cffbfc8395 (bug 712130) Backed out changeset ba6c2fff9fd5 (bug 712130)
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsFocusManager.cpp
dom/base/nsIDocument.h
dom/html/nsGenericHTMLElement.cpp
layout/base/PresShell.cpp
layout/reftests/bugs/712130-1-ref.html
layout/reftests/bugs/712130-1.html
layout/reftests/bugs/712130-2-ref.html
layout/reftests/bugs/712130-2.html
layout/reftests/bugs/reftest.list
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1573,17 +1573,16 @@ nsDocument::nsDocument(const char* aCont
   , mNeedsReleaseAfterStackRefCntRelease(false)
   , mMaybeServiceWorkerControlled(false)
 #ifdef DEBUG
   , mWillReparent(false)
 #endif
   , mDOMLoadingSet(false)
   , mDOMInteractiveSet(false)
   , mDOMCompleteSet(false)
-  , mAutoFocusFired(false)
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
 
@@ -9959,115 +9958,16 @@ nsDocument::GetTemplateContentsOwner()
     // |doc| is the template contents owner of template elements created
     // by |doc|.
     doc->mTemplateContentsOwner = doc;
   }
 
   return mTemplateContentsOwner;
 }
 
-
-/**
- * nsAutoFocusEvent is used to dispatch a focus event for an
- * nsGenericHTMLFormElement with the autofocus attribute enabled.
- */
-class nsAutoFocusEvent : public Runnable
-{
-public:
-  explicit nsAutoFocusEvent(already_AddRefed<Element>&& aElement,
-                            already_AddRefed<nsPIDOMWindowOuter>&& aRootWindow)
-    : mozilla::Runnable("nsAutoFocusEvent")
-    , mElement(aElement)
-    , mRootWindow(aRootWindow)
-  {
-  }
-
-  NS_IMETHOD Run() override
-  {
-    // Don't steal focus from the user.
-    if (mRootWindow->GetFocusedNode()) {
-      return NS_OK;
-    }
-
-    mozilla::ErrorResult rv;
-    mElement->Focus(rv);
-    return rv.StealNSResult();
-  }
-private:
-  nsCOMPtr<Element> mElement;
-  nsCOMPtr<nsPIDOMWindowOuter> mRootWindow;
-};
-
-void
-nsDocument::SetAutoFocusElement(Element* aAutoFocusElement)
-{
-  if (mAutoFocusFired) {
-    // Too late.
-    return;
-  }
-
-  if (mAutoFocusElement) {
-    // The spec disallows multiple autofocus elements, so we consider only the
-    // first one to preserve the old behavior.
-    return;
-  }
-
-  mAutoFocusElement = do_GetWeakReference(aAutoFocusElement);
-  TriggerAutoFocus();
-}
-
-static nsCOMPtr<nsPIDOMWindowOuter>
-GetRootWindow(nsIDocument* aDoc)
-{
-  nsIDocShell* docShell = aDoc->GetDocShell();
-  if (!docShell) {
-    return nullptr;
-  }
-  nsCOMPtr<nsIDocShellTreeItem> rootItem;
-  docShell->GetRootTreeItem(getter_AddRefs(rootItem));
-  return rootItem ? rootItem->GetWindow() : nullptr;
-}
-
-void
-nsDocument::TriggerAutoFocus()
-{
-  if (mAutoFocusFired) {
-    return;
-  }
-
-  if (!mPresShell || !mPresShell->DidInitialize()) {
-    // Delay autofocus until frames are constructed so that we don't thrash
-    // style and layout calculations.
-    return;
-  }
-
-  nsCOMPtr<Element> autoFocusElement = do_QueryReferent(mAutoFocusElement);
-  if (autoFocusElement) {
-    mAutoFocusFired = true;
-
-    nsCOMPtr<nsPIDOMWindowOuter> rootWindow = GetRootWindow(this);
-    if (!rootWindow) {
-      return;
-    }
-
-    // NOTE: This may be removed in the future since the spec technically
-    // allows autofocus after load.
-    nsCOMPtr<nsIDocument> rootDoc = rootWindow->GetExtantDoc();
-    if (rootDoc &&
-        rootDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
-      return;
-    }
-
-    nsCOMPtr<nsIRunnable> event =
-      new nsAutoFocusEvent(autoFocusElement.forget(), rootWindow.forget());
-    nsresult rv = NS_DispatchToCurrentThread(event.forget());
-    NS_ENSURE_SUCCESS_VOID(rv);
-  }
-}
-
 void
 nsDocument::SetScrollToRef(nsIURI *aDocumentURI)
 {
   if (!aDocumentURI) {
     return;
   }
 
   nsAutoCString ref;
@@ -11850,16 +11750,28 @@ public:
 private:
   PendingFullscreenRequestList() = delete;
 
   static LinkedList<FullscreenRequest> sList;
 };
 
 /* static */ LinkedList<FullscreenRequest> PendingFullscreenRequestList::sList;
 
+static nsCOMPtr<nsPIDOMWindowOuter>
+GetRootWindow(nsIDocument* aDoc)
+{
+  nsIDocShell* docShell = aDoc->GetDocShell();
+  if (!docShell) {
+    return nullptr;
+  }
+  nsCOMPtr<nsIDocShellTreeItem> rootItem;
+  docShell->GetRootTreeItem(getter_AddRefs(rootItem));
+  return rootItem ? rootItem->GetWindow() : nullptr;
+}
+
 static bool
 ShouldApplyFullscreenDirectly(nsIDocument* aDoc,
                               nsPIDOMWindowOuter* aRootWin)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // If we are in the content process, we can apply the fullscreen
     // state directly only if we have been in DOM fullscreen, because
     // otherwise we always need to notify the chrome.
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -808,19 +808,16 @@ public:
   virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
                                        RefPtr<mozilla::StyleSheet>* aSheet) override;
 
   virtual nsISupports* GetCurrentContentSink() override;
 
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
-  virtual void SetAutoFocusElement(Element* aAutoFocusElement) override;
-  virtual void TriggerAutoFocus() override;
-
   virtual void SetScrollToRef(nsIURI *aDocumentURI) override;
   virtual void ScrollToRef() override;
   virtual void ResetScrolledToRefAlready() override;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) override;
 
   virtual Element* LookupImageElement(const nsAString& aElementId) override;
   virtual void MozSetImageElement(const nsAString& aImageElementId,
                                   Element* aElement) override;
@@ -1316,18 +1313,16 @@ private:
 
   // Set if we've found a URL for the current picture
   nsString mPreloadPictureFoundSource;
 
   RefPtr<mozilla::dom::DOMImplementation> mDOMImplementation;
 
   RefPtr<nsContentList> mImageMaps;
 
-  nsWeakPtr mAutoFocusElement;
-
   nsCString mScrollToRef;
   uint8_t mScrolledToRefAlready : 1;
   uint8_t mChangeScrollPosWhenScrollingToRef : 1;
 
   // Tracking for plugins in the document.
   nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins;
 
   RefPtr<mozilla::dom::DocumentTimeline> mDocumentTimeline;
@@ -1368,17 +1363,16 @@ public:
   bool mWillReparent;
 #endif
 
 private:
   void RecordNavigationTiming(ReadyState aReadyState);
   bool mDOMLoadingSet : 1;
   bool mDOMInteractiveSet : 1;
   bool mDOMCompleteSet : 1;
-  bool mAutoFocusFired : 1;
 };
 
 class nsDocumentOnStack
 {
 public:
   explicit nsDocumentOnStack(nsDocument* aDoc) : mDoc(aDoc)
   {
     mDoc->IncreaseStackRefCnt();
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1594,17 +1594,17 @@ nsFocusManager::CheckIfFocusable(nsICont
   nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
   // can't focus elements that are not in documents
   if (!doc) {
     LOGCONTENT("Cannot focus %s because content not in document", aContent)
     return nullptr;
   }
 
   // Make sure that our frames are up to date while ensuring the presshell is
-  // also initialized in case we come from a script calling focus() early.
+  // also initialized in case we come from an autofocus event.
   mEventHandlingNeedsFlush = false;
   doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
 
   nsIPresShell *shell = doc->GetShell();
   if (!shell)
     return nullptr;
 
   // the root content can always be focused,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2601,19 +2601,16 @@ public:
    */
   mozilla::EventStates GetDocumentState() const
   {
     return mDocumentState;
   }
 
   virtual nsISupports* GetCurrentContentSink() = 0;
 
-  virtual void SetAutoFocusElement(Element* aAutoFocusElement) = 0;
-  virtual void TriggerAutoFocus() = 0;
-
   virtual void SetScrollToRef(nsIURI *aDocumentURI) = 0;
   virtual void ScrollToRef() = 0;
   virtual void ResetScrolledToRefAlready() = 0;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) = 0;
 
   using mozilla::dom::DocumentOrShadowRoot::GetElementById;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -107,16 +107,74 @@
 #include "mozilla/StyleSetHandleInlines.h"
 #include "ReferrerPolicy.h"
 #include "mozilla/dom/HTMLLabelElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+/**
+ * nsAutoFocusEvent is used to dispatch a focus event when a
+ * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute
+ * enabled.
+ */
+class nsAutoFocusEvent : public Runnable
+{
+public:
+  explicit nsAutoFocusEvent(nsGenericHTMLFormElement* aElement)
+    : mozilla::Runnable("nsAutoFocusEvent")
+    , mElement(aElement)
+  {
+  }
+
+  NS_IMETHOD Run() override {
+    nsFocusManager* fm = nsFocusManager::GetFocusManager();
+    if (!fm) {
+      return NS_ERROR_NULL_POINTER;
+    }
+
+    nsIDocument* document = mElement->OwnerDoc();
+
+    nsPIDOMWindowOuter* window = document->GetWindow();
+    if (!window) {
+      return NS_OK;
+    }
+
+    // Trying to found the top window (equivalent to window.top).
+    if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetTop()) {
+      window = top;
+    }
+
+    if (window->GetFocusedNode()) {
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIDocument> topDoc = window->GetExtantDoc();
+    if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
+      return NS_OK;
+    }
+
+    // If something is focused in the same document, ignore autofocus.
+    if (!fm->GetFocusedContent() ||
+        fm->GetFocusedContent()->OwnerDoc() != document) {
+      mozilla::ErrorResult rv;
+      mElement->Focus(rv);
+      return rv.StealNSResult();
+    }
+
+    return NS_OK;
+  }
+private:
+  // NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement
+  // because AddRef/Release are ambiguous with nsGenericHTMLFormElement
+  // and Focus() is declared (and defined) in nsGenericHTMLElement class.
+  RefPtr<nsGenericHTMLElement> mElement;
+};
+
 NS_IMPL_ADDREF_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
 NS_IMPL_RELEASE_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)
@@ -1823,18 +1881,20 @@ nsGenericHTMLFormElement::BindToTree(nsI
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // An autofocus event has to be launched if the autofocus attribute is
   // specified and the element accept the autofocus attribute. In addition,
   // the document should not be already loaded and the "browser.autofocus"
   // preference should be 'true'.
   if (IsAutofocusable() && HasAttr(kNameSpaceID_None, nsGkAtoms::autofocus) &&
-      nsContentUtils::AutoFocusEnabled() && aDocument) {
-    aDocument->SetAutoFocusElement(this);
+      nsContentUtils::AutoFocusEnabled()) {
+    nsCOMPtr<nsIRunnable> event = new nsAutoFocusEvent(this);
+    rv = NS_DispatchToCurrentThread(event);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // If @form is set, the element *has* to be in a document, otherwise it
   // wouldn't be possible to find an element with the corresponding id.
   // If @form isn't set, the element *has* to have a parent, otherwise it
   // wouldn't be possible to find a form ancestor.
   // We should not call UpdateFormOwner if none of these conditions are
   // fulfilled.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -1831,18 +1831,16 @@ PresShell::Initialize(nscoord aWidth, ns
     NS_ENSURE_STATE(!mHaveShutDown);
 
     // Run the XBL binding constructors for any new frames we've constructed.
     // (Do this in a script runner, since our caller might have a script
     // blocker on the stack.)
     nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
   }
 
-  mDocument->TriggerAutoFocus();
-
   NS_ASSERTION(rootFrame, "How did that happen?");
 
   // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
   // set, but XBL processing could have caused a reflow which clears it.
   if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
     // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
     rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
                                NS_FRAME_HAS_DIRTY_CHILDREN);
deleted file mode 100644
--- a/layout/reftests/bugs/712130-1-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
-<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
-<input type="text">
deleted file mode 100644
--- a/layout/reftests/bugs/712130-1.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
-<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
-<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
deleted file mode 100644
--- a/layout/reftests/bugs/712130-2-ref.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
deleted file mode 100644
--- a/layout/reftests/bugs/712130-2.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<!DOCTYPE html>
-<html class="reftest-wait">
-<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
-<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1702,18 +1702,16 @@ skip-if(azureSkiaGL) == 670442-1.html 67
 != 691087-1.html 691087-1-ref.html
 == 691571-1.html 691571-1-ref.html
 fuzzy-if(skiaContent,1,200) == 696307-1.html 696307-1-ref.html
 fuzzy-if(skiaContent,1,550) == 696739-1.html 696739-1-ref.html
 needs-focus == 703186-1.html 703186-1-ref.html
 needs-focus == 703186-2.html 703186-2-ref.html
 needs-focus != 703186-1.html 703186-2.html
 == 711359-1.html 711359-1-ref.html
-needs-focus == 712130-1.html 712130-1-ref.html
-needs-focus == 712130-2.html 712130-2-ref.html
 == 712849-1.html 712849-1-ref.html
 == 713856-static.html  713856-ref.html
 == 713856-dynamic.html 713856-ref.html
 == 714519-1-as.html 714519-1-ref.html
 == 714519-1-q.html 714519-1-ref.html
 == 714519-2-as.html 714519-2-ref.html
 == 714519-2-q.html 714519-2-ref.html
 fuzzy-if(true,1,21) fuzzy-if(d2d,71,173) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html # bug 773482