summaryrefslogtreecommitdiff
path: root/dom/html/HTMLObjectElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/HTMLObjectElement.cpp')
-rw-r--r--dom/html/HTMLObjectElement.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp
index a0d06a8c65..a77cd6fe57 100644
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -18,6 +18,11 @@
#include "nsNPAPIPluginInstance.h"
#include "nsIWidget.h"
#include "nsContentUtils.h"
+#ifdef XP_MACOSX
+#include "mozilla/EventDispatcher.h"
+#include "mozilla/dom/Event.h"
+#include "nsFocusManager.h"
+#endif
namespace mozilla {
namespace dom {
@@ -39,6 +44,9 @@ HTMLObjectElement::HTMLObjectElement(already_AddRefed<mozilla::dom::NodeInfo>& a
HTMLObjectElement::~HTMLObjectElement()
{
+#ifdef XP_MACOSX
+ OnFocusBlurPlugin(this, false);
+#endif
UnregisterActivityObserver();
DestroyImageLoadingContent();
}
@@ -109,6 +117,131 @@ NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
// nsIConstraintValidation
NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObjectElement)
+#ifdef XP_MACOSX
+
+static nsIWidget* GetWidget(Element* aElement)
+{
+ return nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
+}
+
+Element* HTMLObjectElement::sLastFocused = nullptr; // Weak
+
+class PluginFocusSetter : public Runnable
+{
+public:
+ PluginFocusSetter(nsIWidget* aWidget, Element* aElement)
+ : mWidget(aWidget), mElement(aElement)
+ {
+ }
+
+ NS_IMETHOD Run() override
+ {
+ 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)
+{
+ // In general we don't want to call nsIWidget::SetPluginFocused() for any
+ // Element that doesn't have a plugin running. But if SetPluginFocused(true)
+ // was just called for aElement while it had a plugin running, we want to
+ // make sure nsIWidget::SetPluginFocused(false) gets called for it now, even
+ // if aFocus is true.
+ if (aFocus) {
+ nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aElement);
+ bool hasRunningPlugin = false;
+ if (olc) {
+ // nsIObjectLoadingContent::GetHasRunningPlugin() fails when
+ // nsContentUtils::IsCallerChrome() returns false (which it can do even
+ // when we're processing a trusted focus event). We work around this by
+ // calling nsObjectLoadingContent::HasRunningPlugin() directly.
+ hasRunningPlugin =
+ static_cast<nsObjectLoadingContent*>(olc.get())->HasRunningPlugin();
+ }
+ if (!hasRunningPlugin) {
+ aFocus = false;
+ }
+ }
+
+ if (aFocus || aElement == sLastFocused) {
+ if (!aFocus) {
+ sLastFocused = nullptr;
+ }
+ nsIWidget* widget = GetWidget(aElement);
+ if (widget) {
+ nsContentUtils::AddScriptRunner(
+ new PluginFocusSetter(widget, aFocus ? aElement : nullptr));
+ }
+ }
+}
+
+void
+HTMLObjectElement::HandlePluginCrashed(Element* aElement)
+{
+ OnFocusBlurPlugin(aElement, false);
+}
+
+void
+HTMLObjectElement::HandlePluginInstantiated(Element* aElement)
+{
+ // If aElement is already focused when a plugin is instantiated, we need
+ // to initiate a call to nsIWidget::SetPluginFocused(true). Otherwise
+ // keyboard input won't work in a click-to-play plugin until aElement
+ // loses focus and regains it.
+ nsIContent* focusedContent = nullptr;
+ nsFocusManager *fm = nsFocusManager::GetFocusManager();
+ if (fm) {
+ focusedContent = fm->GetFocusedContent();
+ }
+ if (SameCOMIdentity(focusedContent, aElement)) {
+ OnFocusBlurPlugin(aElement, true);
+ }
+}
+
+void
+HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
+ WidgetEvent* aEvent)
+{
+ if (!aEvent->IsTrusted()) {
+ return;
+ }
+ switch (aEvent->mMessage) {
+ case eFocus: {
+ OnFocusBlurPlugin(aElement, true);
+ break;
+ }
+ case eBlur: {
+ OnFocusBlurPlugin(aElement, false);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+NS_IMETHODIMP
+HTMLObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
+{
+ HandleFocusBlurPlugin(this, aVisitor.mEvent);
+ return NS_OK;
+}
+
+#endif // #ifdef XP_MACOSX
+
NS_IMETHODIMP
HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
{
@@ -149,6 +282,14 @@ 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 eBlur 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);
}