Bug 1137229 - Keyboard input can stop working in a window. r=smaug
☠☠ backed out by ceac43ebc32f ☠ ☠
authorSteven Michaud <smichaud@pobox.com>
Tue, 24 Mar 2015 11:41:32 -0500
changeset 265693 cb2fce9d19c752b96d55d1c7c28d71748c2d50ca
parent 265692 40a24381b8fb0b858d7525d8eb8123a107b273e7
child 265694 ceac43ebc32f8070b5564f924c8630dd883a4aee
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [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<Element> mElement;
+  nsCOMPtr<nsIWidget> mWidget;
+};
+
+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,