diff options
Diffstat (limited to 'dom/html/HTMLObjectElement.cpp')
-rw-r--r-- | dom/html/HTMLObjectElement.cpp | 141 |
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); } |