michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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: // Local Includes michael@0: #include "nsDocShellTreeOwner.h" michael@0: #include "nsWebBrowser.h" michael@0: michael@0: // Helper Classes michael@0: #include "nsStyleCoord.h" michael@0: #include "nsSize.h" michael@0: #include "nsHTMLReflowState.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "mozilla/LookAndFeel.h" michael@0: michael@0: // Interfaces needed to be included michael@0: #include "nsPresContext.h" michael@0: #include "nsIContextMenuListener.h" michael@0: #include "nsIContextMenuListener2.h" michael@0: #include "nsITooltipListener.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsIDOMNodeList.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMDocumentType.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "Link.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/SVGTitleElement.h" michael@0: #include "nsIDOMEvent.h" michael@0: #include "nsIDOMMouseEvent.h" michael@0: #include "nsIFormControl.h" michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsIDOMHTMLTextAreaElement.h" michael@0: #include "nsIDOMHTMLHtmlElement.h" michael@0: #include "nsIDOMHTMLAppletElement.h" michael@0: #include "nsIDOMHTMLObjectElement.h" michael@0: #include "nsIDOMHTMLEmbedElement.h" michael@0: #include "nsIDOMHTMLDocument.h" michael@0: #include "nsIImageLoadingContent.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsIDOMHTMLElement.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsPIWindowRoot.h" michael@0: #include "nsIDOMWindowCollection.h" michael@0: #include "nsIWindowWatcher.h" michael@0: #include "nsPIWindowWatcher.h" michael@0: #include "nsIPrompt.h" michael@0: #include "nsRect.h" michael@0: #include "nsIWebBrowserChromeFocus.h" michael@0: #include "nsIContent.h" michael@0: #include "imgIContainer.h" michael@0: #include "nsContextMenuInfo.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsView.h" michael@0: #include "nsIDOMDragEvent.h" michael@0: #include "nsIConstraintValidation.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: // michael@0: // GetEventReceiver michael@0: // michael@0: // A helper routine that navigates the tricky path from a |nsWebBrowser| to michael@0: // a |EventTarget| via the window root and chrome event handler. michael@0: // michael@0: static nsresult michael@0: GetDOMEventTarget(nsWebBrowser* inBrowser, EventTarget** aTarget) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(inBrowser); michael@0: michael@0: nsCOMPtr domWindow; michael@0: inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); michael@0: NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr domWindowPrivate = do_QueryInterface(domWindow); michael@0: NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE); michael@0: nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot(); michael@0: NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE); michael@0: nsCOMPtr target = michael@0: rootWindow->GetChromeEventHandler(); michael@0: NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); michael@0: target.forget(aTarget); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: //***************************************************************************** michael@0: //*** nsDocShellTreeOwner: Object Management michael@0: //***************************************************************************** michael@0: michael@0: nsDocShellTreeOwner::nsDocShellTreeOwner() : michael@0: mWebBrowser(nullptr), michael@0: mTreeOwner(nullptr), michael@0: mPrimaryContentShell(nullptr), michael@0: mWebBrowserChrome(nullptr), michael@0: mOwnerWin(nullptr), michael@0: mOwnerRequestor(nullptr), michael@0: mChromeTooltipListener(nullptr), michael@0: mChromeContextMenuListener(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsDocShellTreeOwner::~nsDocShellTreeOwner() michael@0: { michael@0: RemoveChromeListeners(); michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner::nsISupports michael@0: //***************************************************************************** michael@0: michael@0: NS_IMPL_ADDREF(nsDocShellTreeOwner) michael@0: NS_IMPL_RELEASE(nsDocShellTreeOwner) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner) michael@0: NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner::nsIInterfaceRequestor michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aSink); michael@0: michael@0: if(NS_SUCCEEDED(QueryInterface(aIID, aSink))) michael@0: return NS_OK; michael@0: michael@0: if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) { michael@0: if (mWebBrowserChromeWeak != nullptr) michael@0: return mWebBrowserChromeWeak->QueryReferent(aIID, aSink); michael@0: return mOwnerWin->QueryInterface(aIID, aSink); michael@0: } michael@0: michael@0: if (aIID.Equals(NS_GET_IID(nsIPrompt))) { michael@0: nsIPrompt *prompt; michael@0: EnsurePrompter(); michael@0: prompt = mPrompter; michael@0: if (prompt) { michael@0: NS_ADDREF(prompt); michael@0: *aSink = prompt; michael@0: return NS_OK; michael@0: } michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { michael@0: nsIAuthPrompt *prompt; michael@0: EnsureAuthPrompter(); michael@0: prompt = mAuthPrompter; michael@0: if (prompt) { michael@0: NS_ADDREF(prompt); michael@0: *aSink = prompt; michael@0: return NS_OK; michael@0: } michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: nsCOMPtr req = GetOwnerRequestor(); michael@0: if (req) michael@0: return req->GetInterface(aIID, aSink); michael@0: michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner::nsIDocShellTreeOwner michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, michael@0: nsIDocShellTreeItem* aRequestor, michael@0: nsIDocShellTreeItem* aOriginalRequestor, michael@0: nsIDocShellTreeItem** aFoundItem) michael@0: { michael@0: NS_ENSURE_ARG(aName); michael@0: NS_ENSURE_ARG_POINTER(aFoundItem); michael@0: *aFoundItem = nullptr; // if we don't find one, we return NS_OK and a null result michael@0: nsresult rv; michael@0: michael@0: nsAutoString name(aName); michael@0: michael@0: if (!mWebBrowser) michael@0: return NS_OK; // stymied michael@0: michael@0: /* special cases */ michael@0: if(name.IsEmpty()) michael@0: return NS_OK; michael@0: if(name.LowerCaseEqualsLiteral("_blank")) michael@0: return NS_OK; michael@0: // _main is an IE target which should be case-insensitive but isn't michael@0: // see bug 217886 for details michael@0: // XXXbz what if our browser isn't targetable? We need to handle that somehow. michael@0: if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) { michael@0: *aFoundItem = mWebBrowser->mDocShell; michael@0: NS_IF_ADDREF(*aFoundItem); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!SameCOMIdentity(aRequestor, mWebBrowser->mDocShell)) { michael@0: // This isn't a request coming up from our kid, so check with said kid michael@0: nsISupports* thisSupports = static_cast(this); michael@0: rv = mWebBrowser->mDocShell->FindItemWithName(aName, thisSupports, michael@0: aOriginalRequestor, aFoundItem); michael@0: if (NS_FAILED(rv) || *aFoundItem) { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: // next, if we have a parent and it isn't the requestor, ask it michael@0: if(mTreeOwner) { michael@0: nsCOMPtr reqAsTreeOwner(do_QueryInterface(aRequestor)); michael@0: if (mTreeOwner != reqAsTreeOwner) michael@0: return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShell, michael@0: aOriginalRequestor, aFoundItem); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // finally, failing everything else, search all windows michael@0: return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor, michael@0: aFoundItem); michael@0: } michael@0: michael@0: nsresult michael@0: nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const char16_t* aName, michael@0: nsIDocShellTreeItem* aRequestor, michael@0: nsIDocShellTreeItem* aOriginalRequestor, michael@0: nsIDocShellTreeItem** aFoundItem) michael@0: { michael@0: // search for the item across the list of top-level windows michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (!wwatch) michael@0: return NS_OK; michael@0: michael@0: return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor, michael@0: aFoundItem); michael@0: } michael@0: michael@0: void michael@0: nsDocShellTreeOwner::EnsurePrompter() michael@0: { michael@0: if (mPrompter) michael@0: return; michael@0: michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (wwatch && mWebBrowser) { michael@0: nsCOMPtr domWindow; michael@0: mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); michael@0: if (domWindow) michael@0: wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsDocShellTreeOwner::EnsureAuthPrompter() michael@0: { michael@0: if (mAuthPrompter) michael@0: return; michael@0: michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (wwatch && mWebBrowser) { michael@0: nsCOMPtr domWindow; michael@0: mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); michael@0: if (domWindow) michael@0: wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsDocShellTreeOwner::AddToWatcher() michael@0: { michael@0: if (mWebBrowser) { michael@0: nsCOMPtr domWindow; michael@0: mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); michael@0: if (domWindow) { michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (wwatch) { michael@0: nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); michael@0: if (webBrowserChrome) michael@0: wwatch->AddWindow(domWindow, webBrowserChrome); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsDocShellTreeOwner::RemoveFromWatcher() michael@0: { michael@0: if (mWebBrowser) { michael@0: nsCOMPtr domWindow; michael@0: mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); michael@0: if (domWindow) { michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (wwatch) michael@0: wwatch->RemoveWindow(domWindow); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, michael@0: bool aPrimary, bool aTargetable, michael@0: const nsAString& aID) michael@0: { michael@0: if(mTreeOwner) michael@0: return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, michael@0: aTargetable, aID); michael@0: michael@0: if (aPrimary) michael@0: mPrimaryContentShell = aContentShell; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) michael@0: { michael@0: if(mTreeOwner) michael@0: return mTreeOwner->ContentShellRemoved(aContentShell); michael@0: michael@0: if(mPrimaryContentShell == aContentShell) michael@0: mPrimaryContentShell = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aShell); michael@0: michael@0: if (mTreeOwner) michael@0: return mTreeOwner->GetPrimaryContentShell(aShell); michael@0: michael@0: *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell); michael@0: NS_IF_ADDREF(*aShell); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetContentWindow(JSContext* aCx, michael@0: JS::MutableHandle aVal) michael@0: { michael@0: if (mTreeOwner) michael@0: return mTreeOwner->GetContentWindow(aCx, aVal); michael@0: michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, michael@0: int32_t aCX, int32_t aCY) michael@0: { michael@0: nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); michael@0: michael@0: NS_ENSURE_STATE(mTreeOwner || webBrowserChrome); michael@0: michael@0: if(mTreeOwner) michael@0: return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY); michael@0: michael@0: if(aShellItem == mWebBrowser->mDocShell) michael@0: return webBrowserChrome->SizeBrowserTo(aCX, aCY); michael@0: michael@0: nsCOMPtr webNav(do_QueryInterface(aShellItem)); michael@0: NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr domDocument; michael@0: webNav->GetDocument(getter_AddRefs(domDocument)); michael@0: NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr domElement; michael@0: domDocument->GetDocumentElement(getter_AddRefs(domElement)); michael@0: NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); michael@0: michael@0: // Set the preferred Size michael@0: //XXX michael@0: NS_ERROR("Implement this"); michael@0: /* michael@0: Set the preferred size on the aShellItem. michael@0: */ michael@0: michael@0: nsRefPtr presContext; michael@0: mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext)); michael@0: NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); michael@0: michael@0: nsIPresShell *presShell = presContext->GetPresShell(); michael@0: NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); michael@0: michael@0: NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, michael@0: NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); michael@0: michael@0: nsRect shellArea = presContext->GetVisibleArea(); michael@0: michael@0: int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width); michael@0: int32_t browserCY = presContext->AppUnitsToDevPixels(shellArea.height); michael@0: michael@0: return webBrowserChrome->SizeBrowserTo(browserCX, browserCY); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetPersistence(bool aPersistPosition, michael@0: bool aPersistSize, michael@0: bool aPersistSizeMode) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition, michael@0: bool* aPersistSize, michael@0: bool* aPersistSizeMode) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) michael@0: { michael@0: if(mTreeOwner) { michael@0: mTreeOwner->GetTargetableShellCount(aResult); michael@0: } else { michael@0: *aResult = 0; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner::nsIBaseWindow michael@0: //***************************************************************************** michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow, michael@0: nsIWidget* aParentWidget, int32_t aX, michael@0: int32_t aY, int32_t aCX, int32_t aCY) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::Create() michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::Destroy() michael@0: { michael@0: nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); michael@0: if (webBrowserChrome) michael@0: { michael@0: return webBrowserChrome->DestroyBrowserWindow(); michael@0: } michael@0: michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) michael@0: { michael@0: if (mWebBrowser) { michael@0: return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale); michael@0: } michael@0: michael@0: *aScale = 1.0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, michael@0: aX, aY, 0, 0); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetPosition(int32_t* aX, int32_t* aY) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, michael@0: aX, aY, nullptr, nullptr); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, michael@0: 0, 0, aCX, aCY); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetSize(int32_t* aCX, int32_t* aCY) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, michael@0: nullptr, nullptr, aCX, aCY); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX, michael@0: int32_t aCY, bool aRepaint) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | michael@0: nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, michael@0: aX, aY, aCX, aCY); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX, michael@0: int32_t* aCY) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | michael@0: nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, michael@0: aX, aY, aCX, aCY); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::Repaint(bool aForce) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetSiteWindow(aParentNativeWindow); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle) michael@0: { michael@0: // the nativeHandle should be accessed from nsIXULWindow michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetVisibility(bool* aVisibility) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetVisibility(aVisibility); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetVisibility(bool aVisibility) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetVisibility(aVisibility); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetEnabled(bool *aEnabled) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEnabled); michael@0: *aEnabled = true; michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetEnabled(bool aEnabled) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget) michael@0: { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetFocus() michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetFocus(); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::GetTitle(char16_t** aTitle) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->GetTitle(aTitle); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetTitle(const char16_t* aTitle) michael@0: { michael@0: nsCOMPtr ownerWin = GetOwnerWin(); michael@0: if (ownerWin) michael@0: { michael@0: return ownerWin->SetTitle(aTitle); michael@0: } michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner::nsIWebProgressListener michael@0: //***************************************************************************** michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress, michael@0: nsIRequest* aRequest, michael@0: int32_t aCurSelfProgress, michael@0: int32_t aMaxSelfProgress, michael@0: int32_t aCurTotalProgress, michael@0: int32_t aMaxTotalProgress) michael@0: { michael@0: // In the absence of DOM document creation event, this method is the michael@0: // most convenient place to install the mouse listener on the michael@0: // DOM document. michael@0: return AddChromeListeners(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress, michael@0: nsIRequest* aRequest, michael@0: uint32_t aProgressStateFlags, michael@0: nsresult aStatus) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: nsIURI* aURI, michael@0: uint32_t aFlags) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: nsresult aStatus, michael@0: const char16_t* aMessage) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, michael@0: nsIRequest *aRequest, michael@0: uint32_t state) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner: Helpers michael@0: //***************************************************************************** michael@0: michael@0: //***************************************************************************** michael@0: // nsDocShellTreeOwner: Accessors michael@0: //***************************************************************************** michael@0: michael@0: void michael@0: nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) michael@0: { michael@0: if ( !aWebBrowser ) michael@0: RemoveChromeListeners(); michael@0: if (aWebBrowser != mWebBrowser) { michael@0: mPrompter = 0; michael@0: mAuthPrompter = 0; michael@0: } michael@0: michael@0: mWebBrowser = aWebBrowser; michael@0: } michael@0: michael@0: nsWebBrowser * michael@0: nsDocShellTreeOwner::WebBrowser() michael@0: { michael@0: return mWebBrowser; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) michael@0: { michael@0: if(aTreeOwner) { michael@0: nsCOMPtr webBrowserChrome(do_GetInterface(aTreeOwner)); michael@0: NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); michael@0: NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG); michael@0: mTreeOwner = aTreeOwner; michael@0: } michael@0: else { michael@0: mTreeOwner = nullptr; michael@0: nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); michael@0: if (!webBrowserChrome) michael@0: NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome) michael@0: { michael@0: if(!aWebBrowserChrome) { michael@0: mWebBrowserChrome = nullptr; michael@0: mOwnerWin = nullptr; michael@0: mOwnerRequestor = nullptr; michael@0: mWebBrowserChromeWeak = 0; michael@0: } else { michael@0: nsCOMPtr supportsweak = michael@0: do_QueryInterface(aWebBrowserChrome); michael@0: if (supportsweak) { michael@0: supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak)); michael@0: } else { michael@0: nsCOMPtr ownerWin(do_QueryInterface(aWebBrowserChrome)); michael@0: nsCOMPtr requestor(do_QueryInterface(aWebBrowserChrome)); michael@0: michael@0: // it's ok for ownerWin or requestor to be null. michael@0: mWebBrowserChrome = aWebBrowserChrome; michael@0: mOwnerWin = ownerWin; michael@0: mOwnerRequestor = requestor; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // AddChromeListeners michael@0: // michael@0: // Hook up things to the chrome like context menus and tooltips, if the chrome michael@0: // has implemented the right interfaces. michael@0: // michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::AddChromeListeners() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); michael@0: if (!webBrowserChrome) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // install tooltips michael@0: if ( !mChromeTooltipListener ) { michael@0: nsCOMPtr michael@0: tooltipListener(do_QueryInterface(webBrowserChrome)); michael@0: if ( tooltipListener ) { michael@0: mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, michael@0: webBrowserChrome); michael@0: if ( mChromeTooltipListener ) { michael@0: NS_ADDREF(mChromeTooltipListener); michael@0: rv = mChromeTooltipListener->AddChromeListeners(); michael@0: } michael@0: else michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: michael@0: // install context menus michael@0: if ( !mChromeContextMenuListener ) { michael@0: nsCOMPtr michael@0: contextListener2(do_QueryInterface(webBrowserChrome)); michael@0: nsCOMPtr michael@0: contextListener(do_QueryInterface(webBrowserChrome)); michael@0: if ( contextListener2 || contextListener ) { michael@0: mChromeContextMenuListener = michael@0: new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); michael@0: if ( mChromeContextMenuListener ) { michael@0: NS_ADDREF(mChromeContextMenuListener); michael@0: rv = mChromeContextMenuListener->AddChromeListeners(); michael@0: } michael@0: else michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: michael@0: // register dragover and drop event listeners with the listener manager michael@0: nsCOMPtr target; michael@0: GetDOMEventTarget(mWebBrowser, getter_AddRefs(target)); michael@0: michael@0: EventListenerManager* elmP = target->GetOrCreateListenerManager(); michael@0: if (elmP) { michael@0: elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"), michael@0: TrustedEventsAtSystemGroupBubble()); michael@0: elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"), michael@0: TrustedEventsAtSystemGroupBubble()); michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: } // AddChromeListeners michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::RemoveChromeListeners() michael@0: { michael@0: if ( mChromeTooltipListener ) { michael@0: mChromeTooltipListener->RemoveChromeListeners(); michael@0: NS_RELEASE(mChromeTooltipListener); michael@0: } michael@0: if ( mChromeContextMenuListener ) { michael@0: mChromeContextMenuListener->RemoveChromeListeners(); michael@0: NS_RELEASE(mChromeContextMenuListener); michael@0: } michael@0: michael@0: nsCOMPtr piTarget; michael@0: GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget)); michael@0: if (!piTarget) michael@0: return NS_OK; michael@0: michael@0: EventListenerManager* elmP = piTarget->GetOrCreateListenerManager(); michael@0: if (elmP) michael@0: { michael@0: elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"), michael@0: TrustedEventsAtSystemGroupBubble()); michael@0: elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"), michael@0: TrustedEventsAtSystemGroupBubble()); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: nsCOMPtr dragEvent = do_QueryInterface(aEvent); michael@0: NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG); michael@0: michael@0: bool defaultPrevented; michael@0: aEvent->GetDefaultPrevented(&defaultPrevented); michael@0: if (defaultPrevented) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr handler = do_GetService("@mozilla.org/content/dropped-link-handler;1"); michael@0: if (handler) { michael@0: nsAutoString eventType; michael@0: aEvent->GetType(eventType); michael@0: if (eventType.EqualsLiteral("dragover")) { michael@0: bool canDropLink; michael@0: handler->CanDropLink(dragEvent, false, &canDropLink); michael@0: if (canDropLink) michael@0: aEvent->PreventDefault(); michael@0: } michael@0: else if (eventType.EqualsLiteral("drop")) { michael@0: nsIWebNavigation* webnav = static_cast(mWebBrowser); michael@0: michael@0: nsAutoString link, name; michael@0: if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) { michael@0: if (!link.IsEmpty()) { michael@0: webnav->LoadURI(link.get(), 0, nullptr, nullptr, nullptr); michael@0: } michael@0: } michael@0: else { michael@0: aEvent->StopPropagation(); michael@0: aEvent->PreventDefault(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsDocShellTreeOwner::GetWebBrowserChrome() michael@0: { michael@0: nsCOMPtr chrome; michael@0: if (mWebBrowserChromeWeak) { michael@0: chrome = do_QueryReferent(mWebBrowserChromeWeak); michael@0: } else if (mWebBrowserChrome) { michael@0: chrome = mWebBrowserChrome; michael@0: } michael@0: return chrome.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsDocShellTreeOwner::GetOwnerWin() michael@0: { michael@0: nsCOMPtr win; michael@0: if (mWebBrowserChromeWeak) { michael@0: win = do_QueryReferent(mWebBrowserChromeWeak); michael@0: } else if (mOwnerWin) { michael@0: win = mOwnerWin; michael@0: } michael@0: return win.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsDocShellTreeOwner::GetOwnerRequestor() michael@0: { michael@0: nsCOMPtr req; michael@0: if (mWebBrowserChromeWeak) { michael@0: req = do_QueryReferent(mWebBrowserChromeWeak); michael@0: } else if (mOwnerRequestor) { michael@0: req = mOwnerRequestor; michael@0: } michael@0: return req.forget(); michael@0: } michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // DefaultTooltipTextProvider michael@0: michael@0: class DefaultTooltipTextProvider MOZ_FINAL : public nsITooltipTextProvider michael@0: { michael@0: public: michael@0: DefaultTooltipTextProvider(); michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSITOOLTIPTEXTPROVIDER michael@0: michael@0: protected: michael@0: nsCOMPtr mTag_dialog; michael@0: nsCOMPtr mTag_dialogheader; michael@0: nsCOMPtr mTag_window; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider) michael@0: michael@0: DefaultTooltipTextProvider::DefaultTooltipTextProvider() michael@0: { michael@0: // There are certain element types which we don't want to use michael@0: // as tool tip text. michael@0: mTag_dialog = do_GetAtom("dialog"); michael@0: mTag_dialogheader = do_GetAtom("dialogheader"); michael@0: mTag_window = do_GetAtom("window"); michael@0: } michael@0: michael@0: // michael@0: // UseSVGTitle michael@0: // michael@0: // A helper routine that determines whether we're still interested michael@0: // in SVG titles. We need to stop at the SVG root element that michael@0: // has a document node parent michael@0: // michael@0: static bool michael@0: UseSVGTitle(nsIDOMElement *currElement) michael@0: { michael@0: nsCOMPtr element(do_QueryInterface(currElement)); michael@0: if (!element || !element->IsSVG() || !element->GetParentNode()) michael@0: return false; michael@0: michael@0: return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE; michael@0: } michael@0: michael@0: /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */ michael@0: NS_IMETHODIMP michael@0: DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, michael@0: bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: NS_ENSURE_ARG_POINTER(aText); michael@0: michael@0: nsString outText; michael@0: michael@0: nsCOMPtr node = do_QueryInterface(aNode); michael@0: michael@0: bool lookingForSVGTitle = true; michael@0: bool found = false; michael@0: nsCOMPtr current ( aNode ); michael@0: michael@0: // If the element implement the constraint validation API and has no title, michael@0: // show the validation message, if any. michael@0: nsCOMPtr cvElement = do_QueryInterface(current); michael@0: if (cvElement) { michael@0: nsCOMPtr content = do_QueryInterface(cvElement); michael@0: nsCOMPtr titleAtom = do_GetAtom("title"); michael@0: michael@0: nsCOMPtr formControl = do_QueryInterface(content); michael@0: bool formHasNoValidate = false; michael@0: mozilla::dom::Element* form = formControl->GetFormElement(); michael@0: if (form) { michael@0: nsCOMPtr noValidateAtom = do_GetAtom("novalidate"); michael@0: formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom); michael@0: } michael@0: michael@0: if (!content->HasAttr(kNameSpaceID_None, titleAtom) && michael@0: !formHasNoValidate) { michael@0: cvElement->GetValidationMessage(outText); michael@0: found = !outText.IsEmpty(); michael@0: } michael@0: } michael@0: michael@0: while ( !found && current ) { michael@0: nsCOMPtr currElement ( do_QueryInterface(current) ); michael@0: if ( currElement ) { michael@0: nsCOMPtr content(do_QueryInterface(currElement)); michael@0: if (content) { michael@0: nsIAtom *tagAtom = content->Tag(); michael@0: if (tagAtom != mTag_dialog && michael@0: tagAtom != mTag_dialogheader && michael@0: tagAtom != mTag_window) { michael@0: // first try the normal title attribute... michael@0: currElement->GetAttribute(NS_LITERAL_STRING("title"), outText); michael@0: if ( outText.Length() ) michael@0: found = true; michael@0: else { michael@0: // ...ok, that didn't work, try it in the XLink namespace michael@0: NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink"); michael@0: nsCOMPtr linkContent(do_QueryInterface(currElement)); michael@0: if (linkContent) { michael@0: nsCOMPtr uri(linkContent->GetURIExternal()); michael@0: if (uri) { michael@0: currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText); michael@0: if ( outText.Length() ) michael@0: found = true; michael@0: } michael@0: } michael@0: else { michael@0: if (lookingForSVGTitle) { michael@0: lookingForSVGTitle = UseSVGTitle(currElement); michael@0: } michael@0: if (lookingForSVGTitle) { michael@0: nsINodeList* childNodes = node->ChildNodes(); michael@0: uint32_t childNodeCount = childNodes->Length(); michael@0: for (uint32_t i = 0; i < childNodeCount; i++) { michael@0: nsIContent* child = childNodes->Item(i); michael@0: if (child->IsSVG(nsGkAtoms::title)) { michael@0: static_cast(child)->GetTextContent(outText); michael@0: if ( outText.Length() ) michael@0: found = true; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // not found here, walk up to the parent and keep trying michael@0: if ( !found ) { michael@0: nsCOMPtr temp ( current ); michael@0: temp->GetParentNode(getter_AddRefs(current)); michael@0: } michael@0: } // while not found michael@0: michael@0: *_retval = found; michael@0: *aText = (found) ? ToNewUnicode(outText) : nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener) michael@0: michael@0: // michael@0: // ChromeTooltipListener ctor michael@0: // michael@0: michael@0: ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser, michael@0: nsIWebBrowserChrome* inChrome) michael@0: : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome), michael@0: mTooltipListenerInstalled(false), michael@0: mMouseClientX(0), mMouseClientY(0), michael@0: mShowingTooltip(false) michael@0: { michael@0: mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID); michael@0: if (!mTooltipTextProvider) { michael@0: nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider; michael@0: mTooltipTextProvider = do_QueryInterface(pProvider); michael@0: } michael@0: } // ctor michael@0: michael@0: michael@0: // michael@0: // ChromeTooltipListener dtor michael@0: // michael@0: ChromeTooltipListener::~ChromeTooltipListener() michael@0: { michael@0: michael@0: } // dtor michael@0: michael@0: michael@0: // michael@0: // AddChromeListeners michael@0: // michael@0: // Hook up things to the chrome like context menus and tooltips, if the chrome michael@0: // has implemented the right interfaces. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::AddChromeListeners() michael@0: { michael@0: if (!mEventTarget) michael@0: GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); michael@0: michael@0: // Register the appropriate events for tooltips, but only if michael@0: // the embedding chrome cares. michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); michael@0: if ( tooltipListener && !mTooltipListenerInstalled ) { michael@0: rv = AddTooltipListener(); michael@0: if ( NS_FAILED(rv) ) michael@0: return rv; michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: } // AddChromeListeners michael@0: michael@0: michael@0: // michael@0: // AddTooltipListener michael@0: // michael@0: // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit, michael@0: // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track michael@0: // of how many succeed so we can clean up correctly in Release(). michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::AddTooltipListener() michael@0: { michael@0: if (mEventTarget) { michael@0: nsresult rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), michael@0: this, false, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, michael@0: false, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, michael@0: false, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, michael@0: false, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mTooltipListenerInstalled = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // RemoveChromeListeners michael@0: // michael@0: // Unsubscribe from the various things we've hooked up to the window root. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::RemoveChromeListeners ( ) michael@0: { michael@0: HideTooltip(); michael@0: michael@0: if ( mTooltipListenerInstalled ) michael@0: RemoveTooltipListener(); michael@0: michael@0: mEventTarget = nullptr; michael@0: michael@0: // it really doesn't matter if these fail... michael@0: return NS_OK; michael@0: michael@0: } // RemoveChromeTooltipListeners michael@0: michael@0: michael@0: michael@0: // michael@0: // RemoveTooltipListener michael@0: // michael@0: // Unsubscribe from all the various tooltip events that we were listening to michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::RemoveTooltipListener() michael@0: { michael@0: if (mEventTarget) { michael@0: nsresult rv = michael@0: mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, michael@0: false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), michael@0: this, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, michael@0: false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), michael@0: this, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mTooltipListenerInstalled = false; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: nsAutoString eventType; michael@0: aEvent->GetType(eventType); michael@0: michael@0: if (eventType.EqualsLiteral("keydown") || michael@0: eventType.EqualsLiteral("mousedown") || michael@0: eventType.EqualsLiteral("mouseout")) michael@0: return HideTooltip(); michael@0: if (eventType.EqualsLiteral("mousemove")) michael@0: return MouseMove(aEvent); michael@0: michael@0: NS_ERROR("Unexpected event type"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // MouseMove michael@0: // michael@0: // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the michael@0: // timer fires, we cache the node in |mPossibleTooltipNode|. michael@0: // michael@0: nsresult michael@0: ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) michael@0: { michael@0: nsCOMPtr mouseEvent ( do_QueryInterface(aMouseEvent) ); michael@0: if (!mouseEvent) michael@0: return NS_OK; michael@0: michael@0: // stash the coordinates of the event so that we can still get back to it from within the michael@0: // timer callback. On win32, we'll get a MouseMove event even when a popup goes away -- michael@0: // even when the mouse doesn't change position! To get around this, we make sure the michael@0: // mouse has really moved before proceeding. michael@0: int32_t newMouseX, newMouseY; michael@0: mouseEvent->GetClientX(&newMouseX); michael@0: mouseEvent->GetClientY(&newMouseY); michael@0: if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY ) michael@0: return NS_OK; michael@0: mMouseClientX = newMouseX; mMouseClientY = newMouseY; michael@0: mouseEvent->GetScreenX(&mMouseScreenX); michael@0: mouseEvent->GetScreenY(&mMouseScreenY); michael@0: michael@0: // We want to close the tip if it is being displayed and the mouse moves. Recall michael@0: // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse michael@0: // moves, we want to make sure we reset the timer to show it, so that the delay michael@0: // is from when the mouse stops moving, not when it enters the element. michael@0: if ( mShowingTooltip ) michael@0: return HideTooltip(); michael@0: if ( mTooltipTimer ) michael@0: mTooltipTimer->Cancel(); michael@0: michael@0: mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: if ( mTooltipTimer ) { michael@0: nsCOMPtr eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget(); michael@0: if ( eventTarget ) michael@0: mPossibleTooltipNode = do_QueryInterface(eventTarget); michael@0: if ( mPossibleTooltipNode ) { michael@0: nsresult rv = michael@0: mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this, michael@0: LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500), michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: if (NS_FAILED(rv)) michael@0: mPossibleTooltipNode = nullptr; michael@0: } michael@0: } michael@0: else michael@0: NS_WARNING ( "Could not create a timer for tooltip tracking" ); michael@0: michael@0: return NS_OK; michael@0: michael@0: } // MouseMove michael@0: michael@0: michael@0: // michael@0: // ShowTooltip michael@0: // michael@0: // Tell the registered chrome that they should show the tooltip michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords, michael@0: const nsAString & inTipText) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // do the work to call the client michael@0: nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); michael@0: if ( tooltipListener ) { michael@0: rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); michael@0: if ( NS_SUCCEEDED(rv) ) michael@0: mShowingTooltip = true; michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: } // ShowTooltip michael@0: michael@0: michael@0: // michael@0: // HideTooltip michael@0: // michael@0: // Tell the registered chrome that they should rollup the tooltip michael@0: // NOTE: This routine is safe to call even if the popup is already closed. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeTooltipListener::HideTooltip() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // shut down the relevant timers michael@0: if ( mTooltipTimer ) { michael@0: mTooltipTimer->Cancel(); michael@0: mTooltipTimer = nullptr; michael@0: // release tooltip target michael@0: mPossibleTooltipNode = nullptr; michael@0: } michael@0: if ( mAutoHideTimer ) { michael@0: mAutoHideTimer->Cancel(); michael@0: mAutoHideTimer = nullptr; michael@0: } michael@0: michael@0: // if we're showing the tip, tell the chrome to hide it michael@0: if ( mShowingTooltip ) { michael@0: nsCOMPtr tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); michael@0: if ( tooltipListener ) { michael@0: rv = tooltipListener->OnHideTooltip ( ); michael@0: if ( NS_SUCCEEDED(rv) ) michael@0: mShowingTooltip = false; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: michael@0: } // HideTooltip michael@0: michael@0: michael@0: // michael@0: // sTooltipCallback michael@0: // michael@0: // A timer callback, fired when the mouse has hovered inside of a frame for the michael@0: // appropriate amount of time. Getting to this point means that we should show the michael@0: // tooltip, but only after we determine there is an appropriate TITLE element. michael@0: // michael@0: // This relies on certain things being cached into the |aChromeTooltipListener| object passed to michael@0: // us by the timer: michael@0: // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX) michael@0: // -- the dom node the user hovered over (mPossibleTooltipNode) michael@0: // michael@0: void michael@0: ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, michael@0: void *aChromeTooltipListener) michael@0: { michael@0: ChromeTooltipListener* self = static_cast michael@0: (aChromeTooltipListener); michael@0: if ( self && self->mPossibleTooltipNode ){ michael@0: // The actual coordinates we want to put the tooltip at are relative to the michael@0: // toplevel docshell of our mWebBrowser. We know what the screen michael@0: // coordinates of the mouse event were, which means we just need the screen michael@0: // coordinates of the docshell. Unfortunately, there is no good way to michael@0: // find those short of groveling for the presentation in that docshell and michael@0: // finding the screen coords of its toplevel widget... michael@0: nsCOMPtr docShell = michael@0: do_GetInterface(static_cast(self->mWebBrowser)); michael@0: nsCOMPtr shell; michael@0: if (docShell) { michael@0: shell = docShell->GetPresShell(); michael@0: } michael@0: michael@0: nsIWidget* widget = nullptr; michael@0: if (shell) { michael@0: nsViewManager* vm = shell->GetViewManager(); michael@0: if (vm) { michael@0: nsView* view = vm->GetRootView(); michael@0: if (view) { michael@0: nsPoint offset; michael@0: widget = view->GetNearestWidget(&offset); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!widget) { michael@0: // release tooltip target if there is one, NO MATTER WHAT michael@0: self->mPossibleTooltipNode = nullptr; michael@0: return; michael@0: } michael@0: michael@0: // if there is text associated with the node, show the tip and fire michael@0: // off a timer to auto-hide it. michael@0: michael@0: nsXPIDLString tooltipText; michael@0: if (self->mTooltipTextProvider) { michael@0: bool textFound = false; michael@0: michael@0: self->mTooltipTextProvider->GetNodeText( michael@0: self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound); michael@0: michael@0: if (textFound) { michael@0: nsString tipText(tooltipText); michael@0: self->CreateAutoHideTimer(); michael@0: nsIntPoint screenDot = widget->WidgetToScreenOffset(); michael@0: self->ShowTooltip (self->mMouseScreenX - screenDot.x, michael@0: self->mMouseScreenY - screenDot.y, michael@0: tipText); michael@0: } michael@0: } michael@0: michael@0: // release tooltip target if there is one, NO MATTER WHAT michael@0: self->mPossibleTooltipNode = nullptr; michael@0: } // if "self" data valid michael@0: michael@0: } // sTooltipCallback michael@0: michael@0: michael@0: // michael@0: // CreateAutoHideTimer michael@0: // michael@0: // Create a new timer to see if we should auto-hide. It's ok if this fails. michael@0: // michael@0: void michael@0: ChromeTooltipListener::CreateAutoHideTimer() michael@0: { michael@0: // just to be anal (er, safe) michael@0: if ( mAutoHideTimer ) { michael@0: mAutoHideTimer->Cancel(); michael@0: mAutoHideTimer = nullptr; michael@0: } michael@0: michael@0: mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: if ( mAutoHideTimer ) michael@0: mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: michael@0: } // CreateAutoHideTimer michael@0: michael@0: michael@0: // michael@0: // sAutoHideCallback michael@0: // michael@0: // This fires after a tooltip has been open for a certain length of time. Just tell michael@0: // the listener to close the popup. We don't have to worry, because HideTooltip() can michael@0: // be called multiple times, even if the tip has already been closed. michael@0: // michael@0: void michael@0: ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener) michael@0: { michael@0: ChromeTooltipListener* self = static_cast(aListener); michael@0: if ( self ) michael@0: self->HideTooltip(); michael@0: michael@0: // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup(); michael@0: michael@0: } // sAutoHideCallback michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) michael@0: michael@0: michael@0: // michael@0: // ChromeTooltipListener ctor michael@0: // michael@0: ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) michael@0: : mContextMenuListenerInstalled(false), michael@0: mWebBrowser(inBrowser), michael@0: mWebBrowserChrome(inChrome) michael@0: { michael@0: } // ctor michael@0: michael@0: michael@0: // michael@0: // ChromeTooltipListener dtor michael@0: // michael@0: ChromeContextMenuListener::~ChromeContextMenuListener() michael@0: { michael@0: } // dtor michael@0: michael@0: michael@0: // michael@0: // AddContextMenuListener michael@0: // michael@0: // Subscribe to the events that will allow us to track context menus. Bascially, this michael@0: // is just the context-menu DOM event. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeContextMenuListener::AddContextMenuListener() michael@0: { michael@0: if (mEventTarget) { michael@0: nsresult rv = michael@0: mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, michael@0: false, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mContextMenuListenerInstalled = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // RemoveContextMenuListener michael@0: // michael@0: // Unsubscribe from all the various context menu events that we were listening to. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeContextMenuListener::RemoveContextMenuListener() michael@0: { michael@0: if (mEventTarget) { michael@0: nsresult rv = michael@0: mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, michael@0: false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mContextMenuListenerInstalled = false; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // AddChromeListeners michael@0: // michael@0: // Hook up things to the chrome like context menus and tooltips, if the chrome michael@0: // has implemented the right interfaces. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeContextMenuListener::AddChromeListeners() michael@0: { michael@0: if (!mEventTarget) michael@0: GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); michael@0: michael@0: // Register the appropriate events for context menus, but only if michael@0: // the embedding chrome cares. michael@0: nsresult rv = NS_OK; michael@0: michael@0: nsCOMPtr contextListener2 ( do_QueryInterface(mWebBrowserChrome) ); michael@0: nsCOMPtr contextListener ( do_QueryInterface(mWebBrowserChrome) ); michael@0: if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled ) michael@0: rv = AddContextMenuListener(); michael@0: michael@0: return rv; michael@0: michael@0: } // AddChromeListeners michael@0: michael@0: michael@0: // michael@0: // RemoveChromeListeners michael@0: // michael@0: // Unsubscribe from the various things we've hooked up to the window root. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeContextMenuListener::RemoveChromeListeners() michael@0: { michael@0: if ( mContextMenuListenerInstalled ) michael@0: RemoveContextMenuListener(); michael@0: michael@0: mEventTarget = nullptr; michael@0: michael@0: // it really doesn't matter if these fail... michael@0: return NS_OK; michael@0: michael@0: } // RemoveChromeTooltipListeners michael@0: michael@0: michael@0: michael@0: // michael@0: // ContextMenu michael@0: // michael@0: // We're on call to show the context menu. Dig around in the DOM to michael@0: // find the type of object we're dealing with and notify the front michael@0: // end chrome. michael@0: // michael@0: NS_IMETHODIMP michael@0: ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) michael@0: { michael@0: nsCOMPtr mouseEvent = do_QueryInterface(aMouseEvent); michael@0: NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED); michael@0: michael@0: bool isDefaultPrevented = false; michael@0: aMouseEvent->GetDefaultPrevented(&isDefaultPrevented); michael@0: if (isDefaultPrevented) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr targetNode = aMouseEvent->InternalDOMEvent()->GetTarget(); michael@0: if (!targetNode) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsCOMPtr targetDOMnode; michael@0: nsCOMPtr node = do_QueryInterface(targetNode); michael@0: if (!node) michael@0: return NS_OK; michael@0: michael@0: // Stop the context menu event going to other windows (bug 78396) michael@0: aMouseEvent->PreventDefault(); michael@0: michael@0: // If the listener is a nsIContextMenuListener2, create the info object michael@0: nsCOMPtr menuListener2(do_QueryInterface(mWebBrowserChrome)); michael@0: nsContextMenuInfo *menuInfoImpl = nullptr; michael@0: nsCOMPtr menuInfo; michael@0: if (menuListener2) { michael@0: menuInfoImpl = new nsContextMenuInfo; michael@0: menuInfo = menuInfoImpl; michael@0: } michael@0: michael@0: uint32_t flags = nsIContextMenuListener::CONTEXT_NONE; michael@0: uint32_t flags2 = nsIContextMenuListener2::CONTEXT_NONE; michael@0: michael@0: // XXX test for selected text michael@0: michael@0: uint16_t nodeType; michael@0: nsresult res = node->GetNodeType(&nodeType); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: michael@0: // First, checks for nodes that never have children. michael@0: if (nodeType == nsIDOMNode::ELEMENT_NODE) { michael@0: nsCOMPtr content(do_QueryInterface(node)); michael@0: if (content) { michael@0: nsCOMPtr imgUri; michael@0: content->GetCurrentURI(getter_AddRefs(imgUri)); michael@0: if (imgUri) { michael@0: flags |= nsIContextMenuListener::CONTEXT_IMAGE; michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE; michael@0: targetDOMnode = node; michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr formControl(do_QueryInterface(node)); michael@0: if (formControl) { michael@0: if (formControl->GetType() == NS_FORM_TEXTAREA) { michael@0: flags |= nsIContextMenuListener::CONTEXT_TEXT; michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; michael@0: targetDOMnode = node; michael@0: } else { michael@0: nsCOMPtr inputElement(do_QueryInterface(formControl)); michael@0: if (inputElement) { michael@0: flags |= nsIContextMenuListener::CONTEXT_INPUT; michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_INPUT; michael@0: michael@0: if (menuListener2) { michael@0: if (formControl->IsSingleLineTextControl(false)) { michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; michael@0: } michael@0: } michael@0: michael@0: targetDOMnode = node; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // always consume events for plugins and Java who may throw their michael@0: // own context menus but not for image objects. Document objects michael@0: // will never be targets or ancestors of targets, so that's OK. michael@0: nsCOMPtr objectElement; michael@0: if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) michael@0: objectElement = do_QueryInterface(node); michael@0: nsCOMPtr embedElement(do_QueryInterface(node)); michael@0: nsCOMPtr appletElement(do_QueryInterface(node)); michael@0: michael@0: if (objectElement || embedElement || appletElement) michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Bubble out, looking for items of interest michael@0: do { michael@0: uint16_t nodeType; michael@0: res = node->GetNodeType(&nodeType); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: michael@0: if (nodeType == nsIDOMNode::ELEMENT_NODE) { michael@0: michael@0: // Test if the element has an associated link michael@0: nsCOMPtr element(do_QueryInterface(node)); michael@0: michael@0: bool hasAttr = false; michael@0: res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); michael@0: michael@0: if (NS_SUCCEEDED(res) && hasAttr) michael@0: { michael@0: flags |= nsIContextMenuListener::CONTEXT_LINK; michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_LINK; michael@0: if (!targetDOMnode) michael@0: targetDOMnode = node; michael@0: if (menuInfoImpl) michael@0: menuInfoImpl->SetAssociatedLink(node); michael@0: break; // exit do-while michael@0: } michael@0: } michael@0: michael@0: // walk-up-the-tree michael@0: nsCOMPtr parentNode; michael@0: node->GetParentNode(getter_AddRefs(parentNode)); michael@0: node = parentNode; michael@0: } while (node); michael@0: michael@0: if (!flags && !flags2) { michael@0: // We found nothing of interest so far, check if we michael@0: // have at least an html document. michael@0: nsCOMPtr document; michael@0: node = do_QueryInterface(targetNode); michael@0: node->GetOwnerDocument(getter_AddRefs(document)); michael@0: nsCOMPtr htmlDocument(do_QueryInterface(document)); michael@0: if (htmlDocument) { michael@0: flags |= nsIContextMenuListener::CONTEXT_DOCUMENT; michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT; michael@0: targetDOMnode = node; michael@0: if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) { michael@0: // check if this is a background image that the user was trying to click on michael@0: // and if the listener is ready for that (only nsIContextMenuListener2 and up) michael@0: if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) { michael@0: flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE; michael@0: // For the embedder to get the correct background image michael@0: // targetDOMnode must point to the original node. michael@0: targetDOMnode = do_QueryInterface(targetNode); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // we need to cache the event target into the focus controller's popupNode michael@0: // so we can get at it later from command code, etc.: michael@0: michael@0: // get the dom window michael@0: nsCOMPtr win; michael@0: res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win)); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: NS_ENSURE_TRUE(win, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr window(do_QueryInterface(win)); michael@0: NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); michael@0: nsCOMPtr root = window->GetTopWindowRoot(); michael@0: NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); michael@0: if (root) { michael@0: // set the window root's popup node to the event target michael@0: root->SetPopupNode(targetDOMnode); michael@0: } michael@0: michael@0: // Tell the listener all about the event michael@0: if ( menuListener2 ) { michael@0: menuInfoImpl->SetMouseEvent(aMouseEvent); michael@0: menuInfoImpl->SetDOMNode(targetDOMnode); michael@0: menuListener2->OnShowContextMenu(flags2, menuInfo); michael@0: } michael@0: else { michael@0: nsCOMPtr menuListener(do_QueryInterface(mWebBrowserChrome)); michael@0: if ( menuListener ) michael@0: menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode); michael@0: } michael@0: michael@0: return NS_OK; michael@0: michael@0: } // MouseDown