michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // vim:set ts=2 sts=2 sw=2 et cin: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_X11 michael@0: #include michael@0: #include "gfxXlibSurface.h" michael@0: /* X headers suck */ michael@0: enum { XKeyPress = KeyPress }; michael@0: #include "mozilla/X11Util.h" michael@0: using mozilla::DefaultXDisplay; michael@0: #endif michael@0: michael@0: #include "nsPluginInstanceOwner.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsRect.h" michael@0: #include "nsSize.h" michael@0: #include "nsDisplayList.h" michael@0: #include "ImageLayers.h" michael@0: #include "SharedTextureImage.h" michael@0: #include "nsObjectFrame.h" michael@0: #include "nsIPluginDocument.h" michael@0: #include "nsIStringStream.h" michael@0: #include "nsNetUtil.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsILinkHandler.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: #include "nsIWebBrowserChrome.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsIPluginWidget.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsIDocShellTreeOwner.h" michael@0: #include "nsIDOMHTMLObjectElement.h" michael@0: #include "nsIAppShell.h" michael@0: #include "nsIDOMHTMLAppletElement.h" michael@0: #include "nsIObjectLoadingContent.h" michael@0: #include "nsAttrName.h" michael@0: #include "nsIFocusManager.h" michael@0: #include "nsFocusManager.h" michael@0: #include "nsIDOMDragEvent.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsIDocShell.h" michael@0: #include "ImageContainer.h" michael@0: #include "nsIDOMHTMLCollection.h" michael@0: #include "GLContext.h" michael@0: #include "GLSharedHandleHelpers.h" michael@0: #include "nsIContentInlines.h" michael@0: #include "mozilla/MiscEvents.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/TextEvents.h" michael@0: michael@0: #include "nsContentCID.h" michael@0: #include "nsWidgetsCID.h" michael@0: static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID); michael@0: static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include michael@0: #include "nsPluginUtilsOSX.h" michael@0: #endif michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: #include michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "ANPBase.h" michael@0: #include "AndroidBridge.h" michael@0: #include "nsWindow.h" michael@0: michael@0: static nsPluginInstanceOwner* sFullScreenInstance = nullptr; michael@0: michael@0: using namespace mozilla::dom; michael@0: michael@0: #include michael@0: #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::layers; michael@0: michael@0: // special class for handeling DOM context menu events because for michael@0: // some reason it starves other mouse events if implemented on the michael@0: // same class michael@0: class nsPluginDOMContextMenuListener : public nsIDOMEventListener michael@0: { michael@0: public: michael@0: nsPluginDOMContextMenuListener(nsIContent* aContent); michael@0: virtual ~nsPluginDOMContextMenuListener(); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOMEVENTLISTENER michael@0: michael@0: void Destroy(nsIContent* aContent); michael@0: michael@0: nsEventStatus ProcessEvent(const WidgetGUIEvent& anEvent) michael@0: { michael@0: return nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: }; michael@0: michael@0: class AsyncPaintWaitEvent : public nsRunnable michael@0: { michael@0: public: michael@0: AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) : michael@0: mContent(aContent), mFinished(aFinished) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent, michael@0: mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"), michael@0: true, true); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mContent; michael@0: bool mFinished; michael@0: }; michael@0: michael@0: void michael@0: nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder) michael@0: { michael@0: // This is notification for reftests about async plugin paint start michael@0: if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) { michael@0: nsCOMPtr event = new AsyncPaintWaitEvent(mContent, false); michael@0: // Run this event as soon as it's safe to do so, since listeners need to michael@0: // receive it immediately michael@0: mWaitingForPaint = nsContentUtils::AddScriptRunner(event); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsPluginInstanceOwner::GetImageContainer() michael@0: { michael@0: if (!mInstance) michael@0: return nullptr; michael@0: michael@0: nsRefPtr container; michael@0: michael@0: #if MOZ_WIDGET_ANDROID michael@0: // Right now we only draw with Gecko layers on Honeycomb and higher. See Paint() michael@0: // for what we do on other versions. michael@0: if (AndroidBridge::Bridge()->GetAPIVersion() < 11) michael@0: return nullptr; michael@0: michael@0: LayoutDeviceRect r = GetPluginRect(); michael@0: michael@0: // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render michael@0: // into, set y-flip flags, etc, so we do this at the beginning. michael@0: gfxSize resolution = mObjectFrame->PresContext()->PresShell()->GetCumulativeResolution(); michael@0: ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution.width, resolution.height)).Size(); michael@0: mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height)); michael@0: michael@0: container = LayerManager::CreateImageContainer(); michael@0: michael@0: nsRefPtr img = container->CreateImage(ImageFormat::SHARED_TEXTURE); michael@0: michael@0: SharedTextureImage::Data data; michael@0: data.mSize = gfx::IntSize(r.width, r.height); michael@0: data.mHandle = mInstance->CreateSharedHandle(); michael@0: data.mShareType = mozilla::gl::SharedTextureShareType::SameProcess; michael@0: data.mInverted = mInstance->Inverted(); michael@0: michael@0: SharedTextureImage* pluginImage = static_cast(img.get()); michael@0: pluginImage->SetData(data); michael@0: michael@0: container->SetCurrentImageInTransaction(img); michael@0: michael@0: return container.forget(); michael@0: #endif michael@0: michael@0: mInstance->GetImageContainer(getter_AddRefs(container)); michael@0: return container.forget(); michael@0: } michael@0: michael@0: void michael@0: nsPluginInstanceOwner::SetBackgroundUnknown() michael@0: { michael@0: if (mInstance) { michael@0: mInstance->SetBackgroundUnknown(); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect) michael@0: { michael@0: nsIntRect rect = aRect; michael@0: nsRefPtr ctx; michael@0: if (mInstance && michael@0: NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(ctx)))) { michael@0: return ctx.forget(); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsPluginInstanceOwner::EndUpdateBackground(gfxContext* aContext, michael@0: const nsIntRect& aRect) michael@0: { michael@0: nsIntRect rect = aRect; michael@0: if (mInstance) { michael@0: mInstance->EndUpdateBackground(aContext, &rect); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsPluginInstanceOwner::UseAsyncRendering() michael@0: { michael@0: #ifdef XP_MACOSX michael@0: if (mUseAsyncRendering) { michael@0: return true; michael@0: } michael@0: #endif michael@0: michael@0: bool isOOP; michael@0: bool result = (mInstance && michael@0: NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP michael@0: #ifndef XP_MACOSX michael@0: && (!mPluginWindow || michael@0: mPluginWindow->type == NPWindowTypeDrawable) michael@0: #endif michael@0: ); michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (result) { michael@0: mUseAsyncRendering = true; michael@0: } michael@0: #endif michael@0: michael@0: return result; michael@0: } michael@0: michael@0: nsIntSize michael@0: nsPluginInstanceOwner::GetCurrentImageSize() michael@0: { michael@0: nsIntSize size(0,0); michael@0: if (mInstance) { michael@0: mInstance->GetImageSize(&size); michael@0: } michael@0: return size; michael@0: } michael@0: michael@0: nsPluginInstanceOwner::nsPluginInstanceOwner() michael@0: { michael@0: // create nsPluginNativeWindow object, it is derived from NPWindow michael@0: // struct and allows to manipulate native window procedure michael@0: nsCOMPtr pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID); michael@0: mPluginHost = static_cast(pluginHostCOM.get()); michael@0: if (mPluginHost) michael@0: mPluginHost->NewPluginNativeWindow(&mPluginWindow); michael@0: else michael@0: mPluginWindow = nullptr; michael@0: michael@0: mObjectFrame = nullptr; michael@0: mContent = nullptr; michael@0: mWidgetCreationComplete = false; michael@0: #ifdef XP_MACOSX michael@0: memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext)); michael@0: mInCGPaintLevel = 0; michael@0: mSentInitialTopLevelWindowEvent = false; michael@0: mColorProfile = nullptr; michael@0: mPluginPortChanged = false; michael@0: #endif michael@0: mContentFocused = false; michael@0: mWidgetVisible = true; michael@0: mPluginWindowVisible = false; michael@0: mPluginDocumentActiveState = true; michael@0: mNumCachedAttrs = 0; michael@0: mNumCachedParams = 0; michael@0: mCachedAttrParamNames = nullptr; michael@0: mCachedAttrParamValues = nullptr; michael@0: mLastMouseDownButtonType = -1; michael@0: michael@0: #ifdef XP_MACOSX michael@0: #ifndef NP_NO_CARBON michael@0: // We don't support Carbon, but it is still the default model for i386 NPAPI. michael@0: mEventModel = NPEventModelCarbon; michael@0: #else michael@0: mEventModel = NPEventModelCocoa; michael@0: #endif michael@0: mUseAsyncRendering = false; michael@0: #endif michael@0: michael@0: mWaitingForPaint = false; michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: mFullScreen = false; michael@0: mJavaView = nullptr; michael@0: #endif michael@0: } michael@0: michael@0: nsPluginInstanceOwner::~nsPluginInstanceOwner() michael@0: { michael@0: int32_t cnt; michael@0: michael@0: if (mWaitingForPaint) { michael@0: // We don't care when the event is dispatched as long as it's "soon", michael@0: // since whoever needs it will be waiting for it. michael@0: nsCOMPtr event = new AsyncPaintWaitEvent(mContent, true); michael@0: NS_DispatchToMainThread(event); michael@0: } michael@0: michael@0: mObjectFrame = nullptr; michael@0: michael@0: for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) { michael@0: if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) { michael@0: NS_Free(mCachedAttrParamNames[cnt]); michael@0: mCachedAttrParamNames[cnt] = nullptr; michael@0: } michael@0: michael@0: if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) { michael@0: NS_Free(mCachedAttrParamValues[cnt]); michael@0: mCachedAttrParamValues[cnt] = nullptr; michael@0: } michael@0: } michael@0: michael@0: if (mCachedAttrParamNames) { michael@0: NS_Free(mCachedAttrParamNames); michael@0: mCachedAttrParamNames = nullptr; michael@0: } michael@0: michael@0: if (mCachedAttrParamValues) { michael@0: NS_Free(mCachedAttrParamValues); michael@0: mCachedAttrParamValues = nullptr; michael@0: } michael@0: michael@0: PLUG_DeletePluginNativeWindow(mPluginWindow); michael@0: mPluginWindow = nullptr; michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: RemovePluginView(); michael@0: #endif michael@0: michael@0: if (mInstance) { michael@0: mInstance->SetOwner(nullptr); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPluginInstanceOwner, michael@0: nsIPluginInstanceOwner, michael@0: nsIDOMEventListener, michael@0: nsIPrivacyTransitionObserver, michael@0: nsISupportsWeakReference) michael@0: michael@0: nsresult michael@0: nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance) michael@0: { michael@0: NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!"); michael@0: michael@0: // If we're going to null out mInstance after use, be sure to call michael@0: // mInstance->SetOwner(nullptr) here, since it now won't be called michael@0: // from our destructor. This fixes bug 613376. michael@0: if (mInstance && !aInstance) { michael@0: mInstance->SetOwner(nullptr); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: RemovePluginView(); michael@0: #endif michael@0: } michael@0: michael@0: mInstance = aInstance; michael@0: michael@0: nsCOMPtr doc; michael@0: GetDocument(getter_AddRefs(doc)); michael@0: if (doc) { michael@0: nsCOMPtr domWindow = doc->GetWindow(); michael@0: if (domWindow) { michael@0: nsCOMPtr docShell = domWindow->GetDocShell(); michael@0: if (docShell) michael@0: docShell->AddWeakPrivacyTransitionObserver(this); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow) michael@0: { michael@0: NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null"); michael@0: aWindow = mPluginWindow; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetMode(int32_t *aMode) michael@0: { michael@0: nsCOMPtr doc; michael@0: nsresult rv = GetDocument(getter_AddRefs(doc)); michael@0: nsCOMPtr pDoc (do_QueryInterface(doc)); michael@0: michael@0: if (pDoc) { michael@0: *aMode = NP_FULL; michael@0: } else { michael@0: *aMode = NP_EMBED; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(uint16_t& n, michael@0: const char*const*& names, michael@0: const char*const*& values) michael@0: { michael@0: nsresult rv = EnsureCachedAttrParamArrays(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: n = mNumCachedAttrs; michael@0: names = (const char **)mCachedAttrParamNames; michael@0: values = (const char **)mCachedAttrParamValues; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(name); michael@0: NS_ENSURE_ARG_POINTER(result); michael@0: michael@0: nsresult rv = EnsureCachedAttrParamArrays(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *result = nullptr; michael@0: michael@0: for (int i = 0; i < mNumCachedAttrs; i++) { michael@0: if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { michael@0: *result = mCachedAttrParamValues[i]; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result) michael@0: { michael@0: return CallQueryInterface(mContent, result); michael@0: } michael@0: michael@0: nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aInstance); michael@0: michael@0: *aInstance = mInstance; michael@0: NS_IF_ADDREF(*aInstance); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, michael@0: const char *aTarget, michael@0: nsIInputStream *aPostStream, michael@0: void *aHeadersData, michael@0: uint32_t aHeadersDataLen) michael@0: { michael@0: NS_ENSURE_TRUE(mContent, NS_ERROR_NULL_POINTER); michael@0: michael@0: if (mContent->IsEditable()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIDocument *doc = mContent->GetCurrentDoc(); michael@0: if (!doc) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsIPresShell *presShell = doc->GetShell(); michael@0: if (!presShell) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsPresContext *presContext = presShell->GetPresContext(); michael@0: if (!presContext) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // the container of the pres context will give us the link handler michael@0: nsCOMPtr container = presContext->GetContainerWeak(); michael@0: NS_ENSURE_TRUE(container,NS_ERROR_FAILURE); michael@0: nsCOMPtr lh = do_QueryInterface(container); michael@0: NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE); michael@0: michael@0: nsAutoString unitarget; michael@0: unitarget.AssignASCII(aTarget); // XXX could this be nonascii? michael@0: michael@0: nsCOMPtr baseURI = GetBaseURI(); michael@0: michael@0: // Create an absolute URL michael@0: nsCOMPtr uri; michael@0: nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr headersDataStream; michael@0: if (aPostStream && aHeadersData) { michael@0: if (!aHeadersDataLen) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: nsCOMPtr sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1"); michael@0: if (!sis) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = sis->SetData((char *)aHeadersData, aHeadersDataLen); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: headersDataStream = do_QueryInterface(sis); michael@0: } michael@0: michael@0: int32_t blockPopups = michael@0: Preferences::GetInt("privacy.popups.disable_from_plugins"); michael@0: nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups); michael@0: michael@0: rv = lh->OnLinkClick(mContent, uri, unitarget.get(), NullString(), michael@0: aPostStream, headersDataStream, true); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get()); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char16_t *aStatusMsg) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: if (!mObjectFrame) { michael@0: return rv; michael@0: } michael@0: nsCOMPtr docShellItem = mObjectFrame->PresContext()->GetDocShell(); michael@0: if (NS_FAILED(rv) || !docShellItem) { michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr treeOwner; michael@0: rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner)); michael@0: if (NS_FAILED(rv) || !treeOwner) { michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr browserChrome(do_GetInterface(treeOwner, &rv)); michael@0: if (NS_FAILED(rv) || !browserChrome) { michael@0: return rv; michael@0: } michael@0: rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT, michael@0: aStatusMsg); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument) michael@0: { michael@0: if (!aDocument) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: // XXX sXBL/XBL2 issue: current doc or owner doc? michael@0: // But keep in mind bug 322414 comment 33 michael@0: NS_IF_ADDREF(*aDocument = mContent->OwnerDoc()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect) michael@0: { michael@0: // If our object frame has gone away, we won't be able to determine michael@0: // up-to-date-ness, so just fire off the event. michael@0: if (mWaitingForPaint && (!mObjectFrame || IsUpToDate())) { michael@0: // We don't care when the event is dispatched as long as it's "soon", michael@0: // since whoever needs it will be waiting for it. michael@0: nsCOMPtr event = new AsyncPaintWaitEvent(mContent, true); michael@0: NS_DispatchToMainThread(event); michael@0: mWaitingForPaint = false; michael@0: } michael@0: michael@0: if (!mObjectFrame || !invalidRect || !mWidgetVisible) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) michael@0: // Each time an asynchronously-drawing plugin sends a new surface to display, michael@0: // the image in the ImageContainer is updated and InvalidateRect is called. michael@0: // There are different side effects for (sync) Android plugins. michael@0: nsRefPtr container; michael@0: mInstance->GetImageContainer(getter_AddRefs(container)); michael@0: #endif michael@0: michael@0: #ifndef XP_MACOSX michael@0: // Windowed plugins should not be calling NPN_InvalidateRect, but michael@0: // Silverlight does and expects it to "work" michael@0: if (mWidget) { michael@0: mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top, michael@0: invalidRect->right - invalidRect->left, michael@0: invalidRect->bottom - invalidRect->top)); michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: nsIntRect rect(invalidRect->left, michael@0: invalidRect->top, michael@0: invalidRect->right - invalidRect->left, michael@0: invalidRect->bottom - invalidRect->top); michael@0: // invalidRect is in "display pixels". In non-HiDPI modes "display pixels" michael@0: // are device pixels. But in HiDPI modes each display pixel corresponds michael@0: // to more than one device pixel. michael@0: double scaleFactor = 1.0; michael@0: GetContentsScaleFactor(&scaleFactor); michael@0: rect.ScaleRoundOut(scaleFactor); michael@0: mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginInstanceOwner::RedrawPlugin() michael@0: { michael@0: if (mObjectFrame) { michael@0: mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value) michael@0: { michael@0: if (!mObjectFrame) { michael@0: NS_WARNING("plugin owner has no owner in getting doc's window handle"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #if defined(XP_WIN) michael@0: void** pvalue = (void**)value; michael@0: nsViewManager* vm = mObjectFrame->PresContext()->GetPresShell()->GetViewManager(); michael@0: if (!vm) michael@0: return NS_ERROR_FAILURE; michael@0: #if defined(XP_WIN) michael@0: // This property is provided to allow a "windowless" plugin to determine the window it is drawing michael@0: // in, so it can translate mouse coordinates it receives directly from the operating system michael@0: // to coordinates relative to itself. michael@0: michael@0: // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin michael@0: // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc michael@0: michael@0: // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code michael@0: // determines the window handle of the mozilla window containing the "windowless" plugin. michael@0: michael@0: // Given that this HWND may not be that of the document's window, there is a slight risk michael@0: // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation michael@0: // does not suggest this HWND IS that of the document window, rather that of the window michael@0: // the plugin is drawn in, this seems like a safe fix. michael@0: michael@0: // we only attempt to get the nearest window if this really is a "windowless" plugin so as not michael@0: // to change any behaviour for the much more common windowed plugins, michael@0: // though why this method would even be being called for a windowed plugin escapes me. michael@0: if (mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) { michael@0: // it turns out that flash also uses this window for determining focus, and is currently michael@0: // unable to show a caret correctly if we return the enclosing window. Therefore for michael@0: // now we only return the enclosing window when there is an actual offset which michael@0: // would otherwise cause coordinates to be offset incorrectly. (i.e. michael@0: // if the enclosing window if offset from the document window) michael@0: // michael@0: // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw michael@0: // does not seem to be possible without a change to the flash plugin michael@0: michael@0: nsIWidget* win = mObjectFrame->GetNearestWidget(); michael@0: if (win) { michael@0: nsView *view = nsView::GetViewFor(win); michael@0: NS_ASSERTION(view, "No view for widget"); michael@0: nsPoint offset = view->GetOffsetTo(nullptr); michael@0: michael@0: if (offset.x || offset.y) { michael@0: // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window michael@0: // so that mouse co-ordinates are not messed up. michael@0: *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW); michael@0: if (*pvalue) michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: // simply return the topmost document window michael@0: nsCOMPtr widget; michael@0: vm->GetRootWidget(getter_AddRefs(widget)); michael@0: if (widget) { michael@0: *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW); michael@0: } else { michael@0: NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: #elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11) michael@0: // X11 window managers want the toplevel window for WM_TRANSIENT_FOR. michael@0: nsIWidget* win = mObjectFrame->GetNearestWidget(); michael@0: if (!win) michael@0: return NS_ERROR_FAILURE; michael@0: *static_cast(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW); michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: #endif michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: mEventModel = static_cast(eventModel); michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: #endif michael@0: } michael@0: michael@0: NPError nsPluginInstanceOwner::ShowNativeContextMenu(NPMenu* menu, void* event) michael@0: { michael@0: if (!menu || !event) michael@0: return NPERR_GENERIC_ERROR; michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (GetEventModel() != NPEventModelCocoa) michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: michael@0: return NS_NPAPI_ShowCocoaContextMenu(static_cast(menu), mWidget, michael@0: static_cast(event)); michael@0: #else michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: #endif michael@0: } michael@0: michael@0: NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, michael@0: double *destX, double *destY, NPCoordinateSpace destSpace) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: if (!mWidget) michael@0: return false; michael@0: michael@0: return NS_NPAPI_ConvertPointCocoa(mWidget->GetNativeData(NS_NATIVE_WIDGET), michael@0: sourceX, sourceY, sourceSpace, destX, destY, destSpace); michael@0: #else michael@0: // we should implement this for all platforms michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format, michael@0: void *initData, NPAsyncSurface *surface) michael@0: { michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: } michael@0: michael@0: NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *) michael@0: { michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(result); michael@0: michael@0: *result = nsPluginTagType_Unknown; michael@0: michael@0: nsIAtom *atom = mContent->Tag(); michael@0: michael@0: if (atom == nsGkAtoms::applet) michael@0: *result = nsPluginTagType_Applet; michael@0: else if (atom == nsGkAtoms::embed) michael@0: *result = nsPluginTagType_Embed; michael@0: else if (atom == nsGkAtoms::object) michael@0: *result = nsPluginTagType_Object; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(uint16_t& n, const char*const*& names, const char*const*& values) michael@0: { michael@0: nsresult rv = EnsureCachedAttrParamArrays(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: n = mNumCachedParams; michael@0: if (n) { michael@0: names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1); michael@0: values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1); michael@0: } else michael@0: names = values = nullptr; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(name); michael@0: NS_ENSURE_ARG_POINTER(result); michael@0: michael@0: nsresult rv = EnsureCachedAttrParamArrays(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *result = nullptr; michael@0: michael@0: for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) { michael@0: if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { michael@0: *result = mCachedAttrParamValues[i]; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: michael@0: // Cache the attributes and/or parameters of our tag into a single set michael@0: // of arrays to be compatible with Netscape 4.x. The attributes go first, michael@0: // followed by a PARAM/null and then any PARAM tags. Also, hold the michael@0: // cached array around for the duration of the life of the instance michael@0: // because Netscape 4.x did. See bug 111008. michael@0: nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() michael@0: { michael@0: if (mCachedAttrParamValues) michael@0: return NS_OK; michael@0: michael@0: NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) && michael@0: !mCachedAttrParamNames, michael@0: "re-cache of attrs/params not implemented! use the DOM " michael@0: "node directy instead"); michael@0: michael@0: // Convert to a 16-bit count. Subtract 3 in case we add an extra michael@0: // "src", "wmode", or "codebase" entry below. michael@0: uint32_t cattrs = mContent->GetAttrCount(); michael@0: if (cattrs < 0x0000FFFC) { michael@0: mNumCachedAttrs = static_cast(cattrs); michael@0: } else { michael@0: mNumCachedAttrs = 0xFFFC; michael@0: } michael@0: michael@0: // Check if we are java for special codebase handling michael@0: const char* mime = nullptr; michael@0: bool isJava = NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime && michael@0: nsPluginHost::IsJavaMIMEType(mime); michael@0: michael@0: // now, we need to find all the PARAM tags that are children of us michael@0: // however, be careful not to include any PARAMs that don't have us michael@0: // as a direct parent. For nested object (or applet) tags, be sure michael@0: // to only round up the param tags that coorespond with THIS michael@0: // instance. And also, weed out any bogus tags that may get in the michael@0: // way, see bug 39609. Then, with any param tag that meet our michael@0: // qualification, temporarly cache them in an nsCOMArray until michael@0: // we can figure out what size to make our fixed char* array. michael@0: nsCOMArray ourParams; michael@0: michael@0: // Get all dependent PARAM tags, even if they are not direct children. michael@0: nsCOMPtr mydomElement = do_QueryInterface(mContent); michael@0: NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE); michael@0: michael@0: // Making DOM method calls can cause our frame to go away. michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: michael@0: nsCOMPtr allParams; michael@0: NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml"); michael@0: mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"), michael@0: getter_AddRefs(allParams)); michael@0: if (allParams) { michael@0: uint32_t numAllParams; michael@0: allParams->GetLength(&numAllParams); michael@0: for (uint32_t i = 0; i < numAllParams; i++) { michael@0: nsCOMPtr pnode; michael@0: allParams->Item(i, getter_AddRefs(pnode)); michael@0: nsCOMPtr domelement = do_QueryInterface(pnode); michael@0: if (domelement) { michael@0: // Ignore params without a name attribute. michael@0: nsAutoString name; michael@0: domelement->GetAttribute(NS_LITERAL_STRING("name"), name); michael@0: if (!name.IsEmpty()) { michael@0: // Find the first object or applet parent. michael@0: nsCOMPtr parent; michael@0: nsCOMPtr domobject; michael@0: nsCOMPtr domapplet; michael@0: pnode->GetParentNode(getter_AddRefs(parent)); michael@0: while (!(domobject || domapplet) && parent) { michael@0: domobject = do_QueryInterface(parent); michael@0: domapplet = do_QueryInterface(parent); michael@0: nsCOMPtr temp; michael@0: parent->GetParentNode(getter_AddRefs(temp)); michael@0: parent = temp; michael@0: } michael@0: if (domapplet || domobject) { michael@0: if (domapplet) { michael@0: parent = do_QueryInterface(domapplet); michael@0: } michael@0: else { michael@0: parent = do_QueryInterface(domobject); michael@0: } michael@0: nsCOMPtr mydomNode = do_QueryInterface(mydomElement); michael@0: if (parent == mydomNode) { michael@0: ourParams.AppendObject(domelement); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Convert to a 16-bit count. michael@0: uint32_t cparams = ourParams.Count(); michael@0: if (cparams < 0x0000FFFF) { michael@0: mNumCachedParams = static_cast(cparams); michael@0: } else { michael@0: mNumCachedParams = 0xFFFF; michael@0: } michael@0: michael@0: uint16_t numRealAttrs = mNumCachedAttrs; michael@0: michael@0: // Some plugins were never written to understand the "data" attribute of the OBJECT tag. michael@0: // Real and WMP will not play unless they find a "src" attribute, see bug 152334. michael@0: // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly michael@0: // look for "data", lets instead copy the "data" attribute and add another entry michael@0: // to the bottom of the array if there isn't already a "src" specified. michael@0: nsAutoString data; michael@0: if (mContent->Tag() == nsGkAtoms::object && michael@0: !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src) && michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data) && michael@0: !data.IsEmpty()) { michael@0: mNumCachedAttrs++; michael@0: } michael@0: michael@0: // "plugins.force.wmode" forces us to send a specific "wmode" parameter, michael@0: // used by flash to select a rendering mode. Common values include michael@0: // "opaque", "transparent", "windowed", "direct" michael@0: nsCString wmodeType; michael@0: nsAdoptingCString wmodePref = Preferences::GetCString("plugins.force.wmode"); michael@0: if (!wmodePref.IsEmpty()) { michael@0: mNumCachedAttrs++; michael@0: wmodeType = wmodePref; michael@0: } michael@0: #if defined(XP_WIN) || defined(XP_LINUX) michael@0: // Bug 923745 - Until we support windowed mode plugins in content processes, michael@0: // force flash to use a windowless rendering mode. This hack should go away michael@0: // when bug 923746 lands. (OS X plugins always use some native widgets, so michael@0: // unfortunately this does not help there) michael@0: else if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: mNumCachedAttrs++; michael@0: wmodeType.AssignLiteral("transparent"); michael@0: } michael@0: #endif michael@0: michael@0: // (Bug 738396) java has quirks in its codebase parsing, pass the michael@0: // absolute codebase URI as content sees it. michael@0: bool addCodebase = false; michael@0: nsAutoCString codebaseStr; michael@0: if (isJava) { michael@0: nsCOMPtr objlc = do_QueryInterface(mContent); michael@0: NS_ENSURE_TRUE(objlc, NS_ERROR_UNEXPECTED); michael@0: nsCOMPtr codebaseURI; michael@0: nsresult rv = objlc->GetBaseURI(getter_AddRefs(codebaseURI)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: codebaseURI->GetSpec(codebaseStr); michael@0: if (!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase)) { michael@0: mNumCachedAttrs++; michael@0: addCodebase = true; michael@0: } michael@0: } michael@0: michael@0: mCachedAttrParamNames = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams)); michael@0: NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY); michael@0: mCachedAttrParamValues = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams)); michael@0: NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the michael@0: // attribute order. So we want to make sure we give the plugin the michael@0: // attributes in the order they came in in the source, to be compatible with michael@0: // other browsers. Now in HTML, the storage order is the reverse of the michael@0: // source order, while in XML and XHTML it's the same as the source order michael@0: // (see the AddAttributes functions in the HTML and XML content sinks). michael@0: int32_t start, end, increment; michael@0: if (mContent->IsHTML() && michael@0: mContent->IsInHTMLDocument()) { michael@0: // HTML. Walk attributes in reverse order. michael@0: start = numRealAttrs - 1; michael@0: end = -1; michael@0: increment = -1; michael@0: } else { michael@0: // XHTML or XML. Walk attributes in forward order. michael@0: start = 0; michael@0: end = numRealAttrs; michael@0: increment = 1; michael@0: } michael@0: michael@0: // Set to the next slot to fill in name and value cache arrays. michael@0: uint32_t nextAttrParamIndex = 0; michael@0: michael@0: // Whether or not we force the wmode below while traversing michael@0: // the name/value pairs. michael@0: bool wmodeSet = false; michael@0: michael@0: // Add attribute name/value pairs. michael@0: for (int32_t index = start; index != end; index += increment) { michael@0: const nsAttrName* attrName = mContent->GetAttrNameAt(index); michael@0: nsIAtom* atom = attrName->LocalName(); michael@0: nsAutoString value; michael@0: mContent->GetAttr(attrName->NamespaceID(), atom, value); michael@0: nsAutoString name; michael@0: atom->ToString(name); michael@0: michael@0: FixUpURLS(name, value); michael@0: michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); michael@0: if (!wmodeType.IsEmpty() && michael@0: 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "wmode")) { michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType)); michael@0: michael@0: if (!wmodeSet) { michael@0: // We allocated space to add a wmode attr, but we don't need it now. michael@0: mNumCachedAttrs--; michael@0: wmodeSet = true; michael@0: } michael@0: } else if (isJava && 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "codebase")) { michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr)); michael@0: } else { michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); michael@0: } michael@0: nextAttrParamIndex++; michael@0: } michael@0: michael@0: // Potentially add CODEBASE attribute michael@0: if (addCodebase) { michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("codebase")); michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr)); michael@0: nextAttrParamIndex++; michael@0: } michael@0: michael@0: // Potentially add WMODE attribute. michael@0: if (!wmodeType.IsEmpty() && !wmodeSet) { michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode")); michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType)); michael@0: nextAttrParamIndex++; michael@0: } michael@0: michael@0: // Potentially add SRC attribute. michael@0: if (!data.IsEmpty()) { michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC")); michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data); michael@0: nextAttrParamIndex++; michael@0: } michael@0: michael@0: // Add PARAM and null separator. michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM")); michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // Flash expects an empty string on android michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("")); michael@0: #else michael@0: mCachedAttrParamValues[nextAttrParamIndex] = nullptr; michael@0: #endif michael@0: nextAttrParamIndex++; michael@0: michael@0: // Add PARAM name/value pairs. michael@0: michael@0: // We may decrement mNumCachedParams below michael@0: uint16_t totalParams = mNumCachedParams; michael@0: for (uint16_t i = 0; i < totalParams; i++) { michael@0: nsIDOMElement* param = ourParams.ObjectAt(i); michael@0: if (!param) { michael@0: continue; michael@0: } michael@0: michael@0: nsAutoString name; michael@0: nsAutoString value; michael@0: param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above michael@0: param->GetAttribute(NS_LITERAL_STRING("value"), value); michael@0: michael@0: FixUpURLS(name, value); michael@0: michael@0: /* michael@0: * According to the HTML 4.01 spec, at michael@0: * http://www.w3.org/TR/html4/types.html#type-cdata michael@0: * ''User agents may ignore leading and trailing michael@0: * white space in CDATA attribute values (e.g., " michael@0: * myval " may be interpreted as "myval"). Authors michael@0: * should not declare attribute values with michael@0: * leading or trailing white space.'' michael@0: * However, do not trim consecutive spaces as in bug 122119 michael@0: */ michael@0: name.Trim(" \n\r\t\b", true, true, false); michael@0: value.Trim(" \n\r\t\b", true, true, false); michael@0: if (isJava && name.EqualsIgnoreCase("codebase")) { michael@0: // We inserted normalized codebase above, don't include other versions in michael@0: // params michael@0: mNumCachedParams--; michael@0: continue; michael@0: } michael@0: mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name); michael@0: mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value); michael@0: nextAttrParamIndex++; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef XP_MACOSX michael@0: michael@0: static void InitializeNPCocoaEvent(NPCocoaEvent* event) michael@0: { michael@0: memset(event, 0, sizeof(NPCocoaEvent)); michael@0: } michael@0: michael@0: NPDrawingModel nsPluginInstanceOwner::GetDrawingModel() michael@0: { michael@0: #ifndef NP_NO_QUICKDRAW michael@0: // We don't support the Quickdraw drawing model any more but it's still michael@0: // the default model for i386 per NPAPI. michael@0: NPDrawingModel drawingModel = NPDrawingModelQuickDraw; michael@0: #else michael@0: NPDrawingModel drawingModel = NPDrawingModelCoreGraphics; michael@0: #endif michael@0: michael@0: if (!mInstance) michael@0: return drawingModel; michael@0: michael@0: mInstance->GetDrawingModel((int32_t*)&drawingModel); michael@0: return drawingModel; michael@0: } michael@0: michael@0: bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation() michael@0: { michael@0: if (!mInstance) michael@0: return false; michael@0: michael@0: bool coreAnimation; michael@0: if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation))) michael@0: return false; michael@0: michael@0: return coreAnimation; michael@0: } michael@0: michael@0: nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor) michael@0: { michael@0: if (!mInstance) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor); michael@0: } michael@0: michael@0: NPEventModel nsPluginInstanceOwner::GetEventModel() michael@0: { michael@0: return mEventModel; michael@0: } michael@0: michael@0: #define DEFAULT_REFRESH_RATE 20 // 50 FPS michael@0: michael@0: nsCOMPtr *nsPluginInstanceOwner::sCATimer = nullptr; michael@0: nsTArray *nsPluginInstanceOwner::sCARefreshListeners = nullptr; michael@0: michael@0: void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) { michael@0: if (!sCARefreshListeners) { michael@0: return; michael@0: } michael@0: for (size_t i = 0; i < sCARefreshListeners->Length(); i++) { michael@0: nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i]; michael@0: NPWindow *window; michael@0: instanceOwner->GetWindow(window); michael@0: if (!window) { michael@0: continue; michael@0: } michael@0: NPRect r; michael@0: r.left = 0; michael@0: r.top = 0; michael@0: r.right = window->width; michael@0: r.bottom = window->height; michael@0: instanceOwner->InvalidateRect(&r); michael@0: } michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::AddToCARefreshTimer() { michael@0: if (!mInstance) { michael@0: return; michael@0: } michael@0: michael@0: // Flash invokes InvalidateRect for us. michael@0: const char* mime = nullptr; michael@0: if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) { michael@0: if (strcmp(mime, "application/x-shockwave-flash") == 0) { michael@0: return; michael@0: } michael@0: } michael@0: michael@0: if (!sCARefreshListeners) { michael@0: sCARefreshListeners = new nsTArray(); michael@0: if (!sCARefreshListeners) { michael@0: return; michael@0: } michael@0: } michael@0: michael@0: if (sCARefreshListeners->Contains(this)) { michael@0: return; michael@0: } michael@0: michael@0: sCARefreshListeners->AppendElement(this); michael@0: michael@0: if (!sCATimer) { michael@0: sCATimer = new nsCOMPtr(); michael@0: if (!sCATimer) { michael@0: return; michael@0: } michael@0: } michael@0: michael@0: if (sCARefreshListeners->Length() == 1) { michael@0: *sCATimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: (*sCATimer)->InitWithFuncCallback(CARefresh, nullptr, michael@0: DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK); michael@0: } michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::RemoveFromCARefreshTimer() { michael@0: if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) { michael@0: return; michael@0: } michael@0: michael@0: sCARefreshListeners->RemoveElement(this); michael@0: michael@0: if (sCARefreshListeners->Length() == 0) { michael@0: if (sCATimer) { michael@0: (*sCATimer)->Cancel(); michael@0: delete sCATimer; michael@0: sCATimer = nullptr; michael@0: } michael@0: delete sCARefreshListeners; michael@0: sCARefreshListeners = nullptr; michael@0: } michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext, michael@0: int aWidth, int aHeight) michael@0: { michael@0: if (aWidth == 0 || aHeight == 0) michael@0: return; michael@0: michael@0: if (!mCARenderer) { michael@0: mCARenderer = new nsCARenderer(); michael@0: } michael@0: michael@0: // aWidth and aHeight are in "display pixels". In non-HiDPI modes michael@0: // "display pixels" are device pixels. But in HiDPI modes each michael@0: // display pixel corresponds to more than one device pixel. michael@0: double scaleFactor = 1.0; michael@0: GetContentsScaleFactor(&scaleFactor); michael@0: michael@0: if (!mIOSurface || michael@0: (mIOSurface->GetWidth() != (size_t)aWidth || michael@0: mIOSurface->GetHeight() != (size_t)aHeight || michael@0: mIOSurface->GetContentsScaleFactor() != scaleFactor)) { michael@0: mIOSurface = nullptr; michael@0: michael@0: // If the renderer is backed by an IOSurface, resize it as required. michael@0: mIOSurface = MacIOSurface::CreateIOSurface(aWidth, aHeight, scaleFactor); michael@0: if (mIOSurface) { michael@0: RefPtr attachSurface = MacIOSurface::LookupSurface( michael@0: mIOSurface->GetIOSurfaceID(), michael@0: scaleFactor); michael@0: if (attachSurface) { michael@0: mCARenderer->AttachIOSurface(attachSurface); michael@0: } else { michael@0: NS_ERROR("IOSurface attachment failed"); michael@0: mIOSurface = nullptr; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!mColorProfile) { michael@0: mColorProfile = CreateSystemColorSpace(); michael@0: } michael@0: michael@0: if (mCARenderer->isInit() == false) { michael@0: void *caLayer = nullptr; michael@0: nsresult rv = mInstance->GetValueFromPlugin(NPPVpluginCoreAnimationLayer, &caLayer); michael@0: if (NS_FAILED(rv) || !caLayer) { michael@0: return; michael@0: } michael@0: michael@0: // We don't run Flash in-process so we can unconditionally disallow michael@0: // the offliner renderer. michael@0: mCARenderer->SetupRenderer(caLayer, aWidth, aHeight, scaleFactor, michael@0: DISALLOW_OFFLINE_RENDERER); michael@0: michael@0: // Setting up the CALayer requires resetting the painting otherwise we michael@0: // get garbage for the first few frames. michael@0: FixUpPluginWindow(ePluginPaintDisable); michael@0: FixUpPluginWindow(ePluginPaintEnable); michael@0: } michael@0: michael@0: CGImageRef caImage = nullptr; michael@0: nsresult rt = mCARenderer->Render(aWidth, aHeight, scaleFactor, &caImage); michael@0: if (rt == NS_OK && mIOSurface && mColorProfile) { michael@0: nsCARenderer::DrawSurfaceToCGContext(aCGContext, mIOSurface, mColorProfile, michael@0: 0, 0, aWidth, aHeight); michael@0: } else if (rt == NS_OK && caImage != nullptr) { michael@0: // Significant speed up by resetting the scaling michael@0: ::CGContextSetInterpolationQuality(aCGContext, kCGInterpolationNone ); michael@0: ::CGContextTranslateCTM(aCGContext, 0, (double) aHeight * scaleFactor); michael@0: ::CGContextScaleCTM(aCGContext, scaleFactor, -scaleFactor); michael@0: michael@0: ::CGContextDrawImage(aCGContext, CGRectMake(0,0,aWidth,aHeight), caImage); michael@0: } else { michael@0: NS_NOTREACHED("nsCARenderer::Render failure"); michael@0: } michael@0: } michael@0: michael@0: void* nsPluginInstanceOwner::GetPluginPortCopy() michael@0: { michael@0: if (GetDrawingModel() == NPDrawingModelCoreGraphics || michael@0: GetDrawingModel() == NPDrawingModelCoreAnimation || michael@0: GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation) michael@0: return &mCGPluginPortCopy; michael@0: return nullptr; michael@0: } michael@0: michael@0: // Currently (on OS X in Cocoa widgets) any changes made as a result of michael@0: // calling GetPluginPortFromWidget() are immediately reflected in the NPWindow michael@0: // structure that has been passed to the plugin via SetWindow(). This is michael@0: // because calls to nsChildView::GetNativeData(NS_NATIVE_PLUGIN_PORT_CG) michael@0: // always return a pointer to the same internal (private) object, but may michael@0: // make changes inside that object. All calls to GetPluginPortFromWidget() made while michael@0: // the plugin is active (i.e. excluding those made at our initialization) michael@0: // need to take this into account. The easiest way to do so is to replace michael@0: // them with calls to SetPluginPortAndDetectChange(). This method keeps track michael@0: // of when calls to GetPluginPortFromWidget() result in changes, and sets a flag to make michael@0: // sure SetWindow() gets called the next time through FixUpPluginWindow(), so michael@0: // that the plugin is notified of these changes. michael@0: void* nsPluginInstanceOwner::SetPluginPortAndDetectChange() michael@0: { michael@0: if (!mPluginWindow) michael@0: return nullptr; michael@0: void* pluginPort = GetPluginPortFromWidget(); michael@0: if (!pluginPort) michael@0: return nullptr; michael@0: mPluginWindow->window = pluginPort; michael@0: michael@0: return mPluginWindow->window; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::BeginCGPaint() michael@0: { michael@0: ++mInCGPaintLevel; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::EndCGPaint() michael@0: { michael@0: --mInCGPaintLevel; michael@0: NS_ASSERTION(mInCGPaintLevel >= 0, "Mismatched call to nsPluginInstanceOwner::EndCGPaint()!"); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: // static michael@0: uint32_t michael@0: nsPluginInstanceOwner::GetEventloopNestingLevel() michael@0: { michael@0: nsCOMPtr appShell = do_GetService(kAppShellCID); michael@0: uint32_t currentLevel = 0; michael@0: if (appShell) { michael@0: appShell->GetEventloopNestingLevel(¤tLevel); michael@0: #ifdef XP_MACOSX michael@0: // Cocoa widget code doesn't process UI events through the normal michael@0: // appshell event loop, so it needs an additional count here. michael@0: currentLevel++; michael@0: #endif michael@0: } michael@0: michael@0: // No idea how this happens... but Linux doesn't consistently michael@0: // process UI events through the appshell event loop. If we get a 0 michael@0: // here on any platform we increment the level just in case so that michael@0: // we make sure we always tear the plugin down eventually. michael@0: if (!currentLevel) { michael@0: currentLevel++; michael@0: } michael@0: michael@0: return currentLevel; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: michael@0: // Modified version of nsFrame::GetOffsetToCrossDoc that stops when it michael@0: // hits an element with a displayport (or runs out of frames). This is michael@0: // not really the right thing to do, but it's better than what was here before. michael@0: static nsPoint michael@0: GetOffsetRootContent(nsIFrame* aFrame) michael@0: { michael@0: // offset will hold the final offset michael@0: // docOffset holds the currently accumulated offset at the current APD, it michael@0: // will be converted and added to offset when the current APD changes. michael@0: nsPoint offset(0, 0), docOffset(0, 0); michael@0: const nsIFrame* f = aFrame; michael@0: int32_t currAPD = aFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: int32_t apd = currAPD; michael@0: nsRect displayPort; michael@0: while (f) { michael@0: if (f->GetContent() && nsLayoutUtils::GetDisplayPort(f->GetContent(), &displayPort)) michael@0: break; michael@0: michael@0: docOffset += f->GetPosition(); michael@0: nsIFrame* parent = f->GetParent(); michael@0: if (parent) { michael@0: f = parent; michael@0: } else { michael@0: nsPoint newOffset(0, 0); michael@0: f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset); michael@0: int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0; michael@0: if (!f || newAPD != currAPD) { michael@0: // Convert docOffset to the right APD and add it to offset. michael@0: offset += docOffset.ConvertAppUnits(currAPD, apd); michael@0: docOffset.x = docOffset.y = 0; michael@0: } michael@0: currAPD = newAPD; michael@0: docOffset += newOffset; michael@0: } michael@0: } michael@0: michael@0: offset += docOffset.ConvertAppUnits(currAPD, apd); michael@0: michael@0: return offset; michael@0: } michael@0: michael@0: LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect() michael@0: { michael@0: // Get the offset of the content relative to the page michael@0: nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame); michael@0: LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mObjectFrame->PresContext()->AppUnitsPerDevPixel()); michael@0: return LayoutDeviceRect(rect); michael@0: } michael@0: michael@0: bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */) michael@0: { michael@0: if (!mJavaView) { michael@0: mJavaView = mInstance->GetJavaSurface(); michael@0: michael@0: if (!mJavaView) michael@0: return false; michael@0: michael@0: mJavaView = (void*)AndroidBridge::GetJNIEnv()->NewGlobalRef((jobject)mJavaView); michael@0: } michael@0: michael@0: if (AndroidBridge::Bridge()) michael@0: AndroidBridge::Bridge()->AddPluginView((jobject)mJavaView, aRect, mFullScreen); michael@0: michael@0: if (mFullScreen) michael@0: sFullScreenInstance = this; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::RemovePluginView() michael@0: { michael@0: if (!mInstance || !mJavaView) michael@0: return; michael@0: michael@0: mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen); michael@0: AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView); michael@0: mJavaView = nullptr; michael@0: michael@0: if (mFullScreen) michael@0: sFullScreenInstance = nullptr; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::GetVideos(nsTArray& aVideos) michael@0: { michael@0: if (!mInstance) michael@0: return; michael@0: michael@0: mInstance->GetVideos(aVideos); michael@0: } michael@0: michael@0: already_AddRefed nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo) michael@0: { michael@0: nsRefPtr container = LayerManager::CreateImageContainer(); michael@0: michael@0: nsRefPtr img = container->CreateImage(ImageFormat::SHARED_TEXTURE); michael@0: michael@0: SharedTextureImage::Data data; michael@0: michael@0: data.mShareType = gl::SharedTextureShareType::SameProcess; michael@0: data.mHandle = gl::CreateSharedHandle(mInstance->GLContext(), michael@0: data.mShareType, michael@0: aVideoInfo->mSurfaceTexture, michael@0: gl::SharedTextureBufferType::SurfaceTexture); michael@0: michael@0: // The logic below for Honeycomb is just a guess, but seems to work. We don't have a separate michael@0: // inverted flag for video. michael@0: data.mInverted = AndroidBridge::Bridge()->IsHoneycomb() ? true : mInstance->Inverted(); michael@0: data.mSize = gfx::IntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height); michael@0: michael@0: SharedTextureImage* pluginImage = static_cast(img.get()); michael@0: pluginImage->SetData(data); michael@0: container->SetCurrentImageInTransaction(img); michael@0: michael@0: return container.forget(); michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::Invalidate() { michael@0: NPRect rect; michael@0: rect.left = rect.top = 0; michael@0: rect.right = mPluginWindow->width; michael@0: rect.bottom = mPluginWindow->height; michael@0: InvalidateRect(&rect); michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::RequestFullScreen() { michael@0: if (mFullScreen) michael@0: return; michael@0: michael@0: // Remove whatever view we currently have (if any, fullscreen or otherwise) michael@0: RemovePluginView(); michael@0: michael@0: mFullScreen = true; michael@0: AddPluginView(); michael@0: michael@0: mInstance->NotifyFullScreen(mFullScreen); michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::ExitFullScreen() { michael@0: if (!mFullScreen) michael@0: return; michael@0: michael@0: RemovePluginView(); michael@0: michael@0: mFullScreen = false; michael@0: michael@0: int32_t model = mInstance->GetANPDrawingModel(); michael@0: michael@0: if (model == kSurface_ANPDrawingModel) { michael@0: // We need to do this immediately, otherwise Flash michael@0: // sometimes causes a deadlock (bug 762407) michael@0: AddPluginView(GetPluginRect()); michael@0: } michael@0: michael@0: mInstance->NotifyFullScreen(mFullScreen); michael@0: michael@0: // This will cause Paint() to be called, which is where michael@0: // we normally add/update views and layers michael@0: Invalidate(); michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::ExitFullScreen(jobject view) { michael@0: JNIEnv* env = AndroidBridge::GetJNIEnv(); michael@0: michael@0: if (sFullScreenInstance && sFullScreenInstance->mInstance && michael@0: env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) { michael@0: sFullScreenInstance->ExitFullScreen(); michael@0: } michael@0: } michael@0: michael@0: #endif michael@0: michael@0: nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent) michael@0: { michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (mInstance) { michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = kLifecycle_ANPEventType; michael@0: michael@0: nsAutoString eventType; michael@0: aFocusEvent->GetType(eventType); michael@0: if (eventType.EqualsLiteral("focus")) { michael@0: event.data.lifecycle.action = kGainFocus_ANPLifecycleAction; michael@0: } michael@0: else if (eventType.EqualsLiteral("blur")) { michael@0: event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction; michael@0: } michael@0: else { michael@0: NS_ASSERTION(false, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType"); michael@0: } michael@0: mInstance->HandleEvent(&event, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: #ifndef XP_MACOSX michael@0: if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) { michael@0: // continue only for cases without child window michael@0: return aFocusEvent->PreventDefault(); // consume event michael@0: } michael@0: #endif michael@0: michael@0: WidgetEvent* theEvent = aFocusEvent->GetInternalNSEvent(); michael@0: if (theEvent) { michael@0: // we only care about the message in ProcessEvent michael@0: WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->message, michael@0: nullptr); michael@0: nsEventStatus rv = ProcessEvent(focusEvent); michael@0: if (nsEventStatus_eConsumeNoDefault == rv) { michael@0: aFocusEvent->PreventDefault(); michael@0: aFocusEvent->StopPropagation(); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsPluginInstanceOwner::ProcessKeyPress(nsIDOMEvent* aKeyEvent) michael@0: { michael@0: #ifdef XP_MACOSX michael@0: return DispatchKeyToPlugin(aKeyEvent); michael@0: #else michael@0: if (SendNativeEvents()) michael@0: DispatchKeyToPlugin(aKeyEvent); michael@0: michael@0: if (mInstance) { michael@0: // If this event is going to the plugin, we want to kill it. michael@0: // Not actually sending keypress to the plugin, since we didn't before. michael@0: aKeyEvent->PreventDefault(); michael@0: aKeyEvent->StopPropagation(); michael@0: } michael@0: return NS_OK; michael@0: #endif michael@0: } michael@0: michael@0: nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent) michael@0: { michael@0: #if !defined(XP_MACOSX) michael@0: if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) michael@0: return aKeyEvent->PreventDefault(); // consume event michael@0: // continue only for cases without child window michael@0: #endif michael@0: michael@0: if (mInstance) { michael@0: WidgetKeyboardEvent* keyEvent = michael@0: aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent(); michael@0: if (keyEvent && keyEvent->eventStructType == NS_KEY_EVENT) { michael@0: nsEventStatus rv = ProcessEvent(*keyEvent); michael@0: if (nsEventStatus_eConsumeNoDefault == rv) { michael@0: aKeyEvent->PreventDefault(); michael@0: aKeyEvent->StopPropagation(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsPluginInstanceOwner::ProcessMouseDown(nsIDOMEvent* aMouseEvent) michael@0: { michael@0: #if !defined(XP_MACOSX) michael@0: if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) michael@0: return aMouseEvent->PreventDefault(); // consume event michael@0: // continue only for cases without child window michael@0: #endif michael@0: michael@0: // if the plugin is windowless, we need to set focus ourselves michael@0: // otherwise, we might not get key events michael@0: if (mObjectFrame && mPluginWindow && michael@0: mPluginWindow->type == NPWindowTypeDrawable) { michael@0: michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: if (fm) { michael@0: nsCOMPtr elem = do_QueryInterface(mContent); michael@0: fm->SetFocus(elem, 0); michael@0: } michael@0: } michael@0: michael@0: WidgetMouseEvent* mouseEvent = michael@0: aMouseEvent->GetInternalNSEvent()->AsMouseEvent(); michael@0: if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) { michael@0: mLastMouseDownButtonType = mouseEvent->button; michael@0: nsEventStatus rv = ProcessEvent(*mouseEvent); michael@0: if (nsEventStatus_eConsumeNoDefault == rv) { michael@0: return aMouseEvent->PreventDefault(); // consume event michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent, michael@0: bool aAllowPropagate) michael@0: { michael@0: #if !defined(XP_MACOSX) michael@0: if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) michael@0: return aMouseEvent->PreventDefault(); // consume event michael@0: // continue only for cases without child window michael@0: #endif michael@0: // don't send mouse events if we are hidden michael@0: if (!mWidgetVisible) michael@0: return NS_OK; michael@0: michael@0: WidgetMouseEvent* mouseEvent = michael@0: aMouseEvent->GetInternalNSEvent()->AsMouseEvent(); michael@0: if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) { michael@0: nsEventStatus rv = ProcessEvent(*mouseEvent); michael@0: if (nsEventStatus_eConsumeNoDefault == rv) { michael@0: aMouseEvent->PreventDefault(); michael@0: if (!aAllowPropagate) { michael@0: aMouseEvent->StopPropagation(); michael@0: } michael@0: } michael@0: if (mouseEvent->message == NS_MOUSE_BUTTON_UP) { michael@0: mLastMouseDownButtonType = -1; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: NS_ASSERTION(mInstance, "Should have a valid plugin instance or not receive events."); michael@0: michael@0: nsAutoString eventType; michael@0: aEvent->GetType(eventType); michael@0: if (eventType.EqualsLiteral("focus")) { michael@0: mContentFocused = true; michael@0: return DispatchFocusToPlugin(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("blur")) { michael@0: mContentFocused = false; michael@0: return DispatchFocusToPlugin(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("mousedown")) { michael@0: return ProcessMouseDown(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("mouseup")) { michael@0: // Don't send a mouse-up event to the plugin if its button type doesn't michael@0: // match that of the preceding mouse-down event (if any). This kind of michael@0: // mismatch can happen if the previous mouse-down event was sent to a DOM michael@0: // element above the plugin, the mouse is still above the plugin, and the michael@0: // mouse-down event caused the element to disappear. See bug 627649 and michael@0: // bug 909678. michael@0: WidgetMouseEvent* mouseEvent = aEvent->GetInternalNSEvent()->AsMouseEvent(); michael@0: if (mouseEvent && michael@0: static_cast(mouseEvent->button) != mLastMouseDownButtonType) { michael@0: aEvent->PreventDefault(); michael@0: return NS_OK; michael@0: } michael@0: return DispatchMouseToPlugin(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("mousemove")) { michael@0: return DispatchMouseToPlugin(aEvent, true); michael@0: } michael@0: if (eventType.EqualsLiteral("click") || michael@0: eventType.EqualsLiteral("dblclick") || michael@0: eventType.EqualsLiteral("mouseover") || michael@0: eventType.EqualsLiteral("mouseout")) { michael@0: return DispatchMouseToPlugin(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("keydown") || michael@0: eventType.EqualsLiteral("keyup")) { michael@0: return DispatchKeyToPlugin(aEvent); michael@0: } michael@0: if (eventType.EqualsLiteral("keypress")) { michael@0: return ProcessKeyPress(aEvent); michael@0: } michael@0: michael@0: nsCOMPtr dragEvent(do_QueryInterface(aEvent)); michael@0: if (dragEvent && mInstance) { michael@0: WidgetEvent* ievent = aEvent->GetInternalNSEvent(); michael@0: if ((ievent && ievent->mFlags.mIsTrusted) && michael@0: ievent->message != NS_DRAGDROP_ENTER && ievent->message != NS_DRAGDROP_OVER) { michael@0: aEvent->PreventDefault(); michael@0: } michael@0: michael@0: // Let the plugin handle drag events. michael@0: aEvent->StopPropagation(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef MOZ_X11 michael@0: static unsigned int XInputEventState(const WidgetInputEvent& anEvent) michael@0: { michael@0: unsigned int state = 0; michael@0: if (anEvent.IsShift()) state |= ShiftMask; michael@0: if (anEvent.IsControl()) state |= ControlMask; michael@0: if (anEvent.IsAlt()) state |= Mod1Mask; michael@0: if (anEvent.IsMeta()) state |= Mod4Mask; michael@0: return state; michael@0: } michael@0: #endif michael@0: michael@0: nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent) michael@0: { michael@0: nsEventStatus rv = nsEventStatus_eIgnore; michael@0: michael@0: if (!mInstance || !mObjectFrame) // if mInstance is null, we shouldn't be here michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: #ifdef XP_MACOSX michael@0: if (!mWidget) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: // we never care about synthesized mouse enter michael@0: if (anEvent.message == NS_MOUSE_ENTER_SYNTH) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (!pluginWidget || NS_FAILED(pluginWidget->StartDrawPlugin())) michael@0: return nsEventStatus_eIgnore; michael@0: michael@0: NPEventModel eventModel = GetEventModel(); michael@0: michael@0: // If we have to synthesize an event we'll use one of these. michael@0: NPCocoaEvent synthCocoaEvent; michael@0: void* event = anEvent.pluginEvent; michael@0: nsPoint pt = michael@0: nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) - michael@0: mObjectFrame->GetContentRectRelativeToSelf().TopLeft(); michael@0: nsPresContext* presContext = mObjectFrame->PresContext(); michael@0: // Plugin event coordinates need to be translated from device pixels michael@0: // into "display pixels" in HiDPI modes. michael@0: double scaleFactor = 1.0; michael@0: GetContentsScaleFactor(&scaleFactor); michael@0: size_t intScaleFactor = ceil(scaleFactor); michael@0: nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor, michael@0: presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor); michael@0: michael@0: if (!event) { michael@0: InitializeNPCocoaEvent(&synthCocoaEvent); michael@0: switch (anEvent.message) { michael@0: case NS_MOUSE_MOVE: michael@0: { michael@0: // Ignore mouse-moved events that happen as part of a dragging michael@0: // operation that started over another frame. See bug 525078. michael@0: nsRefPtr frameselection = mObjectFrame->GetFrameSelection(); michael@0: if (!frameselection->GetMouseDownState() || michael@0: (nsIPresShell::GetCapturingContent() == mObjectFrame->GetContent())) { michael@0: synthCocoaEvent.type = NPCocoaEventMouseMoved; michael@0: synthCocoaEvent.data.mouse.pluginX = static_cast(ptPx.x); michael@0: synthCocoaEvent.data.mouse.pluginY = static_cast(ptPx.y); michael@0: event = &synthCocoaEvent; michael@0: } michael@0: } michael@0: break; michael@0: case NS_MOUSE_BUTTON_DOWN: michael@0: synthCocoaEvent.type = NPCocoaEventMouseDown; michael@0: synthCocoaEvent.data.mouse.pluginX = static_cast(ptPx.x); michael@0: synthCocoaEvent.data.mouse.pluginY = static_cast(ptPx.y); michael@0: event = &synthCocoaEvent; michael@0: break; michael@0: case NS_MOUSE_BUTTON_UP: michael@0: // If we're in a dragging operation that started over another frame, michael@0: // convert it into a mouse-entered event (in the Cocoa Event Model). michael@0: // See bug 525078. michael@0: if (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && michael@0: (nsIPresShell::GetCapturingContent() != mObjectFrame->GetContent())) { michael@0: synthCocoaEvent.type = NPCocoaEventMouseEntered; michael@0: synthCocoaEvent.data.mouse.pluginX = static_cast(ptPx.x); michael@0: synthCocoaEvent.data.mouse.pluginY = static_cast(ptPx.y); michael@0: event = &synthCocoaEvent; michael@0: } else { michael@0: synthCocoaEvent.type = NPCocoaEventMouseUp; michael@0: synthCocoaEvent.data.mouse.pluginX = static_cast(ptPx.x); michael@0: synthCocoaEvent.data.mouse.pluginY = static_cast(ptPx.y); michael@0: event = &synthCocoaEvent; michael@0: } michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: // If we still don't have an event, bail. michael@0: if (!event) { michael@0: pluginWidget->EndDrawPlugin(); michael@0: return nsEventStatus_eIgnore; michael@0: } michael@0: } michael@0: michael@0: int16_t response = kNPEventNotHandled; michael@0: void* window = FixUpPluginWindow(ePluginPaintEnable); michael@0: if (window || (eventModel == NPEventModelCocoa)) { michael@0: mInstance->HandleEvent(event, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: } michael@0: michael@0: if (eventModel == NPEventModelCocoa && response == kNPEventStartIME) { michael@0: pluginWidget->StartComplexTextInputForCurrentEvent(); michael@0: } michael@0: michael@0: if ((response == kNPEventHandled || response == kNPEventStartIME) && michael@0: !(anEvent.message == NS_MOUSE_BUTTON_DOWN && michael@0: anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton && michael@0: !mContentFocused)) { michael@0: rv = nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: michael@0: pluginWidget->EndDrawPlugin(); michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: // this code supports windowless plugins michael@0: NPEvent *pPluginEvent = (NPEvent*)anEvent.pluginEvent; michael@0: // we can get synthetic events from the EventStateManager... these michael@0: // have no pluginEvent michael@0: NPEvent pluginEvent; michael@0: if (anEvent.eventStructType == NS_MOUSE_EVENT) { michael@0: if (!pPluginEvent) { michael@0: // XXX Should extend this list to synthesize events for more event michael@0: // types michael@0: pluginEvent.event = 0; michael@0: const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent(); michael@0: switch (anEvent.message) { michael@0: case NS_MOUSE_MOVE: michael@0: pluginEvent.event = WM_MOUSEMOVE; michael@0: break; michael@0: case NS_MOUSE_BUTTON_DOWN: { michael@0: static const int downMsgs[] = michael@0: { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN }; michael@0: static const int dblClickMsgs[] = michael@0: { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK }; michael@0: if (mouseEvent->clickCount == 2) { michael@0: pluginEvent.event = dblClickMsgs[mouseEvent->button]; michael@0: } else { michael@0: pluginEvent.event = downMsgs[mouseEvent->button]; michael@0: } michael@0: break; michael@0: } michael@0: case NS_MOUSE_BUTTON_UP: { michael@0: static const int upMsgs[] = michael@0: { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP }; michael@0: pluginEvent.event = upMsgs[mouseEvent->button]; michael@0: break; michael@0: } michael@0: // don't synthesize anything for NS_MOUSE_DOUBLECLICK, since that michael@0: // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK michael@0: // messages are sent on mouse-down michael@0: default: michael@0: break; michael@0: } michael@0: if (pluginEvent.event) { michael@0: pPluginEvent = &pluginEvent; michael@0: pluginEvent.wParam = michael@0: (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) | michael@0: (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) | michael@0: (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) | michael@0: (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) | michael@0: (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) | michael@0: (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) | michael@0: (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0); michael@0: } michael@0: } michael@0: if (pPluginEvent) { michael@0: // Make event coordinates relative to our enclosing widget, michael@0: // not the widget they were received on. michael@0: // See use of NPEvent in widget/windows/nsWindow.cpp michael@0: // for why this assert should be safe michael@0: NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN || michael@0: anEvent.message == NS_MOUSE_BUTTON_UP || michael@0: anEvent.message == NS_MOUSE_DOUBLECLICK || michael@0: anEvent.message == NS_MOUSE_ENTER_SYNTH || michael@0: anEvent.message == NS_MOUSE_EXIT_SYNTH || michael@0: anEvent.message == NS_MOUSE_MOVE, michael@0: "Incorrect event type for coordinate translation"); michael@0: nsPoint pt = michael@0: nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) - michael@0: mObjectFrame->GetContentRectRelativeToSelf().TopLeft(); michael@0: nsPresContext* presContext = mObjectFrame->PresContext(); michael@0: nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x), michael@0: presContext->AppUnitsToDevPixels(pt.y)); michael@0: nsIntPoint widgetPtPx = ptPx + mObjectFrame->GetWindowOriginInPixels(true); michael@0: pPluginEvent->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y); michael@0: } michael@0: } michael@0: else if (!pPluginEvent) { michael@0: switch (anEvent.message) { michael@0: case NS_FOCUS_CONTENT: michael@0: pluginEvent.event = WM_SETFOCUS; michael@0: pluginEvent.wParam = 0; michael@0: pluginEvent.lParam = 0; michael@0: pPluginEvent = &pluginEvent; michael@0: break; michael@0: case NS_BLUR_CONTENT: michael@0: pluginEvent.event = WM_KILLFOCUS; michael@0: pluginEvent.wParam = 0; michael@0: pluginEvent.lParam = 0; michael@0: pPluginEvent = &pluginEvent; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (pPluginEvent && !pPluginEvent->event) { michael@0: // Don't send null events to plugins. michael@0: NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin."); michael@0: return rv; michael@0: } michael@0: michael@0: if (pPluginEvent) { michael@0: int16_t response = kNPEventNotHandled; michael@0: mInstance->HandleEvent(pPluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: if (response == kNPEventHandled) michael@0: rv = nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_X11 michael@0: // this code supports windowless plugins michael@0: nsIWidget* widget = anEvent.widget; michael@0: XEvent pluginEvent = XEvent(); michael@0: pluginEvent.type = 0; michael@0: michael@0: switch(anEvent.eventStructType) michael@0: { michael@0: case NS_MOUSE_EVENT: michael@0: { michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_MOUSE_CLICK: michael@0: case NS_MOUSE_DOUBLECLICK: michael@0: // Button up/down events sent instead. michael@0: return rv; michael@0: } michael@0: michael@0: // Get reference point relative to plugin origin. michael@0: const nsPresContext* presContext = mObjectFrame->PresContext(); michael@0: nsPoint appPoint = michael@0: nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) - michael@0: mObjectFrame->GetContentRectRelativeToSelf().TopLeft(); michael@0: nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x), michael@0: presContext->AppUnitsToDevPixels(appPoint.y)); michael@0: const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent(); michael@0: // Get reference point relative to screen: michael@0: LayoutDeviceIntPoint rootPoint(-1, -1); michael@0: if (widget) michael@0: rootPoint = anEvent.refPoint + michael@0: LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset()); michael@0: #ifdef MOZ_WIDGET_GTK michael@0: Window root = GDK_ROOT_WINDOW(); michael@0: #elif defined(MOZ_WIDGET_QT) michael@0: Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay())); michael@0: #else michael@0: Window root = None; // Could XQueryTree, but this is not important. michael@0: #endif michael@0: michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_MOUSE_ENTER_SYNTH: michael@0: case NS_MOUSE_EXIT_SYNTH: michael@0: { michael@0: XCrossingEvent& event = pluginEvent.xcrossing; michael@0: event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ? michael@0: EnterNotify : LeaveNotify; michael@0: event.root = root; michael@0: event.time = anEvent.time; michael@0: event.x = pluginPoint.x; michael@0: event.y = pluginPoint.y; michael@0: event.x_root = rootPoint.x; michael@0: event.y_root = rootPoint.y; michael@0: event.state = XInputEventState(mouseEvent); michael@0: // information lost michael@0: event.subwindow = None; michael@0: event.mode = -1; michael@0: event.detail = NotifyDetailNone; michael@0: event.same_screen = True; michael@0: event.focus = mContentFocused; michael@0: } michael@0: break; michael@0: case NS_MOUSE_MOVE: michael@0: { michael@0: XMotionEvent& event = pluginEvent.xmotion; michael@0: event.type = MotionNotify; michael@0: event.root = root; michael@0: event.time = anEvent.time; michael@0: event.x = pluginPoint.x; michael@0: event.y = pluginPoint.y; michael@0: event.x_root = rootPoint.x; michael@0: event.y_root = rootPoint.y; michael@0: event.state = XInputEventState(mouseEvent); michael@0: // information lost michael@0: event.subwindow = None; michael@0: event.is_hint = NotifyNormal; michael@0: event.same_screen = True; michael@0: } michael@0: break; michael@0: case NS_MOUSE_BUTTON_DOWN: michael@0: case NS_MOUSE_BUTTON_UP: michael@0: { michael@0: XButtonEvent& event = pluginEvent.xbutton; michael@0: event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ? michael@0: ButtonPress : ButtonRelease; michael@0: event.root = root; michael@0: event.time = anEvent.time; michael@0: event.x = pluginPoint.x; michael@0: event.y = pluginPoint.y; michael@0: event.x_root = rootPoint.x; michael@0: event.y_root = rootPoint.y; michael@0: event.state = XInputEventState(mouseEvent); michael@0: switch (mouseEvent.button) michael@0: { michael@0: case WidgetMouseEvent::eMiddleButton: michael@0: event.button = 2; michael@0: break; michael@0: case WidgetMouseEvent::eRightButton: michael@0: event.button = 3; michael@0: break; michael@0: default: // WidgetMouseEvent::eLeftButton; michael@0: event.button = 1; michael@0: break; michael@0: } michael@0: // information lost: michael@0: event.subwindow = None; michael@0: event.same_screen = True; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: //XXX case NS_MOUSE_SCROLL_EVENT: not received. michael@0: michael@0: case NS_KEY_EVENT: michael@0: if (anEvent.pluginEvent) michael@0: { michael@0: XKeyEvent &event = pluginEvent.xkey; michael@0: #ifdef MOZ_WIDGET_GTK michael@0: event.root = GDK_ROOT_WINDOW(); michael@0: event.time = anEvent.time; michael@0: const GdkEventKey* gdkEvent = michael@0: static_cast(anEvent.pluginEvent); michael@0: event.keycode = gdkEvent->hardware_keycode; michael@0: event.state = gdkEvent->state; michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_KEY_DOWN: michael@0: // Handle NS_KEY_DOWN for modifier key presses michael@0: // For non-modifiers we get NS_KEY_PRESS michael@0: if (gdkEvent->is_modifier) michael@0: event.type = XKeyPress; michael@0: break; michael@0: case NS_KEY_PRESS: michael@0: event.type = XKeyPress; michael@0: break; michael@0: case NS_KEY_UP: michael@0: event.type = KeyRelease; michael@0: break; michael@0: } michael@0: #endif michael@0: michael@0: // Information that could be obtained from pluginEvent but we may not michael@0: // want to promise to provide: michael@0: event.subwindow = None; michael@0: event.x = 0; michael@0: event.y = 0; michael@0: event.x_root = -1; michael@0: event.y_root = -1; michael@0: event.same_screen = False; michael@0: } michael@0: else michael@0: { michael@0: // If we need to send synthesized key events, then michael@0: // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and michael@0: // gdk_keymap_get_entries_for_keyval will be useful, but the michael@0: // mappings will not be unique. michael@0: NS_WARNING("Synthesized key event not sent to plugin"); michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_FOCUS_CONTENT: michael@0: case NS_BLUR_CONTENT: michael@0: { michael@0: XFocusChangeEvent &event = pluginEvent.xfocus; michael@0: event.type = michael@0: anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut; michael@0: // information lost: michael@0: event.mode = -1; michael@0: event.detail = NotifyDetailNone; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!pluginEvent.type) { michael@0: return rv; michael@0: } michael@0: michael@0: // Fill in (useless) generic event information. michael@0: XAnyEvent& event = pluginEvent.xany; michael@0: event.display = widget ? michael@0: static_cast(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr; michael@0: event.window = None; // not a real window michael@0: // information lost: michael@0: event.serial = 0; michael@0: event.send_event = False; michael@0: michael@0: int16_t response = kNPEventNotHandled; michael@0: mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: if (response == kNPEventHandled) michael@0: rv = nsEventStatus_eConsumeNoDefault; michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: // this code supports windowless plugins michael@0: { michael@0: // The plugin needs focus to receive keyboard and touch events michael@0: nsIFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: if (fm) { michael@0: nsCOMPtr elem = do_QueryInterface(mContent); michael@0: fm->SetFocus(elem, 0); michael@0: } michael@0: } michael@0: switch(anEvent.eventStructType) michael@0: { michael@0: case NS_MOUSE_EVENT: michael@0: { michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_MOUSE_CLICK: michael@0: case NS_MOUSE_DOUBLECLICK: michael@0: // Button up/down events sent instead. michael@0: return rv; michael@0: } michael@0: michael@0: // Get reference point relative to plugin origin. michael@0: const nsPresContext* presContext = mObjectFrame->PresContext(); michael@0: nsPoint appPoint = michael@0: nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) - michael@0: mObjectFrame->GetContentRectRelativeToSelf().TopLeft(); michael@0: nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x), michael@0: presContext->AppUnitsToDevPixels(appPoint.y)); michael@0: michael@0: switch (anEvent.message) michael@0: { michael@0: case NS_MOUSE_MOVE: michael@0: { michael@0: // are these going to be touch events? michael@0: // pluginPoint.x; michael@0: // pluginPoint.y; michael@0: } michael@0: break; michael@0: case NS_MOUSE_BUTTON_DOWN: michael@0: { michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = kMouse_ANPEventType; michael@0: event.data.mouse.action = kDown_ANPMouseAction; michael@0: event.data.mouse.x = pluginPoint.x; michael@0: event.data.mouse.y = pluginPoint.y; michael@0: mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: } michael@0: break; michael@0: case NS_MOUSE_BUTTON_UP: michael@0: { michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = kMouse_ANPEventType; michael@0: event.data.mouse.action = kUp_ANPMouseAction; michael@0: event.data.mouse.x = pluginPoint.x; michael@0: event.data.mouse.y = pluginPoint.y; michael@0: mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case NS_KEY_EVENT: michael@0: { michael@0: const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent(); michael@0: LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode); michael@0: // pluginEvent is initialized by nsWindow::InitKeyEvent(). michael@0: ANPEvent* pluginEvent = reinterpret_cast(keyEvent.pluginEvent); michael@0: if (pluginEvent) { michael@0: MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent)); michael@0: MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType); michael@0: mInstance->HandleEvent(pluginEvent, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: rv = nsEventStatus_eConsumeNoDefault; michael@0: #endif michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsPluginInstanceOwner::Destroy() michael@0: { michael@0: SetFrame(nullptr); michael@0: michael@0: #ifdef XP_MACOSX michael@0: RemoveFromCARefreshTimer(); michael@0: if (mColorProfile) michael@0: ::CGColorSpaceRelease(mColorProfile); michael@0: #endif michael@0: michael@0: // unregister context menu listener michael@0: if (mCXMenuListener) { michael@0: mCXMenuListener->Destroy(mContent); michael@0: mCXMenuListener = nullptr; michael@0: } michael@0: michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("focus"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("blur"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("click"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dblclick"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("drop"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("drag"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragenter"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragover"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, true); michael@0: mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true); michael@0: michael@0: #if MOZ_WIDGET_ANDROID michael@0: RemovePluginView(); michael@0: #endif michael@0: michael@0: if (mWidget) { michael@0: if (mPluginWindow) { michael@0: mPluginWindow->SetPluginWidget(nullptr); michael@0: } michael@0: michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (pluginWidget) { michael@0: pluginWidget->SetPluginInstanceOwner(nullptr); michael@0: } michael@0: mWidget->Destroy(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Paints are handled differently, so we just simulate an update event. michael@0: michael@0: #ifdef XP_MACOSX michael@0: void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext) michael@0: { michael@0: if (!mInstance || !mObjectFrame) michael@0: return; michael@0: michael@0: gfxRect dirtyRectCopy = aDirtyRect; michael@0: double scaleFactor = 1.0; michael@0: GetContentsScaleFactor(&scaleFactor); michael@0: if (scaleFactor != 1.0) { michael@0: ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor); michael@0: // Convert aDirtyRect from device pixels to "display pixels" michael@0: // for HiDPI modes michael@0: dirtyRectCopy.ScaleRoundOut(1.0 / scaleFactor); michael@0: } michael@0: michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) { michael@0: DoCocoaEventDrawRect(dirtyRectCopy, cgContext); michael@0: pluginWidget->EndDrawPlugin(); michael@0: } michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext) michael@0: { michael@0: if (!mInstance || !mObjectFrame) michael@0: return; michael@0: michael@0: // The context given here is only valid during the HandleEvent call. michael@0: NPCocoaEvent updateEvent; michael@0: InitializeNPCocoaEvent(&updateEvent); michael@0: updateEvent.type = NPCocoaEventDrawRect; michael@0: updateEvent.data.draw.context = cgContext; michael@0: updateEvent.data.draw.x = aDrawRect.X(); michael@0: updateEvent.data.draw.y = aDrawRect.Y(); michael@0: updateEvent.data.draw.width = aDrawRect.Width(); michael@0: updateEvent.data.draw.height = aDrawRect.Height(); michael@0: michael@0: mInstance->HandleEvent(&updateEvent, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: #ifdef XP_WIN michael@0: void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC) michael@0: { michael@0: if (!mInstance || !mObjectFrame) michael@0: return; michael@0: michael@0: NPEvent pluginEvent; michael@0: pluginEvent.event = WM_PAINT; michael@0: pluginEvent.wParam = WPARAM(aDC); michael@0: pluginEvent.lParam = LPARAM(&aDirty); michael@0: mInstance->HandleEvent(&pluginEvent, nullptr); michael@0: } michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: michael@0: void nsPluginInstanceOwner::Paint(gfxContext* aContext, michael@0: const gfxRect& aFrameRect, michael@0: const gfxRect& aDirtyRect) michael@0: { michael@0: if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen) michael@0: return; michael@0: michael@0: int32_t model = mInstance->GetANPDrawingModel(); michael@0: michael@0: if (model == kSurface_ANPDrawingModel) { michael@0: if (!AddPluginView(GetPluginRect())) { michael@0: Invalidate(); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (model != kBitmap_ANPDrawingModel) michael@0: return; michael@0: michael@0: #ifdef ANP_BITMAP_DRAWING_MODEL michael@0: static nsRefPtr pluginSurface; michael@0: michael@0: if (pluginSurface == nullptr || michael@0: aFrameRect.width != pluginSurface->Width() || michael@0: aFrameRect.height != pluginSurface->Height()) { michael@0: michael@0: pluginSurface = new gfxImageSurface(gfxIntSize(aFrameRect.width, aFrameRect.height), michael@0: gfxImageFormat::ARGB32); michael@0: if (!pluginSurface) michael@0: return; michael@0: } michael@0: michael@0: // Clears buffer. I think this is needed. michael@0: nsRefPtr ctx = new gfxContext(pluginSurface); michael@0: ctx->SetOperator(gfxContext::OPERATOR_CLEAR); michael@0: ctx->Paint(); michael@0: michael@0: ANPEvent event; michael@0: event.inSize = sizeof(ANPEvent); michael@0: event.eventType = 4; michael@0: event.data.draw.model = 1; michael@0: michael@0: event.data.draw.clip.top = 0; michael@0: event.data.draw.clip.left = 0; michael@0: event.data.draw.clip.bottom = aFrameRect.width; michael@0: event.data.draw.clip.right = aFrameRect.height; michael@0: michael@0: event.data.draw.data.bitmap.format = kRGBA_8888_ANPBitmapFormat; michael@0: event.data.draw.data.bitmap.width = aFrameRect.width; michael@0: event.data.draw.data.bitmap.height = aFrameRect.height; michael@0: event.data.draw.data.bitmap.baseAddr = pluginSurface->Data(); michael@0: event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4; michael@0: michael@0: if (!mInstance) michael@0: return; michael@0: michael@0: mInstance->HandleEvent(&event, nullptr); michael@0: michael@0: aContext->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y)); michael@0: aContext->Clip(aFrameRect); michael@0: aContext->Paint(); michael@0: #endif michael@0: } michael@0: #endif michael@0: michael@0: #if defined(MOZ_X11) michael@0: void nsPluginInstanceOwner::Paint(gfxContext* aContext, michael@0: const gfxRect& aFrameRect, michael@0: const gfxRect& aDirtyRect) michael@0: { michael@0: if (!mInstance || !mObjectFrame) michael@0: return; michael@0: michael@0: // to provide crisper and faster drawing. michael@0: gfxRect pluginRect = aFrameRect; michael@0: if (aContext->UserToDevicePixelSnapped(pluginRect)) { michael@0: pluginRect = aContext->DeviceToUser(pluginRect); michael@0: } michael@0: michael@0: // Round out the dirty rect to plugin pixels to ensure the plugin draws michael@0: // enough pixels for interpolation to device pixels. michael@0: gfxRect dirtyRect = aDirtyRect - pluginRect.TopLeft(); michael@0: dirtyRect.RoundOut(); michael@0: michael@0: // Plugins can only draw an integer number of pixels. michael@0: // michael@0: // With translation-only transformation matrices, pluginRect is already michael@0: // pixel-aligned. michael@0: // michael@0: // With more complex transformations, modifying the scales in the michael@0: // transformation matrix could retain subpixel accuracy and let the plugin michael@0: // draw a suitable number of pixels for interpolation to device pixels in michael@0: // Renderer::Draw, but such cases are not common enough to warrant the michael@0: // effort now. michael@0: nsIntSize pluginSize(NS_lround(pluginRect.width), michael@0: NS_lround(pluginRect.height)); michael@0: michael@0: // Determine what the plugin needs to draw. michael@0: nsIntRect pluginDirtyRect(int32_t(dirtyRect.x), michael@0: int32_t(dirtyRect.y), michael@0: int32_t(dirtyRect.width), michael@0: int32_t(dirtyRect.height)); michael@0: if (!pluginDirtyRect. michael@0: IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height), michael@0: pluginDirtyRect)) michael@0: return; michael@0: michael@0: NPWindow* window; michael@0: GetWindow(window); michael@0: michael@0: uint32_t rendererFlags = 0; michael@0: if (!mFlash10Quirks) { michael@0: rendererFlags |= michael@0: Renderer::DRAW_SUPPORTS_CLIP_RECT | michael@0: Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL; michael@0: } michael@0: michael@0: bool transparent; michael@0: mInstance->IsTransparent(&transparent); michael@0: if (!transparent) michael@0: rendererFlags |= Renderer::DRAW_IS_OPAQUE; michael@0: michael@0: // Renderer::Draw() draws a rectangle with top-left at the aContext origin. michael@0: gfxContextAutoSaveRestore autoSR(aContext); michael@0: aContext->Translate(pluginRect.TopLeft()); michael@0: michael@0: Renderer renderer(window, this, pluginSize, pluginDirtyRect); michael@0: michael@0: Display* dpy = mozilla::DefaultXDisplay(); michael@0: Screen* screen = DefaultScreenOfDisplay(dpy); michael@0: Visual* visual = DefaultVisualOfScreen(screen); michael@0: michael@0: renderer.Draw(aContext, nsIntSize(window->width, window->height), michael@0: rendererFlags, screen, visual); michael@0: } michael@0: nsresult michael@0: nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface, michael@0: nsIntPoint offset, michael@0: nsIntRect *clipRects, michael@0: uint32_t numClipRects) michael@0: { michael@0: Screen *screen = cairo_xlib_surface_get_screen(xsurface); michael@0: Colormap colormap; michael@0: Visual* visual; michael@0: if (!gfxXlibSurface::GetColormapAndVisual(xsurface, &colormap, &visual)) { michael@0: NS_ERROR("Failed to get visual and colormap"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: nsNPAPIPluginInstance *instance = mInstanceOwner->mInstance; michael@0: if (!instance) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // See if the plugin must be notified of new window parameters. michael@0: bool doupdatewindow = false; michael@0: michael@0: if (mWindow->x != offset.x || mWindow->y != offset.y) { michael@0: mWindow->x = offset.x; michael@0: mWindow->y = offset.y; michael@0: doupdatewindow = true; michael@0: } michael@0: michael@0: if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) { michael@0: mWindow->width = mPluginSize.width; michael@0: mWindow->height = mPluginSize.height; michael@0: doupdatewindow = true; michael@0: } michael@0: michael@0: // The clip rect is relative to drawable top-left. michael@0: NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!"); michael@0: nsIntRect clipRect; michael@0: if (numClipRects) { michael@0: clipRect.x = clipRects[0].x; michael@0: clipRect.y = clipRects[0].y; michael@0: clipRect.width = clipRects[0].width; michael@0: clipRect.height = clipRects[0].height; michael@0: // NPRect members are unsigned, but clip rectangles should be contained by michael@0: // the surface. michael@0: NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0, michael@0: "Clip rectangle offsets are negative!"); michael@0: } michael@0: else { michael@0: clipRect.x = offset.x; michael@0: clipRect.y = offset.y; michael@0: clipRect.width = mWindow->width; michael@0: clipRect.height = mWindow->height; michael@0: // Don't ask the plugin to draw outside the drawable. michael@0: // This also ensures that the unsigned clip rectangle offsets won't be -ve. michael@0: clipRect.IntersectRect(clipRect, michael@0: nsIntRect(0, 0, michael@0: cairo_xlib_surface_get_width(xsurface), michael@0: cairo_xlib_surface_get_height(xsurface))); michael@0: } michael@0: michael@0: NPRect newClipRect; michael@0: newClipRect.left = clipRect.x; michael@0: newClipRect.top = clipRect.y; michael@0: newClipRect.right = clipRect.XMost(); michael@0: newClipRect.bottom = clipRect.YMost(); michael@0: if (mWindow->clipRect.left != newClipRect.left || michael@0: mWindow->clipRect.top != newClipRect.top || michael@0: mWindow->clipRect.right != newClipRect.right || michael@0: mWindow->clipRect.bottom != newClipRect.bottom) { michael@0: mWindow->clipRect = newClipRect; michael@0: doupdatewindow = true; michael@0: } michael@0: michael@0: NPSetWindowCallbackStruct* ws_info = michael@0: static_cast(mWindow->ws_info); michael@0: #ifdef MOZ_X11 michael@0: if (ws_info->visual != visual || ws_info->colormap != colormap) { michael@0: ws_info->visual = visual; michael@0: ws_info->colormap = colormap; michael@0: ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual); michael@0: doupdatewindow = true; michael@0: } michael@0: #endif michael@0: michael@0: { michael@0: if (doupdatewindow) michael@0: instance->SetWindow(mWindow); michael@0: } michael@0: michael@0: // Translate the dirty rect to drawable coordinates. michael@0: nsIntRect dirtyRect = mDirtyRect + offset; michael@0: if (mInstanceOwner->mFlash10Quirks) { michael@0: // Work around a bug in Flash up to 10.1 d51 at least, where expose event michael@0: // top left coordinates within the plugin-rect and not at the drawable michael@0: // origin are misinterpreted. (We can move the top left coordinate michael@0: // provided it is within the clipRect.) michael@0: dirtyRect.SetRect(offset.x, offset.y, michael@0: mDirtyRect.XMost(), mDirtyRect.YMost()); michael@0: } michael@0: // Intersect the dirty rect with the clip rect to ensure that it lies within michael@0: // the drawable. michael@0: if (!dirtyRect.IntersectRect(dirtyRect, clipRect)) michael@0: return NS_OK; michael@0: michael@0: { michael@0: XEvent pluginEvent = XEvent(); michael@0: XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose; michael@0: // set the drawing info michael@0: exposeEvent.type = GraphicsExpose; michael@0: exposeEvent.display = DisplayOfScreen(screen); michael@0: exposeEvent.drawable = cairo_xlib_surface_get_drawable(xsurface); michael@0: exposeEvent.x = dirtyRect.x; michael@0: exposeEvent.y = dirtyRect.y; michael@0: exposeEvent.width = dirtyRect.width; michael@0: exposeEvent.height = dirtyRect.height; michael@0: exposeEvent.count = 0; michael@0: // information not set: michael@0: exposeEvent.serial = 0; michael@0: exposeEvent.send_event = False; michael@0: exposeEvent.major_code = 0; michael@0: exposeEvent.minor_code = 0; michael@0: michael@0: instance->HandleEvent(&pluginEvent, nullptr); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: nsresult nsPluginInstanceOwner::Init(nsIContent* aContent) michael@0: { michael@0: mLastEventloopNestingLevel = GetEventloopNestingLevel(); michael@0: michael@0: mContent = aContent; michael@0: michael@0: // Get a frame, don't reflow. If a reflow was necessary it should have been michael@0: // done at a higher level than this (content). michael@0: nsIFrame* frame = aContent->GetPrimaryFrame(); michael@0: nsIObjectFrame* iObjFrame = do_QueryFrame(frame); michael@0: nsObjectFrame* objFrame = static_cast(iObjFrame); michael@0: if (objFrame) { michael@0: SetFrame(objFrame); michael@0: // Some plugins require a specific sequence of shutdown and startup when michael@0: // a page is reloaded. Shutdown happens usually when the last instance michael@0: // is destroyed. Here we make sure the plugin instance in the old michael@0: // document is destroyed before we try to create the new one. michael@0: objFrame->PresContext()->EnsureVisible(); michael@0: } else { michael@0: NS_NOTREACHED("Should not be initializing plugin without a frame"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // register context menu listener michael@0: mCXMenuListener = new nsPluginDOMContextMenuListener(aContent); michael@0: michael@0: mContent->AddEventListener(NS_LITERAL_STRING("focus"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("blur"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("mouseup"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("mousemove"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("click"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dblclick"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("mouseover"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("mouseout"), this, false, michael@0: false); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("keypress"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("keydown"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("keyup"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("drop"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragdrop"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("drag"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, true); michael@0: mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void* nsPluginInstanceOwner::GetPluginPortFromWidget() michael@0: { michael@0: //!!! Port must be released for windowless plugins on Windows, because it is HDC !!! michael@0: michael@0: void* result = nullptr; michael@0: if (mWidget) { michael@0: #ifdef XP_WIN michael@0: if (mPluginWindow && (mPluginWindow->type == NPWindowTypeDrawable)) michael@0: result = mWidget->GetNativeData(NS_NATIVE_GRAPHIC); michael@0: else michael@0: #endif michael@0: #ifdef XP_MACOSX michael@0: if (GetDrawingModel() == NPDrawingModelCoreGraphics || michael@0: GetDrawingModel() == NPDrawingModelCoreAnimation || michael@0: GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation) michael@0: result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG); michael@0: else michael@0: #endif michael@0: result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort) michael@0: { michael@0: #ifdef XP_WIN michael@0: if (mWidget && mPluginWindow && michael@0: mPluginWindow->type == NPWindowTypeDrawable) { michael@0: mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void) michael@0: { michael@0: NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER); michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: // Can't call this twice! michael@0: if (mWidget) { michael@0: NS_WARNING("Trying to create a plugin widget twice!"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: bool windowless = false; michael@0: mInstance->IsWindowless(&windowless); michael@0: if (!windowless && !nsIWidget::UsePuppetWidgets()) { michael@0: // Try to get a parent widget, on some platforms widget creation will fail without michael@0: // a parent. michael@0: nsCOMPtr parentWidget; michael@0: nsIDocument *doc = nullptr; michael@0: if (mContent) { michael@0: doc = mContent->OwnerDoc(); michael@0: parentWidget = nsContentUtils::WidgetForDocument(doc); michael@0: } michael@0: michael@0: mWidget = do_CreateInstance(kWidgetCID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: nsWidgetInitData initData; michael@0: initData.mWindowType = eWindowType_plugin; michael@0: initData.mUnicode = false; michael@0: initData.clipChildren = true; michael@0: initData.clipSiblings = true; michael@0: rv = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0), michael@0: nullptr, &initData); michael@0: if (NS_FAILED(rv)) { michael@0: mWidget->Destroy(); michael@0: mWidget = nullptr; michael@0: return rv; michael@0: } michael@0: michael@0: mWidget->EnableDragDrop(true); michael@0: mWidget->Show(false); michael@0: mWidget->Enable(false); michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Now that we have a widget we want to set the event model before michael@0: // any events are processed. michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (!pluginWidget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: pluginWidget->SetPluginEventModel(GetEventModel()); michael@0: pluginWidget->SetPluginDrawingModel(GetDrawingModel()); michael@0: michael@0: if (GetDrawingModel() == NPDrawingModelCoreAnimation) { michael@0: AddToCARefreshTimer(); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: if (mObjectFrame) { michael@0: // nullptr widget is fine, will result in windowless setup. michael@0: mObjectFrame->PrepForDrawing(mWidget); michael@0: } michael@0: michael@0: if (windowless) { michael@0: mPluginWindow->type = NPWindowTypeDrawable; michael@0: michael@0: // this needs to be a HDC according to the spec, but I do michael@0: // not see the right way to release it so let's postpone michael@0: // passing HDC till paint event when it is really michael@0: // needed. Change spec? michael@0: mPluginWindow->window = nullptr; michael@0: #ifdef MOZ_X11 michael@0: // Fill in the display field. michael@0: NPSetWindowCallbackStruct* ws_info = michael@0: static_cast(mPluginWindow->ws_info); michael@0: ws_info->display = DefaultXDisplay(); michael@0: michael@0: nsAutoCString description; michael@0: GetPluginDescription(description); michael@0: NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10."); michael@0: mFlash10Quirks = StringBeginsWith(description, flash10Head); michael@0: #endif michael@0: } else if (mWidget) { michael@0: // mPluginWindow->type is used in |GetPluginPort| so it must michael@0: // be initialized first michael@0: mPluginWindow->type = NPWindowTypeWindow; michael@0: mPluginWindow->window = GetPluginPortFromWidget(); michael@0: // tell the plugin window about the widget michael@0: mPluginWindow->SetPluginWidget(mWidget); michael@0: michael@0: // tell the widget about the current plugin instance owner. michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (pluginWidget) { michael@0: pluginWidget->SetPluginInstanceOwner(this); michael@0: } michael@0: } michael@0: michael@0: mWidgetCreationComplete = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Mac specific code to fix up the port location and clipping region michael@0: #ifdef XP_MACOSX michael@0: michael@0: void* nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState) michael@0: { michael@0: if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr pluginWidget = do_QueryInterface(mWidget); michael@0: if (!pluginWidget) michael@0: return nullptr; michael@0: michael@0: // If we've already set up a CGContext in nsObjectFrame::PaintPlugin(), we michael@0: // don't want calls to SetPluginPortAndDetectChange() to step on our work. michael@0: if (mInCGPaintLevel < 1) { michael@0: SetPluginPortAndDetectChange(); michael@0: } michael@0: michael@0: // We'll need the top-level Cocoa window for the Cocoa event model. michael@0: nsIWidget* widget = mObjectFrame->GetNearestWidget(); michael@0: if (!widget) michael@0: return nullptr; michael@0: void *cocoaTopLevelWindow = widget->GetNativeData(NS_NATIVE_WINDOW); michael@0: if (!cocoaTopLevelWindow) michael@0: return nullptr; michael@0: michael@0: nsIntPoint pluginOrigin; michael@0: nsIntRect widgetClip; michael@0: bool widgetVisible; michael@0: pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, widgetVisible); michael@0: mWidgetVisible = widgetVisible; michael@0: michael@0: // printf("GetPluginClipRect returning visible %d\n", widgetVisible); michael@0: michael@0: // This would be a lot easier if we could use obj-c here, michael@0: // but we can't. Since we have only nsIWidget and we can't michael@0: // use its native widget (an obj-c object) we have to go michael@0: // from the widget's screen coordinates to its window coords michael@0: // instead of straight to window coords. michael@0: nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset(); michael@0: michael@0: nsRect windowRect; michael@0: NS_NPAPI_CocoaWindowFrame(cocoaTopLevelWindow, windowRect); michael@0: michael@0: double scaleFactor = 1.0; michael@0: GetContentsScaleFactor(&scaleFactor); michael@0: int intScaleFactor = ceil(scaleFactor); michael@0: michael@0: // Convert geckoScreenCoords from device pixels to "display pixels" michael@0: // for HiDPI modes. michael@0: mPluginWindow->x = geckoScreenCoords.x/intScaleFactor - windowRect.x; michael@0: mPluginWindow->y = geckoScreenCoords.y/intScaleFactor - windowRect.y; michael@0: michael@0: NPRect oldClipRect = mPluginWindow->clipRect; michael@0: michael@0: // fix up the clipping region michael@0: mPluginWindow->clipRect.top = widgetClip.y; michael@0: mPluginWindow->clipRect.left = widgetClip.x; michael@0: michael@0: if (!mWidgetVisible || inPaintState == ePluginPaintDisable) { michael@0: mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top; michael@0: mPluginWindow->clipRect.right = mPluginWindow->clipRect.left; michael@0: } michael@0: else if (inPaintState == ePluginPaintEnable) michael@0: { michael@0: mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height; michael@0: mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width; michael@0: } michael@0: michael@0: // if the clip rect changed, call SetWindow() michael@0: // (RealPlayer needs this to draw correctly) michael@0: if (mPluginWindow->clipRect.left != oldClipRect.left || michael@0: mPluginWindow->clipRect.top != oldClipRect.top || michael@0: mPluginWindow->clipRect.right != oldClipRect.right || michael@0: mPluginWindow->clipRect.bottom != oldClipRect.bottom || michael@0: mPluginPortChanged) michael@0: { michael@0: if (UseAsyncRendering()) { michael@0: mInstance->AsyncSetWindow(mPluginWindow); michael@0: } michael@0: else { michael@0: mPluginWindow->CallSetWindow(mInstance); michael@0: } michael@0: mPluginPortChanged = false; michael@0: } michael@0: michael@0: // After the first NPP_SetWindow call we need to send an initial michael@0: // top-level window focus event. michael@0: if (!mSentInitialTopLevelWindowEvent) { michael@0: // Set this before calling ProcessEvent to avoid endless recursion. michael@0: mSentInitialTopLevelWindowEvent = true; michael@0: michael@0: WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, nullptr); michael@0: NPCocoaEvent cocoaEvent; michael@0: InitializeNPCocoaEvent(&cocoaEvent); michael@0: cocoaEvent.type = NPCocoaEventWindowFocusChanged; michael@0: cocoaEvent.data.focus.hasFocus = NS_NPAPI_CocoaWindowIsMain(cocoaTopLevelWindow); michael@0: pluginEvent.pluginEvent = &cocoaEvent; michael@0: ProcessEvent(pluginEvent); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsPluginInstanceOwner::HidePluginWindow() michael@0: { michael@0: if (!mPluginWindow || !mInstance) { michael@0: return; michael@0: } michael@0: michael@0: mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top; michael@0: mPluginWindow->clipRect.right = mPluginWindow->clipRect.left; michael@0: mWidgetVisible = false; michael@0: if (UseAsyncRendering()) { michael@0: mInstance->AsyncSetWindow(mPluginWindow); michael@0: } else { michael@0: mInstance->SetWindow(mPluginWindow); michael@0: } michael@0: } michael@0: michael@0: #else // XP_MACOSX michael@0: michael@0: void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow) michael@0: { michael@0: if (!mPluginWindow) michael@0: return; michael@0: michael@0: // For windowless plugins a non-empty clip rectangle will be michael@0: // passed to the plugin during paint, an additional update michael@0: // of the the clip rectangle here is not required michael@0: if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering()) michael@0: return; michael@0: michael@0: const NPWindow oldWindow = *mPluginWindow; michael@0: michael@0: bool windowless = (mPluginWindow->type == NPWindowTypeDrawable); michael@0: nsIntPoint origin = mObjectFrame->GetWindowOriginInPixels(windowless); michael@0: michael@0: mPluginWindow->x = origin.x; michael@0: mPluginWindow->y = origin.y; michael@0: michael@0: mPluginWindow->clipRect.left = 0; michael@0: mPluginWindow->clipRect.top = 0; michael@0: michael@0: if (mPluginWindowVisible && mPluginDocumentActiveState) { michael@0: mPluginWindow->clipRect.right = mPluginWindow->width; michael@0: mPluginWindow->clipRect.bottom = mPluginWindow->height; michael@0: } else { michael@0: mPluginWindow->clipRect.right = 0; michael@0: mPluginWindow->clipRect.bottom = 0; michael@0: } michael@0: michael@0: if (!aSetWindow) michael@0: return; michael@0: michael@0: if (mPluginWindow->x != oldWindow.x || michael@0: mPluginWindow->y != oldWindow.y || michael@0: mPluginWindow->clipRect.left != oldWindow.clipRect.left || michael@0: mPluginWindow->clipRect.top != oldWindow.clipRect.top || michael@0: mPluginWindow->clipRect.right != oldWindow.clipRect.right || michael@0: mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) { michael@0: CallSetWindow(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible) michael@0: { michael@0: mPluginWindowVisible = aVisible; michael@0: UpdateWindowPositionAndClipRect(true); michael@0: } michael@0: michael@0: void michael@0: nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive) michael@0: { michael@0: mPluginDocumentActiveState = aIsActive; michael@0: UpdateWindowPositionAndClipRect(true); michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (mInstance) { michael@0: if (!mPluginDocumentActiveState) michael@0: RemovePluginView(); michael@0: michael@0: mInstance->NotifyOnScreen(mPluginDocumentActiveState); michael@0: michael@0: // This is, perhaps, incorrect. It is supposed to be sent michael@0: // when "the webview has paused or resumed". The side effect michael@0: // is that Flash video players pause or resume (if they were michael@0: // playing before) based on the value here. I personally think michael@0: // we want that on Android when switching to another tab, so michael@0: // that's why we call it here. michael@0: mInstance->NotifyForeground(mPluginDocumentActiveState); michael@0: } michael@0: #endif michael@0: } michael@0: #endif // XP_MACOSX michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginInstanceOwner::CallSetWindow() michael@0: { michael@0: if (mObjectFrame) { michael@0: mObjectFrame->CallSetWindow(false); michael@0: } else if (mInstance) { michael@0: if (UseAsyncRendering()) { michael@0: mInstance->AsyncSetWindow(mPluginWindow); michael@0: } else { michael@0: mInstance->SetWindow(mPluginWindow); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginInstanceOwner::GetContentsScaleFactor(double *result) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(result); michael@0: double scaleFactor = 1.0; michael@0: // On Mac, device pixels need to be translated to (and from) "display pixels" michael@0: // for plugins. On other platforms, plugin coordinates are always in device michael@0: // pixels. michael@0: #if defined(XP_MACOSX) michael@0: nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(mContent->OwnerDoc()); michael@0: if (presShell) { michael@0: scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/ michael@0: presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel(); michael@0: } michael@0: #endif michael@0: *result = scaleFactor; michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame) michael@0: { michael@0: // Don't do anything if the frame situation hasn't changed. michael@0: if (mObjectFrame == aFrame) { michael@0: return; michael@0: } michael@0: michael@0: // If we already have a frame that is changing or going away... michael@0: if (mObjectFrame) { michael@0: // Make sure the old frame isn't holding a reference to us. michael@0: mObjectFrame->SetInstanceOwner(nullptr); michael@0: } michael@0: michael@0: // Swap in the new frame (or no frame) michael@0: mObjectFrame = aFrame; michael@0: michael@0: // Set up a new frame michael@0: if (mObjectFrame) { michael@0: mObjectFrame->SetInstanceOwner(this); michael@0: // Can only call PrepForDrawing on an object frame once. Don't do it here unless michael@0: // widget creation is complete. Doesn't matter if we actually have a widget. michael@0: if (mWidgetCreationComplete) { michael@0: mObjectFrame->PrepForDrawing(mWidget); michael@0: } michael@0: mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size()); michael@0: mObjectFrame->InvalidateFrame(); michael@0: michael@0: nsFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: const nsIContent* content = aFrame->GetContent(); michael@0: if (fm && content) { michael@0: mContentFocused = (content == fm->GetFocusedContent()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsObjectFrame* nsPluginInstanceOwner::GetFrame() michael@0: { michael@0: return mObjectFrame; michael@0: } michael@0: michael@0: // Little helper function to resolve relative URL in michael@0: // |value| for certain inputs of |name| michael@0: void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value) michael@0: { michael@0: if (name.LowerCaseEqualsLiteral("pluginspage")) { michael@0: nsCOMPtr baseURI = GetBaseURI(); michael@0: nsAutoString newURL; michael@0: NS_MakeAbsoluteURI(newURL, value, baseURI); michael@0: if (!newURL.IsEmpty()) michael@0: value = newURL; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled) michael@0: { michael@0: return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK; michael@0: } michael@0: michael@0: already_AddRefed nsPluginInstanceOwner::GetBaseURI() const michael@0: { michael@0: if (!mContent) { michael@0: return nullptr; michael@0: } michael@0: return mContent->GetBaseURI(); michael@0: } michael@0: michael@0: // nsPluginDOMContextMenuListener class implementation michael@0: michael@0: nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener(nsIContent* aContent) michael@0: { michael@0: aContent->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true); michael@0: } michael@0: michael@0: nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener() michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener, michael@0: nsIDOMEventListener) michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginDOMContextMenuListener::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: aEvent->PreventDefault(); // consume event michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent) michael@0: { michael@0: // Unregister context menu listener michael@0: aContent->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true); michael@0: }