embedding/browser/webBrowser/nsDocShellTreeOwner.cpp

changeset 0
6474c204b198
     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

mercurial