embedding/browser/webBrowser/nsDocShellTreeOwner.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // Local Includes
     7 #include "nsDocShellTreeOwner.h"
     8 #include "nsWebBrowser.h"
    10 // Helper Classes
    11 #include "nsStyleCoord.h"
    12 #include "nsSize.h"
    13 #include "nsHTMLReflowState.h"
    14 #include "nsIServiceManager.h"
    15 #include "nsComponentManagerUtils.h"
    16 #include "nsXPIDLString.h"
    17 #include "nsIAtom.h"
    18 #include "nsReadableUtils.h"
    19 #include "nsUnicharUtils.h"
    20 #include "nsISimpleEnumerator.h"
    21 #include "mozilla/LookAndFeel.h"
    23 // Interfaces needed to be included
    24 #include "nsPresContext.h"
    25 #include "nsIContextMenuListener.h"
    26 #include "nsIContextMenuListener2.h"
    27 #include "nsITooltipListener.h"
    28 #include "nsIDOMNode.h"
    29 #include "nsIDOMNodeList.h"
    30 #include "nsIDOMDocument.h"
    31 #include "nsIDOMDocumentType.h"
    32 #include "nsIDOMElement.h"
    33 #include "Link.h"
    34 #include "mozilla/dom/Element.h"
    35 #include "mozilla/dom/SVGTitleElement.h"
    36 #include "nsIDOMEvent.h"
    37 #include "nsIDOMMouseEvent.h"
    38 #include "nsIFormControl.h"
    39 #include "nsIDOMHTMLInputElement.h"
    40 #include "nsIDOMHTMLTextAreaElement.h"
    41 #include "nsIDOMHTMLHtmlElement.h"
    42 #include "nsIDOMHTMLAppletElement.h"
    43 #include "nsIDOMHTMLObjectElement.h"
    44 #include "nsIDOMHTMLEmbedElement.h"
    45 #include "nsIDOMHTMLDocument.h"
    46 #include "nsIImageLoadingContent.h"
    47 #include "nsIWebNavigation.h"
    48 #include "nsIDOMHTMLElement.h"
    49 #include "nsIPresShell.h"
    50 #include "nsPIDOMWindow.h"
    51 #include "nsPIWindowRoot.h"
    52 #include "nsIDOMWindowCollection.h"
    53 #include "nsIWindowWatcher.h"
    54 #include "nsPIWindowWatcher.h"
    55 #include "nsIPrompt.h"
    56 #include "nsRect.h"
    57 #include "nsIWebBrowserChromeFocus.h"
    58 #include "nsIContent.h"
    59 #include "imgIContainer.h"
    60 #include "nsContextMenuInfo.h"
    61 #include "nsPresContext.h"
    62 #include "nsViewManager.h"
    63 #include "nsView.h"
    64 #include "nsIDOMDragEvent.h"
    65 #include "nsIConstraintValidation.h"
    66 #include "mozilla/Attributes.h"
    67 #include "mozilla/EventListenerManager.h"
    68 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
    70 using namespace mozilla;
    71 using namespace mozilla::dom;
    73 //
    74 // GetEventReceiver
    75 //
    76 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
    77 // a |EventTarget| via the window root and chrome event handler.
    78 //
    79 static nsresult
    80 GetDOMEventTarget(nsWebBrowser* inBrowser, EventTarget** aTarget)
    81 {
    82   NS_ENSURE_ARG_POINTER(inBrowser);
    84   nsCOMPtr<nsIDOMWindow> domWindow;
    85   inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
    86   NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
    88   nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
    89   NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
    90   nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot();
    91   NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
    92   nsCOMPtr<EventTarget> target =
    93     rootWindow->GetChromeEventHandler();
    94   NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
    95   target.forget(aTarget);
    97   return NS_OK;
    98 }
   101 //*****************************************************************************
   102 //***    nsDocShellTreeOwner: Object Management
   103 //*****************************************************************************
   105 nsDocShellTreeOwner::nsDocShellTreeOwner() :
   106    mWebBrowser(nullptr), 
   107    mTreeOwner(nullptr),
   108    mPrimaryContentShell(nullptr),
   109    mWebBrowserChrome(nullptr),
   110    mOwnerWin(nullptr),
   111    mOwnerRequestor(nullptr),
   112    mChromeTooltipListener(nullptr),
   113    mChromeContextMenuListener(nullptr)
   114 {
   115 }
   117 nsDocShellTreeOwner::~nsDocShellTreeOwner()
   118 {
   119   RemoveChromeListeners();
   120 }
   122 //*****************************************************************************
   123 // nsDocShellTreeOwner::nsISupports
   124 //*****************************************************************************   
   126 NS_IMPL_ADDREF(nsDocShellTreeOwner)
   127 NS_IMPL_RELEASE(nsDocShellTreeOwner)
   129 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
   130     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
   131     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
   132     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   133     NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   134     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   135     NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   136     NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
   137     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   138 NS_INTERFACE_MAP_END
   140 //*****************************************************************************
   141 // nsDocShellTreeOwner::nsIInterfaceRequestor
   142 //*****************************************************************************   
   144 NS_IMETHODIMP
   145 nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
   146 {
   147   NS_ENSURE_ARG_POINTER(aSink);
   149   if(NS_SUCCEEDED(QueryInterface(aIID, aSink)))
   150     return NS_OK;
   152   if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
   153     if (mWebBrowserChromeWeak != nullptr)
   154       return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
   155     return mOwnerWin->QueryInterface(aIID, aSink);
   156   }
   158   if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
   159     nsIPrompt *prompt;
   160     EnsurePrompter();
   161     prompt = mPrompter;
   162     if (prompt) {
   163       NS_ADDREF(prompt);
   164       *aSink = prompt;
   165       return NS_OK;
   166     }
   167     return NS_NOINTERFACE;
   168   }
   170   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
   171     nsIAuthPrompt *prompt;
   172     EnsureAuthPrompter();
   173     prompt = mAuthPrompter;
   174     if (prompt) {
   175       NS_ADDREF(prompt);
   176       *aSink = prompt;
   177       return NS_OK;
   178     }
   179     return NS_NOINTERFACE;
   180   }
   182   nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor();
   183   if (req)
   184     return req->GetInterface(aIID, aSink);
   186   return NS_NOINTERFACE;
   187 }
   189 //*****************************************************************************
   190 // nsDocShellTreeOwner::nsIDocShellTreeOwner
   191 //*****************************************************************************   
   193 NS_IMETHODIMP
   194 nsDocShellTreeOwner::FindItemWithName(const char16_t* aName,
   195                                       nsIDocShellTreeItem* aRequestor,
   196                                       nsIDocShellTreeItem* aOriginalRequestor,
   197                                       nsIDocShellTreeItem** aFoundItem)
   198 {
   199   NS_ENSURE_ARG(aName);
   200   NS_ENSURE_ARG_POINTER(aFoundItem);
   201   *aFoundItem = nullptr; // if we don't find one, we return NS_OK and a null result 
   202   nsresult rv;
   204   nsAutoString name(aName);
   206   if (!mWebBrowser)
   207     return NS_OK; // stymied
   209   /* special cases */
   210   if(name.IsEmpty())
   211     return NS_OK;
   212   if(name.LowerCaseEqualsLiteral("_blank"))
   213     return NS_OK;
   214   // _main is an IE target which should be case-insensitive but isn't
   215   // see bug 217886 for details
   216   // XXXbz what if our browser isn't targetable?  We need to handle that somehow.
   217   if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) {
   218     *aFoundItem = mWebBrowser->mDocShell;
   219     NS_IF_ADDREF(*aFoundItem);
   220     return NS_OK;
   221   }
   223   if (!SameCOMIdentity(aRequestor, mWebBrowser->mDocShell)) {
   224     // This isn't a request coming up from our kid, so check with said kid
   225     nsISupports* thisSupports = static_cast<nsIDocShellTreeOwner*>(this);
   226     rv = mWebBrowser->mDocShell->FindItemWithName(aName, thisSupports,
   227                                                   aOriginalRequestor, aFoundItem);
   228     if (NS_FAILED(rv) || *aFoundItem) {
   229       return rv;
   230     }
   231   }
   233   // next, if we have a parent and it isn't the requestor, ask it
   234   if(mTreeOwner) {
   235     nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
   236     if (mTreeOwner != reqAsTreeOwner)
   237       return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShell,
   238                                           aOriginalRequestor, aFoundItem);
   239     return NS_OK;
   240   }
   242   // finally, failing everything else, search all windows
   243   return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor,
   244                                        aFoundItem);
   245 }
   247 nsresult
   248 nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const char16_t* aName,
   249                                                    nsIDocShellTreeItem* aRequestor,
   250                                                    nsIDocShellTreeItem* aOriginalRequestor,
   251                                                    nsIDocShellTreeItem** aFoundItem)
   252 {
   253   // search for the item across the list of top-level windows
   254   nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
   255   if (!wwatch)
   256     return NS_OK;
   258   return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor,
   259                                   aFoundItem);
   260 }
   262 void
   263 nsDocShellTreeOwner::EnsurePrompter()
   264 {
   265   if (mPrompter)
   266     return;
   268   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
   269   if (wwatch && mWebBrowser) {
   270     nsCOMPtr<nsIDOMWindow> domWindow;
   271     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
   272     if (domWindow)
   273       wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter));
   274   }
   275 }
   277 void
   278 nsDocShellTreeOwner::EnsureAuthPrompter()
   279 {
   280   if (mAuthPrompter)
   281     return;
   283   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
   284   if (wwatch && mWebBrowser) {
   285     nsCOMPtr<nsIDOMWindow> domWindow;
   286     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
   287     if (domWindow)
   288       wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter));
   289   }
   290 }
   292 void
   293 nsDocShellTreeOwner::AddToWatcher()
   294 {
   295   if (mWebBrowser) {
   296     nsCOMPtr<nsIDOMWindow> domWindow;
   297     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
   298     if (domWindow) {
   299       nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
   300       if (wwatch) {
   301         nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
   302         if (webBrowserChrome)
   303           wwatch->AddWindow(domWindow, webBrowserChrome);
   304       }
   305     }
   306   }
   307 }
   309 void
   310 nsDocShellTreeOwner::RemoveFromWatcher()
   311 {
   312   if (mWebBrowser) {
   313     nsCOMPtr<nsIDOMWindow> domWindow;
   314     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
   315     if (domWindow) {
   316       nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
   317       if (wwatch)
   318         wwatch->RemoveWindow(domWindow);
   319     }
   320   }
   321 }
   324 NS_IMETHODIMP
   325 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
   326                                        bool aPrimary, bool aTargetable,
   327                                        const nsAString& aID)
   328 {
   329    if(mTreeOwner)
   330       return mTreeOwner->ContentShellAdded(aContentShell, aPrimary,
   331                                            aTargetable, aID);
   333    if (aPrimary)
   334       mPrimaryContentShell = aContentShell;
   335    return NS_OK;
   336 }
   338 NS_IMETHODIMP
   339 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
   340 {
   341   if(mTreeOwner)
   342     return mTreeOwner->ContentShellRemoved(aContentShell);
   344   if(mPrimaryContentShell == aContentShell)
   345     mPrimaryContentShell = nullptr;
   347   return NS_OK;
   348 }
   350 NS_IMETHODIMP
   351 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell)
   352 {
   353    NS_ENSURE_ARG_POINTER(aShell);
   355    if (mTreeOwner)
   356        return mTreeOwner->GetPrimaryContentShell(aShell);
   358    *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell);
   359    NS_IF_ADDREF(*aShell);
   361    return NS_OK;
   362 }
   364 NS_IMETHODIMP
   365 nsDocShellTreeOwner::GetContentWindow(JSContext* aCx,
   366                                       JS::MutableHandle<JS::Value> aVal)
   367 {
   368   if (mTreeOwner)
   369     return mTreeOwner->GetContentWindow(aCx, aVal);
   371   return NS_ERROR_NOT_IMPLEMENTED;
   372 }
   374 NS_IMETHODIMP
   375 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
   376                                  int32_t aCX, int32_t aCY)
   377 {
   378    nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
   380    NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
   382    if(mTreeOwner)
   383       return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
   385    if(aShellItem == mWebBrowser->mDocShell)
   386       return webBrowserChrome->SizeBrowserTo(aCX, aCY);
   388    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
   389    NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
   391    nsCOMPtr<nsIDOMDocument> domDocument;
   392    webNav->GetDocument(getter_AddRefs(domDocument));
   393    NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE);
   395    nsCOMPtr<nsIDOMElement> domElement;
   396    domDocument->GetDocumentElement(getter_AddRefs(domElement));
   397    NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE);
   399    // Set the preferred Size
   400    //XXX
   401    NS_ERROR("Implement this");
   402    /*
   403    Set the preferred size on the aShellItem.
   404    */
   406    nsRefPtr<nsPresContext> presContext;
   407    mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
   408    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
   410    nsIPresShell *presShell = presContext->GetPresShell();
   411    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
   413    NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE,
   414       NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE);
   416    nsRect shellArea = presContext->GetVisibleArea();
   418    int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width);
   419    int32_t browserCY = presContext->AppUnitsToDevPixels(shellArea.height);
   421    return webBrowserChrome->SizeBrowserTo(browserCX, browserCY);
   422 }
   424 NS_IMETHODIMP
   425 nsDocShellTreeOwner::SetPersistence(bool aPersistPosition,
   426                                     bool aPersistSize,
   427                                     bool aPersistSizeMode)
   428 {
   429   return NS_ERROR_NOT_IMPLEMENTED;
   430 }
   432 NS_IMETHODIMP
   433 nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition,
   434                                     bool* aPersistSize,
   435                                     bool* aPersistSizeMode)
   436 {
   437   return NS_ERROR_NOT_IMPLEMENTED;
   438 }
   440 NS_IMETHODIMP
   441 nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult)
   442 {
   443   if(mTreeOwner) {
   444     mTreeOwner->GetTargetableShellCount(aResult);
   445   } else {
   446     *aResult = 0;
   447   }
   449   return NS_OK;
   450 }
   452 //*****************************************************************************
   453 // nsDocShellTreeOwner::nsIBaseWindow
   454 //*****************************************************************************   
   457 NS_IMETHODIMP
   458 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
   459                                 nsIWidget* aParentWidget, int32_t aX,
   460                                 int32_t aY, int32_t aCX, int32_t aCY)   
   461 {
   462   return NS_ERROR_NULL_POINTER;
   463 }
   465 NS_IMETHODIMP
   466 nsDocShellTreeOwner::Create()
   467 {
   468   return NS_ERROR_NULL_POINTER;
   469 }
   471 NS_IMETHODIMP
   472 nsDocShellTreeOwner::Destroy()
   473 {
   474   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
   475   if (webBrowserChrome)
   476   {
   477     return webBrowserChrome->DestroyBrowserWindow();
   478   }
   480   return NS_ERROR_NULL_POINTER;
   481 }
   483 NS_IMETHODIMP
   484 nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
   485 {
   486   if (mWebBrowser) {
   487     return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale);
   488   }
   490   *aScale = 1.0;
   491   return NS_OK;
   492 }
   494 NS_IMETHODIMP
   495 nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY)
   496 {
   497   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   498   if (ownerWin)
   499   {
   500     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
   501                                    aX, aY, 0, 0);
   502   }
   503   return NS_ERROR_NULL_POINTER;
   504 }
   506 NS_IMETHODIMP
   507 nsDocShellTreeOwner::GetPosition(int32_t* aX, int32_t* aY)
   508 {
   509   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   510   if (ownerWin)
   511   {
   512     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
   513                                    aX, aY, nullptr, nullptr);
   514   }
   515   return NS_ERROR_NULL_POINTER;
   516 }
   518 NS_IMETHODIMP
   519 nsDocShellTreeOwner::SetSize(int32_t aCX, int32_t aCY, bool aRepaint)
   520 {
   521   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   522   if (ownerWin)
   523   {
   524     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
   525                                    0, 0, aCX, aCY);
   526   }
   527   return NS_ERROR_NULL_POINTER;
   528 }
   530 NS_IMETHODIMP
   531 nsDocShellTreeOwner::GetSize(int32_t* aCX, int32_t* aCY)
   532 {
   533   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   534   if (ownerWin)
   535   {
   536     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
   537                                    nullptr, nullptr, aCX, aCY);
   538   }
   539   return NS_ERROR_NULL_POINTER;
   540 }
   542 NS_IMETHODIMP
   543 nsDocShellTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX,
   544                                         int32_t aCY, bool aRepaint)
   545 {
   546   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   547   if (ownerWin)
   548   {
   549     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
   550                                    nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
   551                                    aX, aY, aCX, aCY);
   552   }
   553   return NS_ERROR_NULL_POINTER;
   554 }
   556 NS_IMETHODIMP
   557 nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX,
   558                                         int32_t* aCY)
   559 {
   560   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   561   if (ownerWin)
   562   {
   563     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
   564                                    nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
   565                                    aX, aY, aCX, aCY);
   566   }
   567   return NS_ERROR_NULL_POINTER;
   568 }
   570 NS_IMETHODIMP
   571 nsDocShellTreeOwner::Repaint(bool aForce)
   572 {
   573   return NS_ERROR_NULL_POINTER;
   574 }
   576 NS_IMETHODIMP
   577 nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget)
   578 {
   579   return NS_ERROR_NULL_POINTER;
   580 }
   582 NS_IMETHODIMP
   583 nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget)
   584 {
   585   return NS_ERROR_NULL_POINTER;
   586 }
   588 NS_IMETHODIMP
   589 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
   590 {
   591   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   592   if (ownerWin)
   593   {
   594     return ownerWin->GetSiteWindow(aParentNativeWindow);
   595   }
   596   return NS_ERROR_NULL_POINTER;
   597 }
   599 NS_IMETHODIMP
   600 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
   601 {
   602   return NS_ERROR_NULL_POINTER;
   603 }
   605 NS_IMETHODIMP
   606 nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle)
   607 {
   608   // the nativeHandle should be accessed from nsIXULWindow
   609   return NS_ERROR_NOT_IMPLEMENTED;
   610 }
   612 NS_IMETHODIMP
   613 nsDocShellTreeOwner::GetVisibility(bool* aVisibility)
   614 {
   615   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   616   if (ownerWin)
   617   {
   618     return ownerWin->GetVisibility(aVisibility);
   619   }
   620   return NS_ERROR_NULL_POINTER;
   621 }
   623 NS_IMETHODIMP
   624 nsDocShellTreeOwner::SetVisibility(bool aVisibility)
   625 {
   626   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   627   if (ownerWin)
   628   {
   629     return ownerWin->SetVisibility(aVisibility);
   630   }
   631   return NS_ERROR_NULL_POINTER;
   632 }
   634 NS_IMETHODIMP
   635 nsDocShellTreeOwner::GetEnabled(bool *aEnabled)
   636 {
   637   NS_ENSURE_ARG_POINTER(aEnabled);
   638   *aEnabled = true;
   639   return NS_ERROR_NOT_IMPLEMENTED;
   640 }
   642 NS_IMETHODIMP
   643 nsDocShellTreeOwner::SetEnabled(bool aEnabled)
   644 {
   645   return NS_ERROR_NOT_IMPLEMENTED;
   646 }
   648 NS_IMETHODIMP
   649 nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget)
   650 {
   651     return NS_ERROR_NULL_POINTER;
   652 }
   654 NS_IMETHODIMP
   655 nsDocShellTreeOwner::SetFocus()
   656 {
   657   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   658   if (ownerWin)
   659   {
   660     return ownerWin->SetFocus();
   661   }
   662   return NS_ERROR_NULL_POINTER;
   663 }
   665 NS_IMETHODIMP
   666 nsDocShellTreeOwner::GetTitle(char16_t** aTitle)
   667 {
   668   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   669   if (ownerWin)
   670   {
   671     return ownerWin->GetTitle(aTitle);
   672   }
   673   return NS_ERROR_NULL_POINTER;
   674 }
   676 NS_IMETHODIMP
   677 nsDocShellTreeOwner::SetTitle(const char16_t* aTitle)
   678 {
   679   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   680   if (ownerWin)
   681   {
   682     return ownerWin->SetTitle(aTitle);
   683   }
   684   return NS_ERROR_NULL_POINTER;
   685 }
   688 //*****************************************************************************
   689 // nsDocShellTreeOwner::nsIWebProgressListener
   690 //*****************************************************************************   
   693 NS_IMETHODIMP
   694 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress,
   695                                       nsIRequest* aRequest,
   696                                       int32_t aCurSelfProgress,
   697                                       int32_t aMaxSelfProgress, 
   698                                       int32_t aCurTotalProgress,
   699                                       int32_t aMaxTotalProgress)
   700 {
   701     // In the absence of DOM document creation event, this method is the
   702     // most convenient place to install the mouse listener on the
   703     // DOM document.
   704     return AddChromeListeners();
   705 }
   707 NS_IMETHODIMP
   708 nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress,
   709                                    nsIRequest* aRequest,
   710                                    uint32_t aProgressStateFlags,
   711                                    nsresult aStatus)
   712 {
   713     return NS_OK;
   714 }
   716 NS_IMETHODIMP
   717 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
   718                                       nsIRequest* aRequest,
   719                                       nsIURI* aURI,
   720                                       uint32_t aFlags)
   721 {
   722     return NS_OK;
   723 }
   725 NS_IMETHODIMP 
   726 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
   727                                     nsIRequest* aRequest,
   728                                     nsresult aStatus,
   729                                     const char16_t* aMessage)
   730 {
   731     return NS_OK;
   732 }
   734 NS_IMETHODIMP 
   735 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, 
   736                                       nsIRequest *aRequest, 
   737                                       uint32_t state)
   738 {
   739     return NS_OK;
   740 }
   743 //*****************************************************************************
   744 // nsDocShellTreeOwner: Helpers
   745 //*****************************************************************************   
   747 //*****************************************************************************
   748 // nsDocShellTreeOwner: Accessors
   749 //*****************************************************************************   
   751 void
   752 nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
   753 {
   754   if ( !aWebBrowser )
   755     RemoveChromeListeners();
   756   if (aWebBrowser != mWebBrowser) {
   757     mPrompter = 0;
   758     mAuthPrompter = 0;
   759   }
   761   mWebBrowser = aWebBrowser;
   762 }
   764 nsWebBrowser *
   765 nsDocShellTreeOwner::WebBrowser()
   766 {
   767    return mWebBrowser;
   768 }
   770 NS_IMETHODIMP
   771 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
   772 { 
   773   if(aTreeOwner) {
   774     nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner));
   775     NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG);
   776     NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG);
   777     mTreeOwner = aTreeOwner;
   778   }
   779   else {
   780     mTreeOwner = nullptr;
   781     nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
   782     if (!webBrowserChrome)
   783       NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE);
   784   }
   786   return NS_OK;
   787 }
   789 NS_IMETHODIMP
   790 nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome)
   791 {
   792   if(!aWebBrowserChrome) {
   793     mWebBrowserChrome = nullptr;
   794     mOwnerWin = nullptr;
   795     mOwnerRequestor = nullptr;
   796     mWebBrowserChromeWeak = 0;
   797   } else {
   798     nsCOMPtr<nsISupportsWeakReference> supportsweak =
   799                                            do_QueryInterface(aWebBrowserChrome);
   800     if (supportsweak) {
   801       supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak));
   802     } else {
   803       nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome));
   804       nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome));
   806       // it's ok for ownerWin or requestor to be null.
   807       mWebBrowserChrome = aWebBrowserChrome;
   808       mOwnerWin = ownerWin;
   809       mOwnerRequestor = requestor;
   810     }
   811   }
   812   return NS_OK;
   813 }
   816 //
   817 // AddChromeListeners
   818 //
   819 // Hook up things to the chrome like context menus and tooltips, if the chrome
   820 // has implemented the right interfaces.
   821 //
   822 NS_IMETHODIMP
   823 nsDocShellTreeOwner::AddChromeListeners()
   824 {
   825   nsresult rv = NS_OK;
   827   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
   828   if (!webBrowserChrome)
   829     return NS_ERROR_FAILURE;
   831   // install tooltips
   832   if ( !mChromeTooltipListener ) { 
   833     nsCOMPtr<nsITooltipListener>
   834                            tooltipListener(do_QueryInterface(webBrowserChrome));
   835     if ( tooltipListener ) {
   836       mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser,
   837                                                          webBrowserChrome);
   838       if ( mChromeTooltipListener ) {
   839         NS_ADDREF(mChromeTooltipListener);
   840         rv = mChromeTooltipListener->AddChromeListeners();
   841       }
   842       else
   843         rv = NS_ERROR_OUT_OF_MEMORY;
   844     }
   845   }
   847   // install context menus
   848   if ( !mChromeContextMenuListener ) {
   849     nsCOMPtr<nsIContextMenuListener2>
   850                           contextListener2(do_QueryInterface(webBrowserChrome));
   851     nsCOMPtr<nsIContextMenuListener>
   852                            contextListener(do_QueryInterface(webBrowserChrome));
   853     if ( contextListener2 || contextListener ) {
   854       mChromeContextMenuListener =
   855                    new ChromeContextMenuListener(mWebBrowser, webBrowserChrome);
   856       if ( mChromeContextMenuListener ) {
   857         NS_ADDREF(mChromeContextMenuListener);
   858         rv = mChromeContextMenuListener->AddChromeListeners();
   859       }
   860       else
   861         rv = NS_ERROR_OUT_OF_MEMORY;
   862     }
   863   }
   865   // register dragover and drop event listeners with the listener manager
   866   nsCOMPtr<EventTarget> target;
   867   GetDOMEventTarget(mWebBrowser, getter_AddRefs(target));
   869   EventListenerManager* elmP = target->GetOrCreateListenerManager();
   870   if (elmP) {
   871     elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"),
   872                                  TrustedEventsAtSystemGroupBubble());
   873     elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"),
   874                                  TrustedEventsAtSystemGroupBubble());
   875   }
   877   return rv;
   879 } // AddChromeListeners
   882 NS_IMETHODIMP
   883 nsDocShellTreeOwner::RemoveChromeListeners()
   884 {
   885   if ( mChromeTooltipListener ) {
   886     mChromeTooltipListener->RemoveChromeListeners();
   887     NS_RELEASE(mChromeTooltipListener);
   888   }
   889   if ( mChromeContextMenuListener ) {
   890     mChromeContextMenuListener->RemoveChromeListeners();
   891     NS_RELEASE(mChromeContextMenuListener);
   892   }
   894   nsCOMPtr<EventTarget> piTarget;
   895   GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget));
   896   if (!piTarget)
   897     return NS_OK;
   899   EventListenerManager* elmP = piTarget->GetOrCreateListenerManager();
   900   if (elmP)
   901   {
   902     elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"),
   903                                     TrustedEventsAtSystemGroupBubble());
   904     elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"),
   905                                     TrustedEventsAtSystemGroupBubble());
   906   }
   908   return NS_OK;
   909 }
   911 NS_IMETHODIMP
   912 nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent)
   913 {
   914   nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
   915   NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG);
   917   bool defaultPrevented;
   918   aEvent->GetDefaultPrevented(&defaultPrevented);
   919   if (defaultPrevented) {
   920     return NS_OK;
   921   }
   923   nsCOMPtr<nsIDroppedLinkHandler> handler = do_GetService("@mozilla.org/content/dropped-link-handler;1");
   924   if (handler) {
   925     nsAutoString eventType;
   926     aEvent->GetType(eventType);
   927     if (eventType.EqualsLiteral("dragover")) {
   928       bool canDropLink;
   929       handler->CanDropLink(dragEvent, false, &canDropLink);
   930       if (canDropLink)
   931         aEvent->PreventDefault();
   932     }
   933     else if (eventType.EqualsLiteral("drop")) {
   934       nsIWebNavigation* webnav = static_cast<nsIWebNavigation *>(mWebBrowser);
   936       nsAutoString link, name;
   937       if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) {
   938         if (!link.IsEmpty()) {
   939           webnav->LoadURI(link.get(), 0, nullptr, nullptr, nullptr);
   940         }
   941       }
   942       else {
   943         aEvent->StopPropagation();
   944         aEvent->PreventDefault();
   945       }
   946     }
   947   }
   949   return NS_OK;
   950 }
   952 already_AddRefed<nsIWebBrowserChrome>
   953 nsDocShellTreeOwner::GetWebBrowserChrome()
   954 {
   955   nsCOMPtr<nsIWebBrowserChrome> chrome;
   956   if (mWebBrowserChromeWeak) {
   957     chrome = do_QueryReferent(mWebBrowserChromeWeak);
   958   } else if (mWebBrowserChrome) {
   959     chrome = mWebBrowserChrome;
   960   }
   961   return chrome.forget();
   962 }
   964 already_AddRefed<nsIEmbeddingSiteWindow>
   965 nsDocShellTreeOwner::GetOwnerWin()
   966 {
   967   nsCOMPtr<nsIEmbeddingSiteWindow> win;
   968   if (mWebBrowserChromeWeak) {
   969     win = do_QueryReferent(mWebBrowserChromeWeak);
   970   } else if (mOwnerWin) {
   971     win = mOwnerWin;
   972   }
   973   return win.forget();
   974 }
   976 already_AddRefed<nsIInterfaceRequestor>
   977 nsDocShellTreeOwner::GetOwnerRequestor()
   978 {
   979   nsCOMPtr<nsIInterfaceRequestor> req;
   980   if (mWebBrowserChromeWeak) {
   981     req = do_QueryReferent(mWebBrowserChromeWeak);
   982   } else if (mOwnerRequestor) {
   983     req = mOwnerRequestor;
   984   }
   985   return req.forget();
   986 }
   989 ///////////////////////////////////////////////////////////////////////////////
   990 // DefaultTooltipTextProvider
   992 class DefaultTooltipTextProvider MOZ_FINAL : public nsITooltipTextProvider
   993 {
   994 public:
   995     DefaultTooltipTextProvider();
   997     NS_DECL_THREADSAFE_ISUPPORTS
   998     NS_DECL_NSITOOLTIPTEXTPROVIDER
  1000 protected:
  1001     nsCOMPtr<nsIAtom>   mTag_dialog;
  1002     nsCOMPtr<nsIAtom>   mTag_dialogheader;
  1003     nsCOMPtr<nsIAtom>   mTag_window;
  1004 };
  1006 NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider)
  1008 DefaultTooltipTextProvider::DefaultTooltipTextProvider()
  1010     // There are certain element types which we don't want to use
  1011     // as tool tip text. 
  1012     mTag_dialog       = do_GetAtom("dialog");
  1013     mTag_dialogheader = do_GetAtom("dialogheader");
  1014     mTag_window       = do_GetAtom("window");   
  1017 //
  1018 // UseSVGTitle
  1019 //
  1020 // A helper routine that determines whether we're still interested
  1021 // in SVG titles. We need to stop at the SVG root element that
  1022 // has a document node parent
  1023 //
  1024 static bool
  1025 UseSVGTitle(nsIDOMElement *currElement)
  1027   nsCOMPtr<dom::Element> element(do_QueryInterface(currElement));
  1028   if (!element || !element->IsSVG() || !element->GetParentNode())
  1029     return false;
  1031   return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE;
  1034 /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
  1035 NS_IMETHODIMP
  1036 DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, char16_t **aText,
  1037                                         bool *_retval)
  1039   NS_ENSURE_ARG_POINTER(aNode);
  1040   NS_ENSURE_ARG_POINTER(aText);
  1042   nsString outText;
  1044   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
  1046   bool lookingForSVGTitle = true;
  1047   bool found = false;
  1048   nsCOMPtr<nsIDOMNode> current ( aNode );
  1050   // If the element implement the constraint validation API and has no title,
  1051   // show the validation message, if any.
  1052   nsCOMPtr<nsIConstraintValidation> cvElement = do_QueryInterface(current);
  1053   if (cvElement) {
  1054     nsCOMPtr<nsIContent> content = do_QueryInterface(cvElement);
  1055     nsCOMPtr<nsIAtom> titleAtom = do_GetAtom("title");
  1057     nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(content);
  1058     bool formHasNoValidate = false;
  1059     mozilla::dom::Element* form = formControl->GetFormElement();
  1060     if (form) {
  1061       nsCOMPtr<nsIAtom> noValidateAtom = do_GetAtom("novalidate");
  1062       formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom);
  1065     if (!content->HasAttr(kNameSpaceID_None, titleAtom) &&
  1066         !formHasNoValidate) {
  1067       cvElement->GetValidationMessage(outText);
  1068       found = !outText.IsEmpty();
  1072   while ( !found && current ) {
  1073     nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) );
  1074     if ( currElement ) {
  1075       nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
  1076       if (content) {
  1077         nsIAtom *tagAtom = content->Tag();
  1078         if (tagAtom != mTag_dialog &&
  1079             tagAtom != mTag_dialogheader &&
  1080             tagAtom != mTag_window) {
  1081           // first try the normal title attribute...
  1082           currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
  1083           if ( outText.Length() )
  1084             found = true;
  1085           else {
  1086             // ...ok, that didn't work, try it in the XLink namespace
  1087             NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink");
  1088             nsCOMPtr<mozilla::dom::Link> linkContent(do_QueryInterface(currElement));
  1089             if (linkContent) {
  1090               nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal());
  1091               if (uri) {
  1092                 currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText);
  1093                 if ( outText.Length() )
  1094                   found = true;
  1097             else {
  1098               if (lookingForSVGTitle) {
  1099                 lookingForSVGTitle = UseSVGTitle(currElement);
  1101               if (lookingForSVGTitle) {
  1102                 nsINodeList* childNodes = node->ChildNodes();
  1103                 uint32_t childNodeCount = childNodes->Length();
  1104                 for (uint32_t i = 0; i < childNodeCount; i++) {
  1105                   nsIContent* child = childNodes->Item(i);
  1106                   if (child->IsSVG(nsGkAtoms::title)) {
  1107                     static_cast<dom::SVGTitleElement*>(child)->GetTextContent(outText);
  1108                     if ( outText.Length() )
  1109                       found = true;
  1110                     break;
  1120     // not found here, walk up to the parent and keep trying
  1121     if ( !found ) {
  1122       nsCOMPtr<nsIDOMNode> temp ( current );
  1123       temp->GetParentNode(getter_AddRefs(current));
  1125   } // while not found
  1127   *_retval = found;
  1128   *aText = (found) ? ToNewUnicode(outText) : nullptr;
  1130   return NS_OK;
  1133 ///////////////////////////////////////////////////////////////////////////////
  1135 NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener)
  1137 //
  1138 // ChromeTooltipListener ctor
  1139 //
  1141 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
  1142                                              nsIWebBrowserChrome* inChrome) 
  1143   : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
  1144      mTooltipListenerInstalled(false),
  1145      mMouseClientX(0), mMouseClientY(0),
  1146      mShowingTooltip(false)
  1148   mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
  1149   if (!mTooltipTextProvider) {
  1150     nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
  1151     mTooltipTextProvider = do_QueryInterface(pProvider);
  1153 } // ctor
  1156 //
  1157 // ChromeTooltipListener dtor
  1158 //
  1159 ChromeTooltipListener::~ChromeTooltipListener()
  1162 } // dtor
  1165 //
  1166 // AddChromeListeners
  1167 //
  1168 // Hook up things to the chrome like context menus and tooltips, if the chrome
  1169 // has implemented the right interfaces.
  1170 //
  1171 NS_IMETHODIMP
  1172 ChromeTooltipListener::AddChromeListeners()
  1174   if (!mEventTarget)
  1175     GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
  1177   // Register the appropriate events for tooltips, but only if
  1178   // the embedding chrome cares.
  1179   nsresult rv = NS_OK;
  1180   nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
  1181   if ( tooltipListener && !mTooltipListenerInstalled ) {
  1182     rv = AddTooltipListener();
  1183     if ( NS_FAILED(rv) )
  1184       return rv;
  1187   return rv;
  1189 } // AddChromeListeners
  1192 //
  1193 // AddTooltipListener
  1194 //
  1195 // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
  1196 // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
  1197 // of how many succeed so we can clean up correctly in Release().
  1198 //
  1199 NS_IMETHODIMP
  1200 ChromeTooltipListener::AddTooltipListener()
  1202   if (mEventTarget) {
  1203     nsresult rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"),
  1204                                                  this, false, false);
  1205     NS_ENSURE_SUCCESS(rv, rv);
  1206     rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
  1207                                         false, false);
  1208     NS_ENSURE_SUCCESS(rv, rv);
  1209     rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this,
  1210                                         false, false);
  1211     NS_ENSURE_SUCCESS(rv, rv);
  1212     rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
  1213                                         false, false);
  1214     NS_ENSURE_SUCCESS(rv, rv);
  1216     mTooltipListenerInstalled = true;
  1219   return NS_OK;
  1223 //
  1224 // RemoveChromeListeners
  1225 //
  1226 // Unsubscribe from the various things we've hooked up to the window root.
  1227 //
  1228 NS_IMETHODIMP
  1229 ChromeTooltipListener::RemoveChromeListeners ( )
  1231   HideTooltip();
  1233   if ( mTooltipListenerInstalled )
  1234     RemoveTooltipListener();
  1236   mEventTarget = nullptr;
  1238   // it really doesn't matter if these fail...
  1239   return NS_OK;
  1241 } // RemoveChromeTooltipListeners
  1245 //
  1246 // RemoveTooltipListener
  1247 //
  1248 // Unsubscribe from all the various tooltip events that we were listening to
  1249 //
  1250 NS_IMETHODIMP 
  1251 ChromeTooltipListener::RemoveTooltipListener()
  1253   if (mEventTarget) {
  1254     nsresult rv =
  1255       mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this,
  1256                                         false);
  1257     NS_ENSURE_SUCCESS(rv, rv);
  1258     rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
  1259                                            this, false);
  1260     NS_ENSURE_SUCCESS(rv, rv);
  1261     rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this,
  1262                                            false);
  1263     NS_ENSURE_SUCCESS(rv, rv);
  1264     rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
  1265                                            this, false);
  1266     NS_ENSURE_SUCCESS(rv, rv);
  1268     mTooltipListenerInstalled = false;
  1271   return NS_OK;
  1274 NS_IMETHODIMP
  1275 ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
  1277   nsAutoString eventType;
  1278   aEvent->GetType(eventType);
  1280   if (eventType.EqualsLiteral("keydown") ||
  1281       eventType.EqualsLiteral("mousedown") ||
  1282       eventType.EqualsLiteral("mouseout"))
  1283     return HideTooltip();
  1284   if (eventType.EqualsLiteral("mousemove"))
  1285     return MouseMove(aEvent);
  1287   NS_ERROR("Unexpected event type");
  1288   return NS_OK;
  1291 //
  1292 // MouseMove
  1293 //
  1294 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
  1295 // timer fires, we cache the node in |mPossibleTooltipNode|.
  1296 //
  1297 nsresult
  1298 ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
  1300   nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
  1301   if (!mouseEvent)
  1302     return NS_OK;
  1304   // stash the coordinates of the event so that we can still get back to it from within the 
  1305   // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
  1306   // even when the mouse doesn't change position! To get around this, we make sure the
  1307   // mouse has really moved before proceeding.
  1308   int32_t newMouseX, newMouseY;
  1309   mouseEvent->GetClientX(&newMouseX);
  1310   mouseEvent->GetClientY(&newMouseY);
  1311   if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
  1312     return NS_OK;
  1313   mMouseClientX = newMouseX; mMouseClientY = newMouseY;
  1314   mouseEvent->GetScreenX(&mMouseScreenX);
  1315   mouseEvent->GetScreenY(&mMouseScreenY);
  1317   // We want to close the tip if it is being displayed and the mouse moves. Recall 
  1318   // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
  1319   // moves, we want to make sure we reset the timer to show it, so that the delay
  1320   // is from when the mouse stops moving, not when it enters the element.
  1321   if ( mShowingTooltip )
  1322     return HideTooltip();
  1323   if ( mTooltipTimer )
  1324     mTooltipTimer->Cancel();
  1326   mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
  1327   if ( mTooltipTimer ) {
  1328     nsCOMPtr<EventTarget> eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget();
  1329     if ( eventTarget )
  1330       mPossibleTooltipNode = do_QueryInterface(eventTarget);
  1331     if ( mPossibleTooltipNode ) {
  1332       nsresult rv =
  1333         mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
  1334           LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
  1335           nsITimer::TYPE_ONE_SHOT);
  1336       if (NS_FAILED(rv))
  1337         mPossibleTooltipNode = nullptr;
  1340   else
  1341     NS_WARNING ( "Could not create a timer for tooltip tracking" );
  1343   return NS_OK;
  1345 } // MouseMove
  1348 //
  1349 // ShowTooltip
  1350 //
  1351 // Tell the registered chrome that they should show the tooltip
  1352 //
  1353 NS_IMETHODIMP
  1354 ChromeTooltipListener::ShowTooltip(int32_t inXCoords, int32_t inYCoords,
  1355                                    const nsAString & inTipText)
  1357   nsresult rv = NS_OK;
  1359   // do the work to call the client
  1360   nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
  1361   if ( tooltipListener ) {
  1362     rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); 
  1363     if ( NS_SUCCEEDED(rv) )
  1364       mShowingTooltip = true;
  1367   return rv;
  1369 } // ShowTooltip
  1372 //
  1373 // HideTooltip
  1374 //
  1375 // Tell the registered chrome that they should rollup the tooltip
  1376 // NOTE: This routine is safe to call even if the popup is already closed.
  1377 //
  1378 NS_IMETHODIMP
  1379 ChromeTooltipListener::HideTooltip()
  1381   nsresult rv = NS_OK;
  1383   // shut down the relevant timers
  1384   if ( mTooltipTimer ) {
  1385     mTooltipTimer->Cancel();
  1386     mTooltipTimer = nullptr;
  1387     // release tooltip target
  1388     mPossibleTooltipNode = nullptr;
  1390   if ( mAutoHideTimer ) {
  1391     mAutoHideTimer->Cancel();
  1392     mAutoHideTimer = nullptr;
  1395   // if we're showing the tip, tell the chrome to hide it
  1396   if ( mShowingTooltip ) {
  1397     nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
  1398     if ( tooltipListener ) {
  1399       rv = tooltipListener->OnHideTooltip ( );
  1400       if ( NS_SUCCEEDED(rv) )
  1401         mShowingTooltip = false;
  1405   return rv;
  1407 } // HideTooltip
  1410 //
  1411 // sTooltipCallback
  1412 //
  1413 // A timer callback, fired when the mouse has hovered inside of a frame for the 
  1414 // appropriate amount of time. Getting to this point means that we should show the
  1415 // tooltip, but only after we determine there is an appropriate TITLE element.
  1416 //
  1417 // This relies on certain things being cached into the |aChromeTooltipListener| object passed to
  1418 // us by the timer:
  1419 //   -- the x/y coordinates of the mouse      (mMouseClientY, mMouseClientX)
  1420 //   -- the dom node the user hovered over    (mPossibleTooltipNode)
  1421 //
  1422 void
  1423 ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
  1424                                         void *aChromeTooltipListener)
  1426   ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>
  1427                                            (aChromeTooltipListener);
  1428   if ( self && self->mPossibleTooltipNode ){
  1429     // The actual coordinates we want to put the tooltip at are relative to the
  1430     // toplevel docshell of our mWebBrowser.  We know what the screen
  1431     // coordinates of the mouse event were, which means we just need the screen
  1432     // coordinates of the docshell.  Unfortunately, there is no good way to
  1433     // find those short of groveling for the presentation in that docshell and
  1434     // finding the screen coords of its toplevel widget...
  1435     nsCOMPtr<nsIDocShell> docShell =
  1436       do_GetInterface(static_cast<nsIWebBrowser*>(self->mWebBrowser));
  1437     nsCOMPtr<nsIPresShell> shell;
  1438     if (docShell) {
  1439       shell = docShell->GetPresShell();
  1442     nsIWidget* widget = nullptr;
  1443     if (shell) {
  1444       nsViewManager* vm = shell->GetViewManager();
  1445       if (vm) {
  1446         nsView* view = vm->GetRootView();
  1447         if (view) {
  1448           nsPoint offset;
  1449           widget = view->GetNearestWidget(&offset);
  1454     if (!widget) {
  1455       // release tooltip target if there is one, NO MATTER WHAT
  1456       self->mPossibleTooltipNode = nullptr;
  1457       return;
  1460     // if there is text associated with the node, show the tip and fire
  1461     // off a timer to auto-hide it.
  1463     nsXPIDLString tooltipText;
  1464     if (self->mTooltipTextProvider) {
  1465       bool textFound = false;
  1467       self->mTooltipTextProvider->GetNodeText(
  1468           self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
  1470       if (textFound) {
  1471         nsString tipText(tooltipText);
  1472         self->CreateAutoHideTimer();
  1473         nsIntPoint screenDot = widget->WidgetToScreenOffset();
  1474         self->ShowTooltip (self->mMouseScreenX - screenDot.x,
  1475                            self->mMouseScreenY - screenDot.y,
  1476                            tipText);
  1480     // release tooltip target if there is one, NO MATTER WHAT
  1481     self->mPossibleTooltipNode = nullptr;
  1482   } // if "self" data valid
  1484 } // sTooltipCallback
  1487 //
  1488 // CreateAutoHideTimer
  1489 //
  1490 // Create a new timer to see if we should auto-hide. It's ok if this fails.
  1491 //
  1492 void
  1493 ChromeTooltipListener::CreateAutoHideTimer()
  1495   // just to be anal (er, safe)
  1496   if ( mAutoHideTimer ) {
  1497     mAutoHideTimer->Cancel();
  1498     mAutoHideTimer = nullptr;
  1501   mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
  1502   if ( mAutoHideTimer )
  1503     mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, 
  1504                                          nsITimer::TYPE_ONE_SHOT);
  1506 } // CreateAutoHideTimer
  1509 //
  1510 // sAutoHideCallback
  1511 //
  1512 // This fires after a tooltip has been open for a certain length of time. Just tell
  1513 // the listener to close the popup. We don't have to worry, because HideTooltip() can
  1514 // be called multiple times, even if the tip has already been closed.
  1515 //
  1516 void
  1517 ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
  1519   ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener);
  1520   if ( self )
  1521     self->HideTooltip();
  1523   // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
  1525 } // sAutoHideCallback
  1528 NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener)
  1531 //
  1532 // ChromeTooltipListener ctor
  1533 //
  1534 ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) 
  1535   : mContextMenuListenerInstalled(false),
  1536     mWebBrowser(inBrowser),
  1537     mWebBrowserChrome(inChrome)
  1539 } // ctor
  1542 //
  1543 // ChromeTooltipListener dtor
  1544 //
  1545 ChromeContextMenuListener::~ChromeContextMenuListener()
  1547 } // dtor
  1550 //
  1551 // AddContextMenuListener
  1552 //
  1553 // Subscribe to the events that will allow us to track context menus. Bascially, this
  1554 // is just the context-menu DOM event.
  1555 //
  1556 NS_IMETHODIMP
  1557 ChromeContextMenuListener::AddContextMenuListener()
  1559   if (mEventTarget) {
  1560     nsresult rv =
  1561       mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
  1562                                      false, false);
  1563     NS_ENSURE_SUCCESS(rv, rv);
  1565     mContextMenuListenerInstalled = true;
  1568   return NS_OK;
  1572 //
  1573 // RemoveContextMenuListener
  1574 //
  1575 // Unsubscribe from all the various context menu events that we were listening to. 
  1576 //
  1577 NS_IMETHODIMP 
  1578 ChromeContextMenuListener::RemoveContextMenuListener()
  1580   if (mEventTarget) {
  1581     nsresult rv =
  1582       mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
  1583                                         false);
  1584     NS_ENSURE_SUCCESS(rv, rv);
  1586     mContextMenuListenerInstalled = false;
  1589   return NS_OK;
  1593 //
  1594 // AddChromeListeners
  1595 //
  1596 // Hook up things to the chrome like context menus and tooltips, if the chrome
  1597 // has implemented the right interfaces.
  1598 //
  1599 NS_IMETHODIMP
  1600 ChromeContextMenuListener::AddChromeListeners()
  1602   if (!mEventTarget)
  1603     GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
  1605   // Register the appropriate events for context menus, but only if
  1606   // the embedding chrome cares.
  1607   nsresult rv = NS_OK;
  1609   nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) );
  1610   nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
  1611   if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled )
  1612     rv = AddContextMenuListener();
  1614   return rv;
  1616 } // AddChromeListeners
  1619 //
  1620 // RemoveChromeListeners
  1621 //
  1622 // Unsubscribe from the various things we've hooked up to the window root.
  1623 //
  1624 NS_IMETHODIMP
  1625 ChromeContextMenuListener::RemoveChromeListeners()
  1627   if ( mContextMenuListenerInstalled )
  1628     RemoveContextMenuListener();
  1630   mEventTarget = nullptr;
  1632   // it really doesn't matter if these fail...
  1633   return NS_OK;
  1635 } // RemoveChromeTooltipListeners
  1639 //
  1640 // ContextMenu
  1641 //
  1642 // We're on call to show the context menu. Dig around in the DOM to
  1643 // find the type of object we're dealing with and notify the front
  1644 // end chrome.
  1645 //
  1646 NS_IMETHODIMP
  1647 ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent)
  1649   nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
  1650   NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED);
  1652   bool isDefaultPrevented = false;
  1653   aMouseEvent->GetDefaultPrevented(&isDefaultPrevented);
  1654   if (isDefaultPrevented) {
  1655     return NS_OK;
  1658   nsCOMPtr<EventTarget> targetNode = aMouseEvent->InternalDOMEvent()->GetTarget();
  1659   if (!targetNode)
  1660     return NS_ERROR_NULL_POINTER;
  1662   nsCOMPtr<nsIDOMNode> targetDOMnode;
  1663   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
  1664   if (!node)
  1665     return NS_OK;
  1667   // Stop the context menu event going to other windows (bug 78396)
  1668   aMouseEvent->PreventDefault();
  1670   // If the listener is a nsIContextMenuListener2, create the info object
  1671   nsCOMPtr<nsIContextMenuListener2> menuListener2(do_QueryInterface(mWebBrowserChrome));
  1672   nsContextMenuInfo *menuInfoImpl = nullptr;
  1673   nsCOMPtr<nsIContextMenuInfo> menuInfo;
  1674   if (menuListener2) {
  1675     menuInfoImpl = new nsContextMenuInfo;
  1676     menuInfo = menuInfoImpl; 
  1679   uint32_t flags = nsIContextMenuListener::CONTEXT_NONE;
  1680   uint32_t flags2 = nsIContextMenuListener2::CONTEXT_NONE;
  1682   // XXX test for selected text
  1684   uint16_t nodeType;
  1685   nsresult res = node->GetNodeType(&nodeType);
  1686   NS_ENSURE_SUCCESS(res, res);
  1688   // First, checks for nodes that never have children.
  1689   if (nodeType == nsIDOMNode::ELEMENT_NODE) {
  1690     nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(node));
  1691     if (content) {
  1692       nsCOMPtr<nsIURI> imgUri;
  1693       content->GetCurrentURI(getter_AddRefs(imgUri));
  1694       if (imgUri) {
  1695         flags |= nsIContextMenuListener::CONTEXT_IMAGE;
  1696         flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE;
  1697         targetDOMnode = node;
  1701     nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(node));
  1702     if (formControl) {
  1703       if (formControl->GetType() == NS_FORM_TEXTAREA) {
  1704         flags |= nsIContextMenuListener::CONTEXT_TEXT;
  1705         flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
  1706         targetDOMnode = node;
  1707       } else {
  1708         nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(formControl));
  1709         if (inputElement) {
  1710           flags |= nsIContextMenuListener::CONTEXT_INPUT;
  1711           flags2 |= nsIContextMenuListener2::CONTEXT_INPUT;
  1713           if (menuListener2) {
  1714             if (formControl->IsSingleLineTextControl(false)) {
  1715               flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
  1719           targetDOMnode = node;
  1724     // always consume events for plugins and Java who may throw their
  1725     // own context menus but not for image objects.  Document objects
  1726     // will never be targets or ancestors of targets, so that's OK.
  1727     nsCOMPtr<nsIDOMHTMLObjectElement> objectElement;
  1728     if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE))
  1729       objectElement = do_QueryInterface(node);
  1730     nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement(do_QueryInterface(node));
  1731     nsCOMPtr<nsIDOMHTMLAppletElement> appletElement(do_QueryInterface(node));
  1733     if (objectElement || embedElement || appletElement)
  1734       return NS_OK;
  1737   // Bubble out, looking for items of interest
  1738   do {
  1739     uint16_t nodeType;
  1740     res = node->GetNodeType(&nodeType);
  1741     NS_ENSURE_SUCCESS(res, res);
  1743     if (nodeType == nsIDOMNode::ELEMENT_NODE) {
  1745       // Test if the element has an associated link
  1746       nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
  1748       bool hasAttr = false;
  1749       res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
  1751       if (NS_SUCCEEDED(res) && hasAttr)
  1753         flags |= nsIContextMenuListener::CONTEXT_LINK;
  1754         flags2 |= nsIContextMenuListener2::CONTEXT_LINK;
  1755         if (!targetDOMnode)
  1756           targetDOMnode = node;
  1757         if (menuInfoImpl)
  1758           menuInfoImpl->SetAssociatedLink(node);
  1759         break; // exit do-while
  1763     // walk-up-the-tree
  1764     nsCOMPtr<nsIDOMNode> parentNode;
  1765     node->GetParentNode(getter_AddRefs(parentNode));
  1766     node = parentNode;
  1767   } while (node);
  1769   if (!flags && !flags2) {
  1770     // We found nothing of interest so far, check if we
  1771     // have at least an html document.
  1772     nsCOMPtr<nsIDOMDocument> document;
  1773     node = do_QueryInterface(targetNode);
  1774     node->GetOwnerDocument(getter_AddRefs(document));
  1775     nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document));
  1776     if (htmlDocument) {
  1777       flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
  1778       flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT;
  1779       targetDOMnode = node;
  1780       if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) {
  1781         // check if this is a background image that the user was trying to click on
  1782         // and if the listener is ready for that (only nsIContextMenuListener2 and up)
  1783         if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) {
  1784           flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE;
  1785           // For the embedder to get the correct background image 
  1786           // targetDOMnode must point to the original node. 
  1787           targetDOMnode = do_QueryInterface(targetNode);
  1793   // we need to cache the event target into the focus controller's popupNode
  1794   // so we can get at it later from command code, etc.:
  1796   // get the dom window
  1797   nsCOMPtr<nsIDOMWindow> win;
  1798   res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win));
  1799   NS_ENSURE_SUCCESS(res, res);
  1800   NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
  1802   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(win));
  1803   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
  1804   nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
  1805   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  1806   if (root) {
  1807     // set the window root's popup node to the event target
  1808     root->SetPopupNode(targetDOMnode);
  1811   // Tell the listener all about the event
  1812   if ( menuListener2 ) {
  1813     menuInfoImpl->SetMouseEvent(aMouseEvent);
  1814     menuInfoImpl->SetDOMNode(targetDOMnode);
  1815     menuListener2->OnShowContextMenu(flags2, menuInfo);
  1817   else {
  1818     nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
  1819     if ( menuListener )
  1820       menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
  1823   return NS_OK;
  1825 } // MouseDown

mercurial