Bug 1137229 - Keyboard input can stop working in a window. r=smaug
authorSteven Michaud <smichaud@pobox.com>
Tue, 24 Mar 2015 17:02:52 -0500
changeset 264301 3beddf2d2c8d4de0d7ec6d481f921c95b1cfdf31
parent 264300 998f44ed19fb7228c6460d5910422843b8f4b04c
child 264302 ee75ca0466a6ed61dc08c9c01ee9998337b2de96
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1137229
milestone39.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 1137229 - Keyboard input can stop working in a window. r=smaug
dom/html/HTMLObjectElement.cpp
dom/html/HTMLObjectElement.h
dom/html/HTMLSharedObjectElement.cpp
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -40,16 +40,19 @@ HTMLObjectElement::HTMLObjectElement(alr
   SetBarredFromConstraintValidation(true);
 
   // By default we're in the loading state
   AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
 HTMLObjectElement::~HTMLObjectElement()
 {
+#ifdef XP_MACOSX
+  OnFocusBlurPlugin(this, false);
+#endif
   UnregisterActivityObserver();
   DestroyImageLoadingContent();
 }
 
 bool
 HTMLObjectElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::usemap) ||
@@ -108,30 +111,60 @@ NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
 
 // nsIConstraintValidation
 NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObjectElement)
 
 #ifdef XP_MACOSX
 
 static nsIWidget* GetWidget(Element* aElement)
 {
-  nsIWidget* retval = NULL;
-  nsIFrame* frame = aElement->GetPrimaryFrame();
-  if (frame) {
-    retval = frame->GetNearestWidget();
-  }
-  return retval;
+  return nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
 }
 
-static void OnFocusBlurPlugin(Element* aElement, bool aFocus)
+Element* HTMLObjectElement::sLastFocused = nullptr; // Weak
+
+class PluginFocusSetter : public nsRunnable
 {
-  nsIWidget* widget = GetWidget(aElement);
-  if (widget) {
-    bool value = aFocus;
-    widget->SetPluginFocused(value);
+public:
+  PluginFocusSetter(nsIWidget* aWidget, Element* aElement)
+  : mWidget(aWidget), mElement(aElement)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (mElement) {
+      HTMLObjectElement::sLastFocused = mElement;
+      bool value = true;
+      mWidget->SetPluginFocused(value);
+    } else if (!HTMLObjectElement::sLastFocused) {
+      bool value = false;
+      mWidget->SetPluginFocused(value);
+    }
+
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIWidget> mWidget;
+  nsCOMPtr<Element> mElement;
+};
+
+void
+HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus)
+{
+  if (aFocus || aElement == sLastFocused) {
+    if (!aFocus) {
+      sLastFocused = nullptr;
+    }
+    nsIWidget* widget = GetWidget(aElement);
+    if (widget) {
+      nsContentUtils::AddScriptRunner(
+        new PluginFocusSetter(widget, aFocus ? aElement : nullptr));
+    }
   }
 }
 
 void
 HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
                                          WidgetEvent* aEvent)
 {
   if (!aEvent->mFlags.mIsTrusted) {
@@ -205,16 +238,24 @@ HTMLObjectElement::BindToTree(nsIDocumen
 
   return NS_OK;
 }
 
 void
 HTMLObjectElement::UnbindFromTree(bool aDeep,
                                   bool aNullParent)
 {
+#ifdef XP_MACOSX
+  // When a page is reloaded (when an nsIDocument's content is removed), the
+  // focused element isn't necessarily sent an NS_BLUR_CONTENT event. See
+  // nsFocusManager::ContentRemoved(). This means that a widget may think it
+  // still contains a focused plugin when it doesn't -- which in turn can
+  // disable text input in the browser window. See bug 1137229.
+  OnFocusBlurPlugin(this, false);
+#endif
   nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 
 
 nsresult
 HTMLObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -28,17 +28,21 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual int32_t TabIndexDefault() override;
 
 #ifdef XP_MACOSX
   // nsIDOMEventTarget
   NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) override;
+  // Helper methods
+  static void OnFocusBlurPlugin(Element* aElement, bool aFocus);
   static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
+  // Weak pointer. Null if last action was blur.
+  static Element* sLastFocused;
 #endif
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
 
   // nsIDOMHTMLObjectElement
   NS_DECL_NSIDOMHTMLOBJECTELEMENT
 
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -57,16 +57,19 @@ HTMLSharedObjectElement::SetItemValueTex
     nsGenericHTMLElement::SetItemValueText(aValue);
   } else {
     SetSrc(aValue);
   }
 }
 
 HTMLSharedObjectElement::~HTMLSharedObjectElement()
 {
+#ifdef XP_MACOSX
+  HTMLObjectElement::OnFocusBlurPlugin(this, false);
+#endif
   UnregisterActivityObserver();
   DestroyImageLoadingContent();
 }
 
 bool
 HTMLSharedObjectElement::IsDoneAddingChildren()
 {
   return mIsDoneAddingChildren;
@@ -154,16 +157,24 @@ HTMLSharedObjectElement::BindToTree(nsID
 
   return NS_OK;
 }
 
 void
 HTMLSharedObjectElement::UnbindFromTree(bool aDeep,
                                         bool aNullParent)
 {
+#ifdef XP_MACOSX
+  // When a page is reloaded (when an nsIDocument's content is removed), the
+  // focused element isn't necessarily sent an NS_BLUR_CONTENT event. See
+  // nsFocusManager::ContentRemoved(). This means that a widget may think it
+  // still contains a focused plugin when it doesn't -- which in turn can
+  // disable text input in the browser window. See bug 1137229.
+  HTMLObjectElement::OnFocusBlurPlugin(this, false);
+#endif
   nsObjectLoadingContent::UnbindFromTree(aDeep, aNullParent);
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 
 nsresult
 HTMLSharedObjectElement::SetAttr(int32_t aNameSpaceID, nsIAtom *aName,
                                  nsIAtom *aPrefix, const nsAString &aValue,