1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1825 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// Local Includes 1.10 +#include "nsDocShellTreeOwner.h" 1.11 +#include "nsWebBrowser.h" 1.12 + 1.13 +// Helper Classes 1.14 +#include "nsStyleCoord.h" 1.15 +#include "nsSize.h" 1.16 +#include "nsHTMLReflowState.h" 1.17 +#include "nsIServiceManager.h" 1.18 +#include "nsComponentManagerUtils.h" 1.19 +#include "nsXPIDLString.h" 1.20 +#include "nsIAtom.h" 1.21 +#include "nsReadableUtils.h" 1.22 +#include "nsUnicharUtils.h" 1.23 +#include "nsISimpleEnumerator.h" 1.24 +#include "mozilla/LookAndFeel.h" 1.25 + 1.26 +// Interfaces needed to be included 1.27 +#include "nsPresContext.h" 1.28 +#include "nsIContextMenuListener.h" 1.29 +#include "nsIContextMenuListener2.h" 1.30 +#include "nsITooltipListener.h" 1.31 +#include "nsIDOMNode.h" 1.32 +#include "nsIDOMNodeList.h" 1.33 +#include "nsIDOMDocument.h" 1.34 +#include "nsIDOMDocumentType.h" 1.35 +#include "nsIDOMElement.h" 1.36 +#include "Link.h" 1.37 +#include "mozilla/dom/Element.h" 1.38 +#include "mozilla/dom/SVGTitleElement.h" 1.39 +#include "nsIDOMEvent.h" 1.40 +#include "nsIDOMMouseEvent.h" 1.41 +#include "nsIFormControl.h" 1.42 +#include "nsIDOMHTMLInputElement.h" 1.43 +#include "nsIDOMHTMLTextAreaElement.h" 1.44 +#include "nsIDOMHTMLHtmlElement.h" 1.45 +#include "nsIDOMHTMLAppletElement.h" 1.46 +#include "nsIDOMHTMLObjectElement.h" 1.47 +#include "nsIDOMHTMLEmbedElement.h" 1.48 +#include "nsIDOMHTMLDocument.h" 1.49 +#include "nsIImageLoadingContent.h" 1.50 +#include "nsIWebNavigation.h" 1.51 +#include "nsIDOMHTMLElement.h" 1.52 +#include "nsIPresShell.h" 1.53 +#include "nsPIDOMWindow.h" 1.54 +#include "nsPIWindowRoot.h" 1.55 +#include "nsIDOMWindowCollection.h" 1.56 +#include "nsIWindowWatcher.h" 1.57 +#include "nsPIWindowWatcher.h" 1.58 +#include "nsIPrompt.h" 1.59 +#include "nsRect.h" 1.60 +#include "nsIWebBrowserChromeFocus.h" 1.61 +#include "nsIContent.h" 1.62 +#include "imgIContainer.h" 1.63 +#include "nsContextMenuInfo.h" 1.64 +#include "nsPresContext.h" 1.65 +#include "nsViewManager.h" 1.66 +#include "nsView.h" 1.67 +#include "nsIDOMDragEvent.h" 1.68 +#include "nsIConstraintValidation.h" 1.69 +#include "mozilla/Attributes.h" 1.70 +#include "mozilla/EventListenerManager.h" 1.71 +#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() 1.72 + 1.73 +using namespace mozilla; 1.74 +using namespace mozilla::dom; 1.75 + 1.76 +// 1.77 +// GetEventReceiver 1.78 +// 1.79 +// A helper routine that navigates the tricky path from a |nsWebBrowser| to 1.80 +// a |EventTarget| via the window root and chrome event handler. 1.81 +// 1.82 +static nsresult 1.83 +GetDOMEventTarget(nsWebBrowser* inBrowser, EventTarget** aTarget) 1.84 +{ 1.85 + NS_ENSURE_ARG_POINTER(inBrowser); 1.86 + 1.87 + nsCOMPtr<nsIDOMWindow> domWindow; 1.88 + inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); 1.89 + NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); 1.90 + 1.91 + nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow); 1.92 + NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE); 1.93 + nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot(); 1.94 + NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE); 1.95 + nsCOMPtr<EventTarget> target = 1.96 + rootWindow->GetChromeEventHandler(); 1.97 + NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); 1.98 + target.forget(aTarget); 1.99 + 1.100 + return NS_OK; 1.101 +} 1.102 + 1.103 + 1.104 +//***************************************************************************** 1.105 +//*** nsDocShellTreeOwner: Object Management 1.106 +//***************************************************************************** 1.107 + 1.108 +nsDocShellTreeOwner::nsDocShellTreeOwner() : 1.109 + mWebBrowser(nullptr), 1.110 + mTreeOwner(nullptr), 1.111 + mPrimaryContentShell(nullptr), 1.112 + mWebBrowserChrome(nullptr), 1.113 + mOwnerWin(nullptr), 1.114 + mOwnerRequestor(nullptr), 1.115 + mChromeTooltipListener(nullptr), 1.116 + mChromeContextMenuListener(nullptr) 1.117 +{ 1.118 +} 1.119 + 1.120 +nsDocShellTreeOwner::~nsDocShellTreeOwner() 1.121 +{ 1.122 + RemoveChromeListeners(); 1.123 +} 1.124 + 1.125 +//***************************************************************************** 1.126 +// nsDocShellTreeOwner::nsISupports 1.127 +//***************************************************************************** 1.128 + 1.129 +NS_IMPL_ADDREF(nsDocShellTreeOwner) 1.130 +NS_IMPL_RELEASE(nsDocShellTreeOwner) 1.131 + 1.132 +NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner) 1.133 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner) 1.134 + NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner) 1.135 + NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) 1.136 + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) 1.137 + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) 1.138 + NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) 1.139 + NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner) 1.140 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.141 +NS_INTERFACE_MAP_END 1.142 + 1.143 +//***************************************************************************** 1.144 +// nsDocShellTreeOwner::nsIInterfaceRequestor 1.145 +//***************************************************************************** 1.146 + 1.147 +NS_IMETHODIMP 1.148 +nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) 1.149 +{ 1.150 + NS_ENSURE_ARG_POINTER(aSink); 1.151 + 1.152 + if(NS_SUCCEEDED(QueryInterface(aIID, aSink))) 1.153 + return NS_OK; 1.154 + 1.155 + if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) { 1.156 + if (mWebBrowserChromeWeak != nullptr) 1.157 + return mWebBrowserChromeWeak->QueryReferent(aIID, aSink); 1.158 + return mOwnerWin->QueryInterface(aIID, aSink); 1.159 + } 1.160 + 1.161 + if (aIID.Equals(NS_GET_IID(nsIPrompt))) { 1.162 + nsIPrompt *prompt; 1.163 + EnsurePrompter(); 1.164 + prompt = mPrompter; 1.165 + if (prompt) { 1.166 + NS_ADDREF(prompt); 1.167 + *aSink = prompt; 1.168 + return NS_OK; 1.169 + } 1.170 + return NS_NOINTERFACE; 1.171 + } 1.172 + 1.173 + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { 1.174 + nsIAuthPrompt *prompt; 1.175 + EnsureAuthPrompter(); 1.176 + prompt = mAuthPrompter; 1.177 + if (prompt) { 1.178 + NS_ADDREF(prompt); 1.179 + *aSink = prompt; 1.180 + return NS_OK; 1.181 + } 1.182 + return NS_NOINTERFACE; 1.183 + } 1.184 + 1.185 + nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor(); 1.186 + if (req) 1.187 + return req->GetInterface(aIID, aSink); 1.188 + 1.189 + return NS_NOINTERFACE; 1.190 +} 1.191 + 1.192 +//***************************************************************************** 1.193 +// nsDocShellTreeOwner::nsIDocShellTreeOwner 1.194 +//***************************************************************************** 1.195 + 1.196 +NS_IMETHODIMP 1.197 +nsDocShellTreeOwner::FindItemWithName(const char16_t* aName, 1.198 + nsIDocShellTreeItem* aRequestor, 1.199 + nsIDocShellTreeItem* aOriginalRequestor, 1.200 + nsIDocShellTreeItem** aFoundItem) 1.201 +{ 1.202 + NS_ENSURE_ARG(aName); 1.203 + NS_ENSURE_ARG_POINTER(aFoundItem); 1.204 + *aFoundItem = nullptr; // if we don't find one, we return NS_OK and a null result 1.205 + nsresult rv; 1.206 + 1.207 + nsAutoString name(aName); 1.208 + 1.209 + if (!mWebBrowser) 1.210 + return NS_OK; // stymied 1.211 + 1.212 + /* special cases */ 1.213 + if(name.IsEmpty()) 1.214 + return NS_OK; 1.215 + if(name.LowerCaseEqualsLiteral("_blank")) 1.216 + return NS_OK; 1.217 + // _main is an IE target which should be case-insensitive but isn't 1.218 + // see bug 217886 for details 1.219 + // XXXbz what if our browser isn't targetable? We need to handle that somehow. 1.220 + if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) { 1.221 + *aFoundItem = mWebBrowser->mDocShell; 1.222 + NS_IF_ADDREF(*aFoundItem); 1.223 + return NS_OK; 1.224 + } 1.225 + 1.226 + if (!SameCOMIdentity(aRequestor, mWebBrowser->mDocShell)) { 1.227 + // This isn't a request coming up from our kid, so check with said kid 1.228 + nsISupports* thisSupports = static_cast<nsIDocShellTreeOwner*>(this); 1.229 + rv = mWebBrowser->mDocShell->FindItemWithName(aName, thisSupports, 1.230 + aOriginalRequestor, aFoundItem); 1.231 + if (NS_FAILED(rv) || *aFoundItem) { 1.232 + return rv; 1.233 + } 1.234 + } 1.235 + 1.236 + // next, if we have a parent and it isn't the requestor, ask it 1.237 + if(mTreeOwner) { 1.238 + nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor)); 1.239 + if (mTreeOwner != reqAsTreeOwner) 1.240 + return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShell, 1.241 + aOriginalRequestor, aFoundItem); 1.242 + return NS_OK; 1.243 + } 1.244 + 1.245 + // finally, failing everything else, search all windows 1.246 + return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor, 1.247 + aFoundItem); 1.248 +} 1.249 + 1.250 +nsresult 1.251 +nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const char16_t* aName, 1.252 + nsIDocShellTreeItem* aRequestor, 1.253 + nsIDocShellTreeItem* aOriginalRequestor, 1.254 + nsIDocShellTreeItem** aFoundItem) 1.255 +{ 1.256 + // search for the item across the list of top-level windows 1.257 + nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); 1.258 + if (!wwatch) 1.259 + return NS_OK; 1.260 + 1.261 + return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor, 1.262 + aFoundItem); 1.263 +} 1.264 + 1.265 +void 1.266 +nsDocShellTreeOwner::EnsurePrompter() 1.267 +{ 1.268 + if (mPrompter) 1.269 + return; 1.270 + 1.271 + nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); 1.272 + if (wwatch && mWebBrowser) { 1.273 + nsCOMPtr<nsIDOMWindow> domWindow; 1.274 + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); 1.275 + if (domWindow) 1.276 + wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter)); 1.277 + } 1.278 +} 1.279 + 1.280 +void 1.281 +nsDocShellTreeOwner::EnsureAuthPrompter() 1.282 +{ 1.283 + if (mAuthPrompter) 1.284 + return; 1.285 + 1.286 + nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); 1.287 + if (wwatch && mWebBrowser) { 1.288 + nsCOMPtr<nsIDOMWindow> domWindow; 1.289 + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); 1.290 + if (domWindow) 1.291 + wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter)); 1.292 + } 1.293 +} 1.294 + 1.295 +void 1.296 +nsDocShellTreeOwner::AddToWatcher() 1.297 +{ 1.298 + if (mWebBrowser) { 1.299 + nsCOMPtr<nsIDOMWindow> domWindow; 1.300 + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); 1.301 + if (domWindow) { 1.302 + nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); 1.303 + if (wwatch) { 1.304 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); 1.305 + if (webBrowserChrome) 1.306 + wwatch->AddWindow(domWindow, webBrowserChrome); 1.307 + } 1.308 + } 1.309 + } 1.310 +} 1.311 + 1.312 +void 1.313 +nsDocShellTreeOwner::RemoveFromWatcher() 1.314 +{ 1.315 + if (mWebBrowser) { 1.316 + nsCOMPtr<nsIDOMWindow> domWindow; 1.317 + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); 1.318 + if (domWindow) { 1.319 + nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); 1.320 + if (wwatch) 1.321 + wwatch->RemoveWindow(domWindow); 1.322 + } 1.323 + } 1.324 +} 1.325 + 1.326 + 1.327 +NS_IMETHODIMP 1.328 +nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, 1.329 + bool aPrimary, bool aTargetable, 1.330 + const nsAString& aID) 1.331 +{ 1.332 + if(mTreeOwner) 1.333 + return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, 1.334 + aTargetable, aID); 1.335 + 1.336 + if (aPrimary) 1.337 + mPrimaryContentShell = aContentShell; 1.338 + return NS_OK; 1.339 +} 1.340 + 1.341 +NS_IMETHODIMP 1.342 +nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) 1.343 +{ 1.344 + if(mTreeOwner) 1.345 + return mTreeOwner->ContentShellRemoved(aContentShell); 1.346 + 1.347 + if(mPrimaryContentShell == aContentShell) 1.348 + mPrimaryContentShell = nullptr; 1.349 + 1.350 + return NS_OK; 1.351 +} 1.352 + 1.353 +NS_IMETHODIMP 1.354 +nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell) 1.355 +{ 1.356 + NS_ENSURE_ARG_POINTER(aShell); 1.357 + 1.358 + if (mTreeOwner) 1.359 + return mTreeOwner->GetPrimaryContentShell(aShell); 1.360 + 1.361 + *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell); 1.362 + NS_IF_ADDREF(*aShell); 1.363 + 1.364 + return NS_OK; 1.365 +} 1.366 + 1.367 +NS_IMETHODIMP 1.368 +nsDocShellTreeOwner::GetContentWindow(JSContext* aCx, 1.369 + JS::MutableHandle<JS::Value> aVal) 1.370 +{ 1.371 + if (mTreeOwner) 1.372 + return mTreeOwner->GetContentWindow(aCx, aVal); 1.373 + 1.374 + return NS_ERROR_NOT_IMPLEMENTED; 1.375 +} 1.376 + 1.377 +NS_IMETHODIMP 1.378 +nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, 1.379 + int32_t aCX, int32_t aCY) 1.380 +{ 1.381 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); 1.382 + 1.383 + NS_ENSURE_STATE(mTreeOwner || webBrowserChrome); 1.384 + 1.385 + if(mTreeOwner) 1.386 + return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY); 1.387 + 1.388 + if(aShellItem == mWebBrowser->mDocShell) 1.389 + return webBrowserChrome->SizeBrowserTo(aCX, aCY); 1.390 + 1.391 + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem)); 1.392 + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); 1.393 + 1.394 + nsCOMPtr<nsIDOMDocument> domDocument; 1.395 + webNav->GetDocument(getter_AddRefs(domDocument)); 1.396 + NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); 1.397 + 1.398 + nsCOMPtr<nsIDOMElement> domElement; 1.399 + domDocument->GetDocumentElement(getter_AddRefs(domElement)); 1.400 + NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); 1.401 + 1.402 + // Set the preferred Size 1.403 + //XXX 1.404 + NS_ERROR("Implement this"); 1.405 + /* 1.406 + Set the preferred size on the aShellItem. 1.407 + */ 1.408 + 1.409 + nsRefPtr<nsPresContext> presContext; 1.410 + mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext)); 1.411 + NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); 1.412 + 1.413 + nsIPresShell *presShell = presContext->GetPresShell(); 1.414 + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 1.415 + 1.416 + NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, 1.417 + NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); 1.418 + 1.419 + nsRect shellArea = presContext->GetVisibleArea(); 1.420 + 1.421 + int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width); 1.422 + int32_t browserCY = presContext->AppUnitsToDevPixels(shellArea.height); 1.423 + 1.424 + return webBrowserChrome->SizeBrowserTo(browserCX, browserCY); 1.425 +} 1.426 + 1.427 +NS_IMETHODIMP 1.428 +nsDocShellTreeOwner::SetPersistence(bool aPersistPosition, 1.429 + bool aPersistSize, 1.430 + bool aPersistSizeMode) 1.431 +{ 1.432 + return NS_ERROR_NOT_IMPLEMENTED; 1.433 +} 1.434 + 1.435 +NS_IMETHODIMP 1.436 +nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition, 1.437 + bool* aPersistSize, 1.438 + bool* aPersistSizeMode) 1.439 +{ 1.440 + return NS_ERROR_NOT_IMPLEMENTED; 1.441 +} 1.442 + 1.443 +NS_IMETHODIMP 1.444 +nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) 1.445 +{ 1.446 + if(mTreeOwner) { 1.447 + mTreeOwner->GetTargetableShellCount(aResult); 1.448 + } else { 1.449 + *aResult = 0; 1.450 + } 1.451 + 1.452 + return NS_OK; 1.453 +} 1.454 + 1.455 +//***************************************************************************** 1.456 +// nsDocShellTreeOwner::nsIBaseWindow 1.457 +//***************************************************************************** 1.458 + 1.459 + 1.460 +NS_IMETHODIMP 1.461 +nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow, 1.462 + nsIWidget* aParentWidget, int32_t aX, 1.463 + int32_t aY, int32_t aCX, int32_t aCY) 1.464 +{ 1.465 + return NS_ERROR_NULL_POINTER; 1.466 +} 1.467 + 1.468 +NS_IMETHODIMP 1.469 +nsDocShellTreeOwner::Create() 1.470 +{ 1.471 + return NS_ERROR_NULL_POINTER; 1.472 +} 1.473 + 1.474 +NS_IMETHODIMP 1.475 +nsDocShellTreeOwner::Destroy() 1.476 +{ 1.477 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); 1.478 + if (webBrowserChrome) 1.479 + { 1.480 + return webBrowserChrome->DestroyBrowserWindow(); 1.481 + } 1.482 + 1.483 + return NS_ERROR_NULL_POINTER; 1.484 +} 1.485 + 1.486 +NS_IMETHODIMP 1.487 +nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) 1.488 +{ 1.489 + if (mWebBrowser) { 1.490 + return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale); 1.491 + } 1.492 + 1.493 + *aScale = 1.0; 1.494 + return NS_OK; 1.495 +} 1.496 + 1.497 +NS_IMETHODIMP 1.498 +nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY) 1.499 +{ 1.500 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.501 + if (ownerWin) 1.502 + { 1.503 + return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, 1.504 + aX, aY, 0, 0); 1.505 + } 1.506 + return NS_ERROR_NULL_POINTER; 1.507 +} 1.508 + 1.509 +NS_IMETHODIMP 1.510 +nsDocShellTreeOwner::GetPosition(int32_t* aX, int32_t* aY) 1.511 +{ 1.512 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.513 + if (ownerWin) 1.514 + { 1.515 + return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, 1.516 + aX, aY, nullptr, nullptr); 1.517 + } 1.518 + return NS_ERROR_NULL_POINTER; 1.519 +} 1.520 + 1.521 +NS_IMETHODIMP 1.522 +nsDocShellTreeOwner::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) 1.523 +{ 1.524 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.525 + if (ownerWin) 1.526 + { 1.527 + return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, 1.528 + 0, 0, aCX, aCY); 1.529 + } 1.530 + return NS_ERROR_NULL_POINTER; 1.531 +} 1.532 + 1.533 +NS_IMETHODIMP 1.534 +nsDocShellTreeOwner::GetSize(int32_t* aCX, int32_t* aCY) 1.535 +{ 1.536 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.537 + if (ownerWin) 1.538 + { 1.539 + return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, 1.540 + nullptr, nullptr, aCX, aCY); 1.541 + } 1.542 + return NS_ERROR_NULL_POINTER; 1.543 +} 1.544 + 1.545 +NS_IMETHODIMP 1.546 +nsDocShellTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX, 1.547 + int32_t aCY, bool aRepaint) 1.548 +{ 1.549 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.550 + if (ownerWin) 1.551 + { 1.552 + return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | 1.553 + nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, 1.554 + aX, aY, aCX, aCY); 1.555 + } 1.556 + return NS_ERROR_NULL_POINTER; 1.557 +} 1.558 + 1.559 +NS_IMETHODIMP 1.560 +nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX, 1.561 + int32_t* aCY) 1.562 +{ 1.563 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.564 + if (ownerWin) 1.565 + { 1.566 + return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | 1.567 + nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, 1.568 + aX, aY, aCX, aCY); 1.569 + } 1.570 + return NS_ERROR_NULL_POINTER; 1.571 +} 1.572 + 1.573 +NS_IMETHODIMP 1.574 +nsDocShellTreeOwner::Repaint(bool aForce) 1.575 +{ 1.576 + return NS_ERROR_NULL_POINTER; 1.577 +} 1.578 + 1.579 +NS_IMETHODIMP 1.580 +nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget) 1.581 +{ 1.582 + return NS_ERROR_NULL_POINTER; 1.583 +} 1.584 + 1.585 +NS_IMETHODIMP 1.586 +nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget) 1.587 +{ 1.588 + return NS_ERROR_NULL_POINTER; 1.589 +} 1.590 + 1.591 +NS_IMETHODIMP 1.592 +nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow) 1.593 +{ 1.594 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.595 + if (ownerWin) 1.596 + { 1.597 + return ownerWin->GetSiteWindow(aParentNativeWindow); 1.598 + } 1.599 + return NS_ERROR_NULL_POINTER; 1.600 +} 1.601 + 1.602 +NS_IMETHODIMP 1.603 +nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow) 1.604 +{ 1.605 + return NS_ERROR_NULL_POINTER; 1.606 +} 1.607 + 1.608 +NS_IMETHODIMP 1.609 +nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle) 1.610 +{ 1.611 + // the nativeHandle should be accessed from nsIXULWindow 1.612 + return NS_ERROR_NOT_IMPLEMENTED; 1.613 +} 1.614 + 1.615 +NS_IMETHODIMP 1.616 +nsDocShellTreeOwner::GetVisibility(bool* aVisibility) 1.617 +{ 1.618 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.619 + if (ownerWin) 1.620 + { 1.621 + return ownerWin->GetVisibility(aVisibility); 1.622 + } 1.623 + return NS_ERROR_NULL_POINTER; 1.624 +} 1.625 + 1.626 +NS_IMETHODIMP 1.627 +nsDocShellTreeOwner::SetVisibility(bool aVisibility) 1.628 +{ 1.629 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.630 + if (ownerWin) 1.631 + { 1.632 + return ownerWin->SetVisibility(aVisibility); 1.633 + } 1.634 + return NS_ERROR_NULL_POINTER; 1.635 +} 1.636 + 1.637 +NS_IMETHODIMP 1.638 +nsDocShellTreeOwner::GetEnabled(bool *aEnabled) 1.639 +{ 1.640 + NS_ENSURE_ARG_POINTER(aEnabled); 1.641 + *aEnabled = true; 1.642 + return NS_ERROR_NOT_IMPLEMENTED; 1.643 +} 1.644 + 1.645 +NS_IMETHODIMP 1.646 +nsDocShellTreeOwner::SetEnabled(bool aEnabled) 1.647 +{ 1.648 + return NS_ERROR_NOT_IMPLEMENTED; 1.649 +} 1.650 + 1.651 +NS_IMETHODIMP 1.652 +nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget) 1.653 +{ 1.654 + return NS_ERROR_NULL_POINTER; 1.655 +} 1.656 + 1.657 +NS_IMETHODIMP 1.658 +nsDocShellTreeOwner::SetFocus() 1.659 +{ 1.660 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.661 + if (ownerWin) 1.662 + { 1.663 + return ownerWin->SetFocus(); 1.664 + } 1.665 + return NS_ERROR_NULL_POINTER; 1.666 +} 1.667 + 1.668 +NS_IMETHODIMP 1.669 +nsDocShellTreeOwner::GetTitle(char16_t** aTitle) 1.670 +{ 1.671 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.672 + if (ownerWin) 1.673 + { 1.674 + return ownerWin->GetTitle(aTitle); 1.675 + } 1.676 + return NS_ERROR_NULL_POINTER; 1.677 +} 1.678 + 1.679 +NS_IMETHODIMP 1.680 +nsDocShellTreeOwner::SetTitle(const char16_t* aTitle) 1.681 +{ 1.682 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin(); 1.683 + if (ownerWin) 1.684 + { 1.685 + return ownerWin->SetTitle(aTitle); 1.686 + } 1.687 + return NS_ERROR_NULL_POINTER; 1.688 +} 1.689 + 1.690 + 1.691 +//***************************************************************************** 1.692 +// nsDocShellTreeOwner::nsIWebProgressListener 1.693 +//***************************************************************************** 1.694 + 1.695 + 1.696 +NS_IMETHODIMP 1.697 +nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress, 1.698 + nsIRequest* aRequest, 1.699 + int32_t aCurSelfProgress, 1.700 + int32_t aMaxSelfProgress, 1.701 + int32_t aCurTotalProgress, 1.702 + int32_t aMaxTotalProgress) 1.703 +{ 1.704 + // In the absence of DOM document creation event, this method is the 1.705 + // most convenient place to install the mouse listener on the 1.706 + // DOM document. 1.707 + return AddChromeListeners(); 1.708 +} 1.709 + 1.710 +NS_IMETHODIMP 1.711 +nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress, 1.712 + nsIRequest* aRequest, 1.713 + uint32_t aProgressStateFlags, 1.714 + nsresult aStatus) 1.715 +{ 1.716 + return NS_OK; 1.717 +} 1.718 + 1.719 +NS_IMETHODIMP 1.720 +nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress, 1.721 + nsIRequest* aRequest, 1.722 + nsIURI* aURI, 1.723 + uint32_t aFlags) 1.724 +{ 1.725 + return NS_OK; 1.726 +} 1.727 + 1.728 +NS_IMETHODIMP 1.729 +nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress, 1.730 + nsIRequest* aRequest, 1.731 + nsresult aStatus, 1.732 + const char16_t* aMessage) 1.733 +{ 1.734 + return NS_OK; 1.735 +} 1.736 + 1.737 +NS_IMETHODIMP 1.738 +nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, 1.739 + nsIRequest *aRequest, 1.740 + uint32_t state) 1.741 +{ 1.742 + return NS_OK; 1.743 +} 1.744 + 1.745 + 1.746 +//***************************************************************************** 1.747 +// nsDocShellTreeOwner: Helpers 1.748 +//***************************************************************************** 1.749 + 1.750 +//***************************************************************************** 1.751 +// nsDocShellTreeOwner: Accessors 1.752 +//***************************************************************************** 1.753 + 1.754 +void 1.755 +nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) 1.756 +{ 1.757 + if ( !aWebBrowser ) 1.758 + RemoveChromeListeners(); 1.759 + if (aWebBrowser != mWebBrowser) { 1.760 + mPrompter = 0; 1.761 + mAuthPrompter = 0; 1.762 + } 1.763 + 1.764 + mWebBrowser = aWebBrowser; 1.765 +} 1.766 + 1.767 +nsWebBrowser * 1.768 +nsDocShellTreeOwner::WebBrowser() 1.769 +{ 1.770 + return mWebBrowser; 1.771 +} 1.772 + 1.773 +NS_IMETHODIMP 1.774 +nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) 1.775 +{ 1.776 + if(aTreeOwner) { 1.777 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner)); 1.778 + NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); 1.779 + NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG); 1.780 + mTreeOwner = aTreeOwner; 1.781 + } 1.782 + else { 1.783 + mTreeOwner = nullptr; 1.784 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); 1.785 + if (!webBrowserChrome) 1.786 + NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE); 1.787 + } 1.788 + 1.789 + return NS_OK; 1.790 +} 1.791 + 1.792 +NS_IMETHODIMP 1.793 +nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome) 1.794 +{ 1.795 + if(!aWebBrowserChrome) { 1.796 + mWebBrowserChrome = nullptr; 1.797 + mOwnerWin = nullptr; 1.798 + mOwnerRequestor = nullptr; 1.799 + mWebBrowserChromeWeak = 0; 1.800 + } else { 1.801 + nsCOMPtr<nsISupportsWeakReference> supportsweak = 1.802 + do_QueryInterface(aWebBrowserChrome); 1.803 + if (supportsweak) { 1.804 + supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak)); 1.805 + } else { 1.806 + nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome)); 1.807 + nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome)); 1.808 + 1.809 + // it's ok for ownerWin or requestor to be null. 1.810 + mWebBrowserChrome = aWebBrowserChrome; 1.811 + mOwnerWin = ownerWin; 1.812 + mOwnerRequestor = requestor; 1.813 + } 1.814 + } 1.815 + return NS_OK; 1.816 +} 1.817 + 1.818 + 1.819 +// 1.820 +// AddChromeListeners 1.821 +// 1.822 +// Hook up things to the chrome like context menus and tooltips, if the chrome 1.823 +// has implemented the right interfaces. 1.824 +// 1.825 +NS_IMETHODIMP 1.826 +nsDocShellTreeOwner::AddChromeListeners() 1.827 +{ 1.828 + nsresult rv = NS_OK; 1.829 + 1.830 + nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); 1.831 + if (!webBrowserChrome) 1.832 + return NS_ERROR_FAILURE; 1.833 + 1.834 + // install tooltips 1.835 + if ( !mChromeTooltipListener ) { 1.836 + nsCOMPtr<nsITooltipListener> 1.837 + tooltipListener(do_QueryInterface(webBrowserChrome)); 1.838 + if ( tooltipListener ) { 1.839 + mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, 1.840 + webBrowserChrome); 1.841 + if ( mChromeTooltipListener ) { 1.842 + NS_ADDREF(mChromeTooltipListener); 1.843 + rv = mChromeTooltipListener->AddChromeListeners(); 1.844 + } 1.845 + else 1.846 + rv = NS_ERROR_OUT_OF_MEMORY; 1.847 + } 1.848 + } 1.849 + 1.850 + // install context menus 1.851 + if ( !mChromeContextMenuListener ) { 1.852 + nsCOMPtr<nsIContextMenuListener2> 1.853 + contextListener2(do_QueryInterface(webBrowserChrome)); 1.854 + nsCOMPtr<nsIContextMenuListener> 1.855 + contextListener(do_QueryInterface(webBrowserChrome)); 1.856 + if ( contextListener2 || contextListener ) { 1.857 + mChromeContextMenuListener = 1.858 + new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); 1.859 + if ( mChromeContextMenuListener ) { 1.860 + NS_ADDREF(mChromeContextMenuListener); 1.861 + rv = mChromeContextMenuListener->AddChromeListeners(); 1.862 + } 1.863 + else 1.864 + rv = NS_ERROR_OUT_OF_MEMORY; 1.865 + } 1.866 + } 1.867 + 1.868 + // register dragover and drop event listeners with the listener manager 1.869 + nsCOMPtr<EventTarget> target; 1.870 + GetDOMEventTarget(mWebBrowser, getter_AddRefs(target)); 1.871 + 1.872 + EventListenerManager* elmP = target->GetOrCreateListenerManager(); 1.873 + if (elmP) { 1.874 + elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"), 1.875 + TrustedEventsAtSystemGroupBubble()); 1.876 + elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"), 1.877 + TrustedEventsAtSystemGroupBubble()); 1.878 + } 1.879 + 1.880 + return rv; 1.881 + 1.882 +} // AddChromeListeners 1.883 + 1.884 + 1.885 +NS_IMETHODIMP 1.886 +nsDocShellTreeOwner::RemoveChromeListeners() 1.887 +{ 1.888 + if ( mChromeTooltipListener ) { 1.889 + mChromeTooltipListener->RemoveChromeListeners(); 1.890 + NS_RELEASE(mChromeTooltipListener); 1.891 + } 1.892 + if ( mChromeContextMenuListener ) { 1.893 + mChromeContextMenuListener->RemoveChromeListeners(); 1.894 + NS_RELEASE(mChromeContextMenuListener); 1.895 + } 1.896 + 1.897 + nsCOMPtr<EventTarget> piTarget; 1.898 + GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget)); 1.899 + if (!piTarget) 1.900 + return NS_OK; 1.901 + 1.902 + EventListenerManager* elmP = piTarget->GetOrCreateListenerManager(); 1.903 + if (elmP) 1.904 + { 1.905 + elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"), 1.906 + TrustedEventsAtSystemGroupBubble()); 1.907 + elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"), 1.908 + TrustedEventsAtSystemGroupBubble()); 1.909 + } 1.910 + 1.911 + return NS_OK; 1.912 +} 1.913 + 1.914 +NS_IMETHODIMP 1.915 +nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent) 1.916 +{ 1.917 + nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent); 1.918 + NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG); 1.919 + 1.920 + bool defaultPrevented; 1.921 + aEvent->GetDefaultPrevented(&defaultPrevented); 1.922 + if (defaultPrevented) { 1.923 + return NS_OK; 1.924 + } 1.925 + 1.926 + nsCOMPtr<nsIDroppedLinkHandler> handler = do_GetService("@mozilla.org/content/dropped-link-handler;1"); 1.927 + if (handler) { 1.928 + nsAutoString eventType; 1.929 + aEvent->GetType(eventType); 1.930 + if (eventType.EqualsLiteral("dragover")) { 1.931 + bool canDropLink; 1.932 + handler->CanDropLink(dragEvent, false, &canDropLink); 1.933 + if (canDropLink) 1.934 + aEvent->PreventDefault(); 1.935 + } 1.936 + else if (eventType.EqualsLiteral("drop")) { 1.937 + nsIWebNavigation* webnav = static_cast<nsIWebNavigation *>(mWebBrowser); 1.938 + 1.939 + nsAutoString link, name; 1.940 + if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) { 1.941 + if (!link.IsEmpty()) { 1.942 + webnav->LoadURI(link.get(), 0, nullptr, nullptr, nullptr); 1.943 + } 1.944 + } 1.945 + else { 1.946 + aEvent->StopPropagation(); 1.947 + aEvent->PreventDefault(); 1.948 + } 1.949 + } 1.950 + } 1.951 + 1.952 + return NS_OK; 1.953 +} 1.954 + 1.955 +already_AddRefed<nsIWebBrowserChrome> 1.956 +nsDocShellTreeOwner::GetWebBrowserChrome() 1.957 +{ 1.958 + nsCOMPtr<nsIWebBrowserChrome> chrome; 1.959 + if (mWebBrowserChromeWeak) { 1.960 + chrome = do_QueryReferent(mWebBrowserChromeWeak); 1.961 + } else if (mWebBrowserChrome) { 1.962 + chrome = mWebBrowserChrome; 1.963 + } 1.964 + return chrome.forget(); 1.965 +} 1.966 + 1.967 +already_AddRefed<nsIEmbeddingSiteWindow> 1.968 +nsDocShellTreeOwner::GetOwnerWin() 1.969 +{ 1.970 + nsCOMPtr<nsIEmbeddingSiteWindow> win; 1.971 + if (mWebBrowserChromeWeak) { 1.972 + win = do_QueryReferent(mWebBrowserChromeWeak); 1.973 + } else if (mOwnerWin) { 1.974 + win = mOwnerWin; 1.975 + } 1.976 + return win.forget(); 1.977 +} 1.978 + 1.979 +already_AddRefed<nsIInterfaceRequestor> 1.980 +nsDocShellTreeOwner::GetOwnerRequestor() 1.981 +{ 1.982 + nsCOMPtr<nsIInterfaceRequestor> req; 1.983 + if (mWebBrowserChromeWeak) { 1.984 + req = do_QueryReferent(mWebBrowserChromeWeak); 1.985 + } else if (mOwnerRequestor) { 1.986 + req = mOwnerRequestor; 1.987 + } 1.988 + return req.forget(); 1.989 +} 1.990 + 1.991 + 1.992 +/////////////////////////////////////////////////////////////////////////////// 1.993 +// DefaultTooltipTextProvider 1.994 + 1.995 +class DefaultTooltipTextProvider MOZ_FINAL : public nsITooltipTextProvider 1.996 +{ 1.997 +public: 1.998 + DefaultTooltipTextProvider(); 1.999 + 1.1000 + NS_DECL_THREADSAFE_ISUPPORTS 1.1001 + NS_DECL_NSITOOLTIPTEXTPROVIDER 1.1002 + 1.1003 +protected: 1.1004 + nsCOMPtr<nsIAtom> mTag_dialog; 1.1005 + nsCOMPtr<nsIAtom> mTag_dialogheader; 1.1006 + nsCOMPtr<nsIAtom> mTag_window; 1.1007 +}; 1.1008 + 1.1009 +NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider) 1.1010 + 1.1011 +DefaultTooltipTextProvider::DefaultTooltipTextProvider() 1.1012 +{ 1.1013 + // There are certain element types which we don't want to use 1.1014 + // as tool tip text. 1.1015 + mTag_dialog = do_GetAtom("dialog"); 1.1016 + mTag_dialogheader = do_GetAtom("dialogheader"); 1.1017 + mTag_window = do_GetAtom("window"); 1.1018 +} 1.1019 + 1.1020 +// 1.1021 +// UseSVGTitle 1.1022 +// 1.1023 +// A helper routine that determines whether we're still interested 1.1024 +// in SVG titles. We need to stop at the SVG root element that 1.1025 +// has a document node parent 1.1026 +// 1.1027 +static bool 1.1028 +UseSVGTitle(nsIDOMElement *currElement) 1.1029 +{ 1.1030 + nsCOMPtr<dom::Element> element(do_QueryInterface(currElement)); 1.1031 + if (!element || !element->IsSVG() || !element->GetParentNode()) 1.1032 + return false; 1.1033 + 1.1034 + return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE; 1.1035 +} 1.1036 + 1.1037 +/* void getNodeText (in nsIDOMNode aNode, out wstring aText); */ 1.1038 +NS_IMETHODIMP 1.1039 +DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText, 1.1040 + bool *_retval) 1.1041 +{ 1.1042 + NS_ENSURE_ARG_POINTER(aNode); 1.1043 + NS_ENSURE_ARG_POINTER(aText); 1.1044 + 1.1045 + nsString outText; 1.1046 + 1.1047 + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); 1.1048 + 1.1049 + bool lookingForSVGTitle = true; 1.1050 + bool found = false; 1.1051 + nsCOMPtr<nsIDOMNode> current ( aNode ); 1.1052 + 1.1053 + // If the element implement the constraint validation API and has no title, 1.1054 + // show the validation message, if any. 1.1055 + nsCOMPtr<nsIConstraintValidation> cvElement = do_QueryInterface(current); 1.1056 + if (cvElement) { 1.1057 + nsCOMPtr<nsIContent> content = do_QueryInterface(cvElement); 1.1058 + nsCOMPtr<nsIAtom> titleAtom = do_GetAtom("title"); 1.1059 + 1.1060 + nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(content); 1.1061 + bool formHasNoValidate = false; 1.1062 + mozilla::dom::Element* form = formControl->GetFormElement(); 1.1063 + if (form) { 1.1064 + nsCOMPtr<nsIAtom> noValidateAtom = do_GetAtom("novalidate"); 1.1065 + formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom); 1.1066 + } 1.1067 + 1.1068 + if (!content->HasAttr(kNameSpaceID_None, titleAtom) && 1.1069 + !formHasNoValidate) { 1.1070 + cvElement->GetValidationMessage(outText); 1.1071 + found = !outText.IsEmpty(); 1.1072 + } 1.1073 + } 1.1074 + 1.1075 + while ( !found && current ) { 1.1076 + nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) ); 1.1077 + if ( currElement ) { 1.1078 + nsCOMPtr<nsIContent> content(do_QueryInterface(currElement)); 1.1079 + if (content) { 1.1080 + nsIAtom *tagAtom = content->Tag(); 1.1081 + if (tagAtom != mTag_dialog && 1.1082 + tagAtom != mTag_dialogheader && 1.1083 + tagAtom != mTag_window) { 1.1084 + // first try the normal title attribute... 1.1085 + currElement->GetAttribute(NS_LITERAL_STRING("title"), outText); 1.1086 + if ( outText.Length() ) 1.1087 + found = true; 1.1088 + else { 1.1089 + // ...ok, that didn't work, try it in the XLink namespace 1.1090 + NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink"); 1.1091 + nsCOMPtr<mozilla::dom::Link> linkContent(do_QueryInterface(currElement)); 1.1092 + if (linkContent) { 1.1093 + nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal()); 1.1094 + if (uri) { 1.1095 + currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText); 1.1096 + if ( outText.Length() ) 1.1097 + found = true; 1.1098 + } 1.1099 + } 1.1100 + else { 1.1101 + if (lookingForSVGTitle) { 1.1102 + lookingForSVGTitle = UseSVGTitle(currElement); 1.1103 + } 1.1104 + if (lookingForSVGTitle) { 1.1105 + nsINodeList* childNodes = node->ChildNodes(); 1.1106 + uint32_t childNodeCount = childNodes->Length(); 1.1107 + for (uint32_t i = 0; i < childNodeCount; i++) { 1.1108 + nsIContent* child = childNodes->Item(i); 1.1109 + if (child->IsSVG(nsGkAtoms::title)) { 1.1110 + static_cast<dom::SVGTitleElement*>(child)->GetTextContent(outText); 1.1111 + if ( outText.Length() ) 1.1112 + found = true; 1.1113 + break; 1.1114 + } 1.1115 + } 1.1116 + } 1.1117 + } 1.1118 + } 1.1119 + } 1.1120 + } 1.1121 + } 1.1122 + 1.1123 + // not found here, walk up to the parent and keep trying 1.1124 + if ( !found ) { 1.1125 + nsCOMPtr<nsIDOMNode> temp ( current ); 1.1126 + temp->GetParentNode(getter_AddRefs(current)); 1.1127 + } 1.1128 + } // while not found 1.1129 + 1.1130 + *_retval = found; 1.1131 + *aText = (found) ? ToNewUnicode(outText) : nullptr; 1.1132 + 1.1133 + return NS_OK; 1.1134 +} 1.1135 + 1.1136 +/////////////////////////////////////////////////////////////////////////////// 1.1137 + 1.1138 +NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener) 1.1139 + 1.1140 +// 1.1141 +// ChromeTooltipListener ctor 1.1142 +// 1.1143 + 1.1144 +ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser, 1.1145 + nsIWebBrowserChrome* inChrome) 1.1146 + : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome), 1.1147 + mTooltipListenerInstalled(false), 1.1148 + mMouseClientX(0), mMouseClientY(0), 1.1149 + mShowingTooltip(false) 1.1150 +{ 1.1151 + mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID); 1.1152 + if (!mTooltipTextProvider) { 1.1153 + nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider; 1.1154 + mTooltipTextProvider = do_QueryInterface(pProvider); 1.1155 + } 1.1156 +} // ctor 1.1157 + 1.1158 + 1.1159 +// 1.1160 +// ChromeTooltipListener dtor 1.1161 +// 1.1162 +ChromeTooltipListener::~ChromeTooltipListener() 1.1163 +{ 1.1164 + 1.1165 +} // dtor 1.1166 + 1.1167 + 1.1168 +// 1.1169 +// AddChromeListeners 1.1170 +// 1.1171 +// Hook up things to the chrome like context menus and tooltips, if the chrome 1.1172 +// has implemented the right interfaces. 1.1173 +// 1.1174 +NS_IMETHODIMP 1.1175 +ChromeTooltipListener::AddChromeListeners() 1.1176 +{ 1.1177 + if (!mEventTarget) 1.1178 + GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); 1.1179 + 1.1180 + // Register the appropriate events for tooltips, but only if 1.1181 + // the embedding chrome cares. 1.1182 + nsresult rv = NS_OK; 1.1183 + nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); 1.1184 + if ( tooltipListener && !mTooltipListenerInstalled ) { 1.1185 + rv = AddTooltipListener(); 1.1186 + if ( NS_FAILED(rv) ) 1.1187 + return rv; 1.1188 + } 1.1189 + 1.1190 + return rv; 1.1191 + 1.1192 +} // AddChromeListeners 1.1193 + 1.1194 + 1.1195 +// 1.1196 +// AddTooltipListener 1.1197 +// 1.1198 +// Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit, 1.1199 +// "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track 1.1200 +// of how many succeed so we can clean up correctly in Release(). 1.1201 +// 1.1202 +NS_IMETHODIMP 1.1203 +ChromeTooltipListener::AddTooltipListener() 1.1204 +{ 1.1205 + if (mEventTarget) { 1.1206 + nsresult rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), 1.1207 + this, false, false); 1.1208 + NS_ENSURE_SUCCESS(rv, rv); 1.1209 + rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, 1.1210 + false, false); 1.1211 + NS_ENSURE_SUCCESS(rv, rv); 1.1212 + rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, 1.1213 + false, false); 1.1214 + NS_ENSURE_SUCCESS(rv, rv); 1.1215 + rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, 1.1216 + false, false); 1.1217 + NS_ENSURE_SUCCESS(rv, rv); 1.1218 + 1.1219 + mTooltipListenerInstalled = true; 1.1220 + } 1.1221 + 1.1222 + return NS_OK; 1.1223 +} 1.1224 + 1.1225 + 1.1226 +// 1.1227 +// RemoveChromeListeners 1.1228 +// 1.1229 +// Unsubscribe from the various things we've hooked up to the window root. 1.1230 +// 1.1231 +NS_IMETHODIMP 1.1232 +ChromeTooltipListener::RemoveChromeListeners ( ) 1.1233 +{ 1.1234 + HideTooltip(); 1.1235 + 1.1236 + if ( mTooltipListenerInstalled ) 1.1237 + RemoveTooltipListener(); 1.1238 + 1.1239 + mEventTarget = nullptr; 1.1240 + 1.1241 + // it really doesn't matter if these fail... 1.1242 + return NS_OK; 1.1243 + 1.1244 +} // RemoveChromeTooltipListeners 1.1245 + 1.1246 + 1.1247 + 1.1248 +// 1.1249 +// RemoveTooltipListener 1.1250 +// 1.1251 +// Unsubscribe from all the various tooltip events that we were listening to 1.1252 +// 1.1253 +NS_IMETHODIMP 1.1254 +ChromeTooltipListener::RemoveTooltipListener() 1.1255 +{ 1.1256 + if (mEventTarget) { 1.1257 + nsresult rv = 1.1258 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, 1.1259 + false); 1.1260 + NS_ENSURE_SUCCESS(rv, rv); 1.1261 + rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), 1.1262 + this, false); 1.1263 + NS_ENSURE_SUCCESS(rv, rv); 1.1264 + rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, 1.1265 + false); 1.1266 + NS_ENSURE_SUCCESS(rv, rv); 1.1267 + rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), 1.1268 + this, false); 1.1269 + NS_ENSURE_SUCCESS(rv, rv); 1.1270 + 1.1271 + mTooltipListenerInstalled = false; 1.1272 + } 1.1273 + 1.1274 + return NS_OK; 1.1275 +} 1.1276 + 1.1277 +NS_IMETHODIMP 1.1278 +ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) 1.1279 +{ 1.1280 + nsAutoString eventType; 1.1281 + aEvent->GetType(eventType); 1.1282 + 1.1283 + if (eventType.EqualsLiteral("keydown") || 1.1284 + eventType.EqualsLiteral("mousedown") || 1.1285 + eventType.EqualsLiteral("mouseout")) 1.1286 + return HideTooltip(); 1.1287 + if (eventType.EqualsLiteral("mousemove")) 1.1288 + return MouseMove(aEvent); 1.1289 + 1.1290 + NS_ERROR("Unexpected event type"); 1.1291 + return NS_OK; 1.1292 +} 1.1293 + 1.1294 +// 1.1295 +// MouseMove 1.1296 +// 1.1297 +// If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the 1.1298 +// timer fires, we cache the node in |mPossibleTooltipNode|. 1.1299 +// 1.1300 +nsresult 1.1301 +ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) 1.1302 +{ 1.1303 + nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) ); 1.1304 + if (!mouseEvent) 1.1305 + return NS_OK; 1.1306 + 1.1307 + // stash the coordinates of the event so that we can still get back to it from within the 1.1308 + // timer callback. On win32, we'll get a MouseMove event even when a popup goes away -- 1.1309 + // even when the mouse doesn't change position! To get around this, we make sure the 1.1310 + // mouse has really moved before proceeding. 1.1311 + int32_t newMouseX, newMouseY; 1.1312 + mouseEvent->GetClientX(&newMouseX); 1.1313 + mouseEvent->GetClientY(&newMouseY); 1.1314 + if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY ) 1.1315 + return NS_OK; 1.1316 + mMouseClientX = newMouseX; mMouseClientY = newMouseY; 1.1317 + mouseEvent->GetScreenX(&mMouseScreenX); 1.1318 + mouseEvent->GetScreenY(&mMouseScreenY); 1.1319 + 1.1320 + // We want to close the tip if it is being displayed and the mouse moves. Recall 1.1321 + // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse 1.1322 + // moves, we want to make sure we reset the timer to show it, so that the delay 1.1323 + // is from when the mouse stops moving, not when it enters the element. 1.1324 + if ( mShowingTooltip ) 1.1325 + return HideTooltip(); 1.1326 + if ( mTooltipTimer ) 1.1327 + mTooltipTimer->Cancel(); 1.1328 + 1.1329 + mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.1330 + if ( mTooltipTimer ) { 1.1331 + nsCOMPtr<EventTarget> eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget(); 1.1332 + if ( eventTarget ) 1.1333 + mPossibleTooltipNode = do_QueryInterface(eventTarget); 1.1334 + if ( mPossibleTooltipNode ) { 1.1335 + nsresult rv = 1.1336 + mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this, 1.1337 + LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500), 1.1338 + nsITimer::TYPE_ONE_SHOT); 1.1339 + if (NS_FAILED(rv)) 1.1340 + mPossibleTooltipNode = nullptr; 1.1341 + } 1.1342 + } 1.1343 + else 1.1344 + NS_WARNING ( "Could not create a timer for tooltip tracking" ); 1.1345 + 1.1346 + return NS_OK; 1.1347 + 1.1348 +} // MouseMove 1.1349 + 1.1350 + 1.1351 +// 1.1352 +// ShowTooltip 1.1353 +// 1.1354 +// Tell the registered chrome that they should show the tooltip 1.1355 +// 1.1356 +NS_IMETHODIMP 1.1357 +ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords, 1.1358 + const nsAString & inTipText) 1.1359 +{ 1.1360 + nsresult rv = NS_OK; 1.1361 + 1.1362 + // do the work to call the client 1.1363 + nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); 1.1364 + if ( tooltipListener ) { 1.1365 + rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); 1.1366 + if ( NS_SUCCEEDED(rv) ) 1.1367 + mShowingTooltip = true; 1.1368 + } 1.1369 + 1.1370 + return rv; 1.1371 + 1.1372 +} // ShowTooltip 1.1373 + 1.1374 + 1.1375 +// 1.1376 +// HideTooltip 1.1377 +// 1.1378 +// Tell the registered chrome that they should rollup the tooltip 1.1379 +// NOTE: This routine is safe to call even if the popup is already closed. 1.1380 +// 1.1381 +NS_IMETHODIMP 1.1382 +ChromeTooltipListener::HideTooltip() 1.1383 +{ 1.1384 + nsresult rv = NS_OK; 1.1385 + 1.1386 + // shut down the relevant timers 1.1387 + if ( mTooltipTimer ) { 1.1388 + mTooltipTimer->Cancel(); 1.1389 + mTooltipTimer = nullptr; 1.1390 + // release tooltip target 1.1391 + mPossibleTooltipNode = nullptr; 1.1392 + } 1.1393 + if ( mAutoHideTimer ) { 1.1394 + mAutoHideTimer->Cancel(); 1.1395 + mAutoHideTimer = nullptr; 1.1396 + } 1.1397 + 1.1398 + // if we're showing the tip, tell the chrome to hide it 1.1399 + if ( mShowingTooltip ) { 1.1400 + nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) ); 1.1401 + if ( tooltipListener ) { 1.1402 + rv = tooltipListener->OnHideTooltip ( ); 1.1403 + if ( NS_SUCCEEDED(rv) ) 1.1404 + mShowingTooltip = false; 1.1405 + } 1.1406 + } 1.1407 + 1.1408 + return rv; 1.1409 + 1.1410 +} // HideTooltip 1.1411 + 1.1412 + 1.1413 +// 1.1414 +// sTooltipCallback 1.1415 +// 1.1416 +// A timer callback, fired when the mouse has hovered inside of a frame for the 1.1417 +// appropriate amount of time. Getting to this point means that we should show the 1.1418 +// tooltip, but only after we determine there is an appropriate TITLE element. 1.1419 +// 1.1420 +// This relies on certain things being cached into the |aChromeTooltipListener| object passed to 1.1421 +// us by the timer: 1.1422 +// -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX) 1.1423 +// -- the dom node the user hovered over (mPossibleTooltipNode) 1.1424 +// 1.1425 +void 1.1426 +ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer, 1.1427 + void *aChromeTooltipListener) 1.1428 +{ 1.1429 + ChromeTooltipListener* self = static_cast<ChromeTooltipListener*> 1.1430 + (aChromeTooltipListener); 1.1431 + if ( self && self->mPossibleTooltipNode ){ 1.1432 + // The actual coordinates we want to put the tooltip at are relative to the 1.1433 + // toplevel docshell of our mWebBrowser. We know what the screen 1.1434 + // coordinates of the mouse event were, which means we just need the screen 1.1435 + // coordinates of the docshell. Unfortunately, there is no good way to 1.1436 + // find those short of groveling for the presentation in that docshell and 1.1437 + // finding the screen coords of its toplevel widget... 1.1438 + nsCOMPtr<nsIDocShell> docShell = 1.1439 + do_GetInterface(static_cast<nsIWebBrowser*>(self->mWebBrowser)); 1.1440 + nsCOMPtr<nsIPresShell> shell; 1.1441 + if (docShell) { 1.1442 + shell = docShell->GetPresShell(); 1.1443 + } 1.1444 + 1.1445 + nsIWidget* widget = nullptr; 1.1446 + if (shell) { 1.1447 + nsViewManager* vm = shell->GetViewManager(); 1.1448 + if (vm) { 1.1449 + nsView* view = vm->GetRootView(); 1.1450 + if (view) { 1.1451 + nsPoint offset; 1.1452 + widget = view->GetNearestWidget(&offset); 1.1453 + } 1.1454 + } 1.1455 + } 1.1456 + 1.1457 + if (!widget) { 1.1458 + // release tooltip target if there is one, NO MATTER WHAT 1.1459 + self->mPossibleTooltipNode = nullptr; 1.1460 + return; 1.1461 + } 1.1462 + 1.1463 + // if there is text associated with the node, show the tip and fire 1.1464 + // off a timer to auto-hide it. 1.1465 + 1.1466 + nsXPIDLString tooltipText; 1.1467 + if (self->mTooltipTextProvider) { 1.1468 + bool textFound = false; 1.1469 + 1.1470 + self->mTooltipTextProvider->GetNodeText( 1.1471 + self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound); 1.1472 + 1.1473 + if (textFound) { 1.1474 + nsString tipText(tooltipText); 1.1475 + self->CreateAutoHideTimer(); 1.1476 + nsIntPoint screenDot = widget->WidgetToScreenOffset(); 1.1477 + self->ShowTooltip (self->mMouseScreenX - screenDot.x, 1.1478 + self->mMouseScreenY - screenDot.y, 1.1479 + tipText); 1.1480 + } 1.1481 + } 1.1482 + 1.1483 + // release tooltip target if there is one, NO MATTER WHAT 1.1484 + self->mPossibleTooltipNode = nullptr; 1.1485 + } // if "self" data valid 1.1486 + 1.1487 +} // sTooltipCallback 1.1488 + 1.1489 + 1.1490 +// 1.1491 +// CreateAutoHideTimer 1.1492 +// 1.1493 +// Create a new timer to see if we should auto-hide. It's ok if this fails. 1.1494 +// 1.1495 +void 1.1496 +ChromeTooltipListener::CreateAutoHideTimer() 1.1497 +{ 1.1498 + // just to be anal (er, safe) 1.1499 + if ( mAutoHideTimer ) { 1.1500 + mAutoHideTimer->Cancel(); 1.1501 + mAutoHideTimer = nullptr; 1.1502 + } 1.1503 + 1.1504 + mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.1505 + if ( mAutoHideTimer ) 1.1506 + mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, 1.1507 + nsITimer::TYPE_ONE_SHOT); 1.1508 + 1.1509 +} // CreateAutoHideTimer 1.1510 + 1.1511 + 1.1512 +// 1.1513 +// sAutoHideCallback 1.1514 +// 1.1515 +// This fires after a tooltip has been open for a certain length of time. Just tell 1.1516 +// the listener to close the popup. We don't have to worry, because HideTooltip() can 1.1517 +// be called multiple times, even if the tip has already been closed. 1.1518 +// 1.1519 +void 1.1520 +ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener) 1.1521 +{ 1.1522 + ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener); 1.1523 + if ( self ) 1.1524 + self->HideTooltip(); 1.1525 + 1.1526 + // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup(); 1.1527 + 1.1528 +} // sAutoHideCallback 1.1529 + 1.1530 + 1.1531 +NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) 1.1532 + 1.1533 + 1.1534 +// 1.1535 +// ChromeTooltipListener ctor 1.1536 +// 1.1537 +ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) 1.1538 + : mContextMenuListenerInstalled(false), 1.1539 + mWebBrowser(inBrowser), 1.1540 + mWebBrowserChrome(inChrome) 1.1541 +{ 1.1542 +} // ctor 1.1543 + 1.1544 + 1.1545 +// 1.1546 +// ChromeTooltipListener dtor 1.1547 +// 1.1548 +ChromeContextMenuListener::~ChromeContextMenuListener() 1.1549 +{ 1.1550 +} // dtor 1.1551 + 1.1552 + 1.1553 +// 1.1554 +// AddContextMenuListener 1.1555 +// 1.1556 +// Subscribe to the events that will allow us to track context menus. Bascially, this 1.1557 +// is just the context-menu DOM event. 1.1558 +// 1.1559 +NS_IMETHODIMP 1.1560 +ChromeContextMenuListener::AddContextMenuListener() 1.1561 +{ 1.1562 + if (mEventTarget) { 1.1563 + nsresult rv = 1.1564 + mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, 1.1565 + false, false); 1.1566 + NS_ENSURE_SUCCESS(rv, rv); 1.1567 + 1.1568 + mContextMenuListenerInstalled = true; 1.1569 + } 1.1570 + 1.1571 + return NS_OK; 1.1572 +} 1.1573 + 1.1574 + 1.1575 +// 1.1576 +// RemoveContextMenuListener 1.1577 +// 1.1578 +// Unsubscribe from all the various context menu events that we were listening to. 1.1579 +// 1.1580 +NS_IMETHODIMP 1.1581 +ChromeContextMenuListener::RemoveContextMenuListener() 1.1582 +{ 1.1583 + if (mEventTarget) { 1.1584 + nsresult rv = 1.1585 + mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, 1.1586 + false); 1.1587 + NS_ENSURE_SUCCESS(rv, rv); 1.1588 + 1.1589 + mContextMenuListenerInstalled = false; 1.1590 + } 1.1591 + 1.1592 + return NS_OK; 1.1593 +} 1.1594 + 1.1595 + 1.1596 +// 1.1597 +// AddChromeListeners 1.1598 +// 1.1599 +// Hook up things to the chrome like context menus and tooltips, if the chrome 1.1600 +// has implemented the right interfaces. 1.1601 +// 1.1602 +NS_IMETHODIMP 1.1603 +ChromeContextMenuListener::AddChromeListeners() 1.1604 +{ 1.1605 + if (!mEventTarget) 1.1606 + GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); 1.1607 + 1.1608 + // Register the appropriate events for context menus, but only if 1.1609 + // the embedding chrome cares. 1.1610 + nsresult rv = NS_OK; 1.1611 + 1.1612 + nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) ); 1.1613 + nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) ); 1.1614 + if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled ) 1.1615 + rv = AddContextMenuListener(); 1.1616 + 1.1617 + return rv; 1.1618 + 1.1619 +} // AddChromeListeners 1.1620 + 1.1621 + 1.1622 +// 1.1623 +// RemoveChromeListeners 1.1624 +// 1.1625 +// Unsubscribe from the various things we've hooked up to the window root. 1.1626 +// 1.1627 +NS_IMETHODIMP 1.1628 +ChromeContextMenuListener::RemoveChromeListeners() 1.1629 +{ 1.1630 + if ( mContextMenuListenerInstalled ) 1.1631 + RemoveContextMenuListener(); 1.1632 + 1.1633 + mEventTarget = nullptr; 1.1634 + 1.1635 + // it really doesn't matter if these fail... 1.1636 + return NS_OK; 1.1637 + 1.1638 +} // RemoveChromeTooltipListeners 1.1639 + 1.1640 + 1.1641 + 1.1642 +// 1.1643 +// ContextMenu 1.1644 +// 1.1645 +// We're on call to show the context menu. Dig around in the DOM to 1.1646 +// find the type of object we're dealing with and notify the front 1.1647 +// end chrome. 1.1648 +// 1.1649 +NS_IMETHODIMP 1.1650 +ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) 1.1651 +{ 1.1652 + nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent); 1.1653 + NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED); 1.1654 + 1.1655 + bool isDefaultPrevented = false; 1.1656 + aMouseEvent->GetDefaultPrevented(&isDefaultPrevented); 1.1657 + if (isDefaultPrevented) { 1.1658 + return NS_OK; 1.1659 + } 1.1660 + 1.1661 + nsCOMPtr<EventTarget> targetNode = aMouseEvent->InternalDOMEvent()->GetTarget(); 1.1662 + if (!targetNode) 1.1663 + return NS_ERROR_NULL_POINTER; 1.1664 + 1.1665 + nsCOMPtr<nsIDOMNode> targetDOMnode; 1.1666 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode); 1.1667 + if (!node) 1.1668 + return NS_OK; 1.1669 + 1.1670 + // Stop the context menu event going to other windows (bug 78396) 1.1671 + aMouseEvent->PreventDefault(); 1.1672 + 1.1673 + // If the listener is a nsIContextMenuListener2, create the info object 1.1674 + nsCOMPtr<nsIContextMenuListener2> menuListener2(do_QueryInterface(mWebBrowserChrome)); 1.1675 + nsContextMenuInfo *menuInfoImpl = nullptr; 1.1676 + nsCOMPtr<nsIContextMenuInfo> menuInfo; 1.1677 + if (menuListener2) { 1.1678 + menuInfoImpl = new nsContextMenuInfo; 1.1679 + menuInfo = menuInfoImpl; 1.1680 + } 1.1681 + 1.1682 + uint32_t flags = nsIContextMenuListener::CONTEXT_NONE; 1.1683 + uint32_t flags2 = nsIContextMenuListener2::CONTEXT_NONE; 1.1684 + 1.1685 + // XXX test for selected text 1.1686 + 1.1687 + uint16_t nodeType; 1.1688 + nsresult res = node->GetNodeType(&nodeType); 1.1689 + NS_ENSURE_SUCCESS(res, res); 1.1690 + 1.1691 + // First, checks for nodes that never have children. 1.1692 + if (nodeType == nsIDOMNode::ELEMENT_NODE) { 1.1693 + nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(node)); 1.1694 + if (content) { 1.1695 + nsCOMPtr<nsIURI> imgUri; 1.1696 + content->GetCurrentURI(getter_AddRefs(imgUri)); 1.1697 + if (imgUri) { 1.1698 + flags |= nsIContextMenuListener::CONTEXT_IMAGE; 1.1699 + flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE; 1.1700 + targetDOMnode = node; 1.1701 + } 1.1702 + } 1.1703 + 1.1704 + nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(node)); 1.1705 + if (formControl) { 1.1706 + if (formControl->GetType() == NS_FORM_TEXTAREA) { 1.1707 + flags |= nsIContextMenuListener::CONTEXT_TEXT; 1.1708 + flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; 1.1709 + targetDOMnode = node; 1.1710 + } else { 1.1711 + nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(formControl)); 1.1712 + if (inputElement) { 1.1713 + flags |= nsIContextMenuListener::CONTEXT_INPUT; 1.1714 + flags2 |= nsIContextMenuListener2::CONTEXT_INPUT; 1.1715 + 1.1716 + if (menuListener2) { 1.1717 + if (formControl->IsSingleLineTextControl(false)) { 1.1718 + flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; 1.1719 + } 1.1720 + } 1.1721 + 1.1722 + targetDOMnode = node; 1.1723 + } 1.1724 + } 1.1725 + } 1.1726 + 1.1727 + // always consume events for plugins and Java who may throw their 1.1728 + // own context menus but not for image objects. Document objects 1.1729 + // will never be targets or ancestors of targets, so that's OK. 1.1730 + nsCOMPtr<nsIDOMHTMLObjectElement> objectElement; 1.1731 + if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) 1.1732 + objectElement = do_QueryInterface(node); 1.1733 + nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement(do_QueryInterface(node)); 1.1734 + nsCOMPtr<nsIDOMHTMLAppletElement> appletElement(do_QueryInterface(node)); 1.1735 + 1.1736 + if (objectElement || embedElement || appletElement) 1.1737 + return NS_OK; 1.1738 + } 1.1739 + 1.1740 + // Bubble out, looking for items of interest 1.1741 + do { 1.1742 + uint16_t nodeType; 1.1743 + res = node->GetNodeType(&nodeType); 1.1744 + NS_ENSURE_SUCCESS(res, res); 1.1745 + 1.1746 + if (nodeType == nsIDOMNode::ELEMENT_NODE) { 1.1747 + 1.1748 + // Test if the element has an associated link 1.1749 + nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node)); 1.1750 + 1.1751 + bool hasAttr = false; 1.1752 + res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); 1.1753 + 1.1754 + if (NS_SUCCEEDED(res) && hasAttr) 1.1755 + { 1.1756 + flags |= nsIContextMenuListener::CONTEXT_LINK; 1.1757 + flags2 |= nsIContextMenuListener2::CONTEXT_LINK; 1.1758 + if (!targetDOMnode) 1.1759 + targetDOMnode = node; 1.1760 + if (menuInfoImpl) 1.1761 + menuInfoImpl->SetAssociatedLink(node); 1.1762 + break; // exit do-while 1.1763 + } 1.1764 + } 1.1765 + 1.1766 + // walk-up-the-tree 1.1767 + nsCOMPtr<nsIDOMNode> parentNode; 1.1768 + node->GetParentNode(getter_AddRefs(parentNode)); 1.1769 + node = parentNode; 1.1770 + } while (node); 1.1771 + 1.1772 + if (!flags && !flags2) { 1.1773 + // We found nothing of interest so far, check if we 1.1774 + // have at least an html document. 1.1775 + nsCOMPtr<nsIDOMDocument> document; 1.1776 + node = do_QueryInterface(targetNode); 1.1777 + node->GetOwnerDocument(getter_AddRefs(document)); 1.1778 + nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document)); 1.1779 + if (htmlDocument) { 1.1780 + flags |= nsIContextMenuListener::CONTEXT_DOCUMENT; 1.1781 + flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT; 1.1782 + targetDOMnode = node; 1.1783 + if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) { 1.1784 + // check if this is a background image that the user was trying to click on 1.1785 + // and if the listener is ready for that (only nsIContextMenuListener2 and up) 1.1786 + if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) { 1.1787 + flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE; 1.1788 + // For the embedder to get the correct background image 1.1789 + // targetDOMnode must point to the original node. 1.1790 + targetDOMnode = do_QueryInterface(targetNode); 1.1791 + } 1.1792 + } 1.1793 + } 1.1794 + } 1.1795 + 1.1796 + // we need to cache the event target into the focus controller's popupNode 1.1797 + // so we can get at it later from command code, etc.: 1.1798 + 1.1799 + // get the dom window 1.1800 + nsCOMPtr<nsIDOMWindow> win; 1.1801 + res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win)); 1.1802 + NS_ENSURE_SUCCESS(res, res); 1.1803 + NS_ENSURE_TRUE(win, NS_ERROR_FAILURE); 1.1804 + 1.1805 + nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(win)); 1.1806 + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1.1807 + nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot(); 1.1808 + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); 1.1809 + if (root) { 1.1810 + // set the window root's popup node to the event target 1.1811 + root->SetPopupNode(targetDOMnode); 1.1812 + } 1.1813 + 1.1814 + // Tell the listener all about the event 1.1815 + if ( menuListener2 ) { 1.1816 + menuInfoImpl->SetMouseEvent(aMouseEvent); 1.1817 + menuInfoImpl->SetDOMNode(targetDOMnode); 1.1818 + menuListener2->OnShowContextMenu(flags2, menuInfo); 1.1819 + } 1.1820 + else { 1.1821 + nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome)); 1.1822 + if ( menuListener ) 1.1823 + menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode); 1.1824 + } 1.1825 + 1.1826 + return NS_OK; 1.1827 + 1.1828 +} // MouseDown