PageRenderTime 105ms CodeModel.GetById 16ms app.highlight 78ms RepoModel.GetById 1ms app.codeStats 1ms

/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp

http://github.com/zpao/v8monkey
C++ | 1862 lines | 1314 code | 275 blank | 273 comment | 217 complexity | 4f39f29c5eef5b8bb178367f40028b2f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
   2/* ***** BEGIN LICENSE BLOCK *****
   3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   4 *
   5 * The contents of this file are subject to the Mozilla Public License Version
   6 * 1.1 (the "License"); you may not use this file except in compliance with
   7 * the License. You may obtain a copy of the License at
   8 * http://www.mozilla.org/MPL/
   9 *
  10 * Software distributed under the License is distributed on an "AS IS" basis,
  11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12 * for the specific language governing rights and limitations under the
  13 * License.
  14 *
  15 * The Original Code is the Mozilla browser.
  16 *
  17 * The Initial Developer of the Original Code is
  18 * Netscape Communications, Inc.
  19 * Portions created by the Initial Developer are Copyright (C) 1999
  20 * the Initial Developer. All Rights Reserved.
  21 *
  22 * Contributor(s):
  23 *   Travis Bogard <travis@netscape.com>
  24 *   Adam Lock <adamlock@netscape.com>
  25 *   Mike Pinkerton <pinkerton@netscape.com>
  26 *   Dan Rosen <dr@netscape.com>
  27 *
  28 * Alternatively, the contents of this file may be used under the terms of
  29 * either the GNU General Public License Version 2 or later (the "GPL"), or
  30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  31 * in which case the provisions of the GPL or the LGPL are applicable instead
  32 * of those above. If you wish to allow use of your version of this file only
  33 * under the terms of either the GPL or the LGPL, and not to allow others to
  34 * use your version of this file under the terms of the MPL, indicate your
  35 * decision by deleting the provisions above and replace them with the notice
  36 * and other provisions required by the GPL or the LGPL. If you do not delete
  37 * the provisions above, a recipient may use your version of this file under
  38 * the terms of any one of the MPL, the GPL or the LGPL.
  39 *
  40 * ***** END LICENSE BLOCK ***** */
  41
  42// Local Includes
  43#include "nsDocShellTreeOwner.h"
  44#include "nsWebBrowser.h"
  45
  46// Helper Classes
  47#include "nsStyleCoord.h"
  48#include "nsSize.h"
  49#include "nsHTMLReflowState.h"
  50#include "nsIServiceManager.h"
  51#include "nsComponentManagerUtils.h"
  52#include "nsXPIDLString.h"
  53#include "nsIAtom.h"
  54#include "nsReadableUtils.h"
  55#include "nsUnicharUtils.h"
  56#include "nsISimpleEnumerator.h"
  57#include "nsGUIEvent.h"
  58#include "mozilla/LookAndFeel.h"
  59
  60// Interfaces needed to be included
  61#include "nsPresContext.h"
  62#include "nsIContextMenuListener.h"
  63#include "nsIContextMenuListener2.h"
  64#include "nsITooltipListener.h"
  65#include "nsIPrivateDOMEvent.h"
  66#include "nsIDOMNode.h"
  67#include "nsIDOMNodeList.h"
  68#include "nsIDOMDocument.h"
  69#include "nsIDOMDocumentType.h"
  70#include "nsIDOMElement.h"
  71#include "Link.h"
  72#include "nsIDOMSVGElement.h"
  73#include "nsIDOMSVGTitleElement.h"
  74#include "nsIDOMEvent.h"
  75#include "nsIDOMMouseEvent.h"
  76#include "nsIDOMNSEvent.h"
  77#include "nsIDOMNamedNodeMap.h"
  78#include "nsIFormControl.h"
  79#include "nsIDOMHTMLInputElement.h"
  80#include "nsIDOMHTMLTextAreaElement.h"
  81#include "nsIDOMHTMLHtmlElement.h"
  82#include "nsIDOMHTMLAppletElement.h"
  83#include "nsIDOMHTMLObjectElement.h"
  84#include "nsIDOMHTMLEmbedElement.h"
  85#include "nsIDOMHTMLDocument.h"
  86#include "nsIImageLoadingContent.h"
  87#include "nsIWebNavigation.h"
  88#include "nsIDOMHTMLElement.h"
  89#include "nsIPresShell.h"
  90#include "nsPIDOMWindow.h"
  91#include "nsPIWindowRoot.h"
  92#include "nsIDOMWindowCollection.h"
  93#include "nsIWindowWatcher.h"
  94#include "nsPIWindowWatcher.h"
  95#include "nsIPrompt.h"
  96#include "nsRect.h"
  97#include "nsIWebBrowserChromeFocus.h"
  98#include "nsIContent.h"
  99#include "imgIContainer.h"
 100#include "nsContextMenuInfo.h"
 101#include "nsPresContext.h"
 102#include "nsIViewManager.h"
 103#include "nsIView.h"
 104#include "nsEventListenerManager.h"
 105#include "nsIDOMDragEvent.h"
 106#include "nsIConstraintValidation.h"
 107
 108using namespace mozilla;
 109
 110//
 111// GetEventReceiver
 112//
 113// A helper routine that navigates the tricky path from a |nsWebBrowser| to
 114// a |nsIDOMEventTarget| via the window root and chrome event handler.
 115//
 116static nsresult
 117GetDOMEventTarget( nsWebBrowser* inBrowser, nsIDOMEventTarget** aTarget)
 118{
 119  NS_ENSURE_ARG_POINTER(inBrowser);
 120  
 121  nsCOMPtr<nsIDOMWindow> domWindow;
 122  inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 123  NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
 124
 125  nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
 126  NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
 127  nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot();
 128  NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
 129  nsCOMPtr<nsIDOMEventTarget> target =
 130    rootWindow->GetChromeEventHandler();
 131  NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
 132  target.forget(aTarget);
 133  
 134  return NS_OK;
 135}
 136
 137
 138//*****************************************************************************
 139//***    nsDocShellTreeOwner: Object Management
 140//*****************************************************************************
 141
 142nsDocShellTreeOwner::nsDocShellTreeOwner() :
 143   mWebBrowser(nsnull), 
 144   mTreeOwner(nsnull),
 145   mPrimaryContentShell(nsnull),
 146   mWebBrowserChrome(nsnull),
 147   mOwnerWin(nsnull),
 148   mOwnerRequestor(nsnull),
 149   mChromeTooltipListener(nsnull),
 150   mChromeContextMenuListener(nsnull)
 151{
 152}
 153
 154nsDocShellTreeOwner::~nsDocShellTreeOwner()
 155{
 156  RemoveChromeListeners();
 157}
 158
 159//*****************************************************************************
 160// nsDocShellTreeOwner::nsISupports
 161//*****************************************************************************   
 162
 163NS_IMPL_ADDREF(nsDocShellTreeOwner)
 164NS_IMPL_RELEASE(nsDocShellTreeOwner)
 165
 166NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
 167    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
 168    NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
 169    NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
 170    NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
 171    NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
 172    NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
 173    NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
 174    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 175NS_INTERFACE_MAP_END
 176
 177//*****************************************************************************
 178// nsDocShellTreeOwner::nsIInterfaceRequestor
 179//*****************************************************************************   
 180
 181NS_IMETHODIMP
 182nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
 183{
 184  NS_ENSURE_ARG_POINTER(aSink);
 185
 186  if(NS_SUCCEEDED(QueryInterface(aIID, aSink)))
 187    return NS_OK;
 188
 189  if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
 190    if (mWebBrowserChromeWeak != nsnull)
 191      return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
 192    return mOwnerWin->QueryInterface(aIID, aSink);
 193  }
 194
 195  if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
 196    nsIPrompt *prompt;
 197    EnsurePrompter();
 198    prompt = mPrompter;
 199    if (prompt) {
 200      NS_ADDREF(prompt);
 201      *aSink = prompt;
 202      return NS_OK;
 203    }
 204    return NS_NOINTERFACE;
 205  }
 206
 207  if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
 208    nsIAuthPrompt *prompt;
 209    EnsureAuthPrompter();
 210    prompt = mAuthPrompter;
 211    if (prompt) {
 212      NS_ADDREF(prompt);
 213      *aSink = prompt;
 214      return NS_OK;
 215    }
 216    return NS_NOINTERFACE;
 217  }
 218
 219  nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor();
 220  if (req)
 221    return req->GetInterface(aIID, aSink);
 222
 223  return NS_NOINTERFACE;
 224}
 225
 226//*****************************************************************************
 227// nsDocShellTreeOwner::nsIDocShellTreeOwner
 228//*****************************************************************************   
 229
 230NS_IMETHODIMP
 231nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
 232                                      nsIDocShellTreeItem* aRequestor,
 233                                      nsIDocShellTreeItem* aOriginalRequestor,
 234                                      nsIDocShellTreeItem** aFoundItem)
 235{
 236  NS_ENSURE_ARG(aName);
 237  NS_ENSURE_ARG_POINTER(aFoundItem);
 238  *aFoundItem = nsnull; // if we don't find one, we return NS_OK and a null result 
 239  nsresult rv;
 240
 241  nsAutoString name(aName);
 242
 243  if (!mWebBrowser)
 244    return NS_OK; // stymied
 245
 246  /* special cases */
 247  if(name.IsEmpty())
 248    return NS_OK;
 249  if(name.LowerCaseEqualsLiteral("_blank"))
 250    return NS_OK;
 251  // _main is an IE target which should be case-insensitive but isn't
 252  // see bug 217886 for details
 253  // XXXbz what if our browser isn't targetable?  We need to handle that somehow.
 254  if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) {
 255    *aFoundItem = mWebBrowser->mDocShellAsItem;
 256    NS_IF_ADDREF(*aFoundItem);
 257    return NS_OK;
 258  }
 259
 260  if (!SameCOMIdentity(aRequestor, mWebBrowser->mDocShellAsItem)) {
 261    // This isn't a request coming up from our kid, so check with said kid
 262    nsISupports* thisSupports = static_cast<nsIDocShellTreeOwner*>(this);
 263    rv =
 264      mWebBrowser->mDocShellAsItem->FindItemWithName(aName, thisSupports,
 265                                                     aOriginalRequestor, aFoundItem);
 266    if (NS_FAILED(rv) || *aFoundItem) {
 267      return rv;
 268    }
 269  }
 270
 271  // next, if we have a parent and it isn't the requestor, ask it
 272  if(mTreeOwner) {
 273    nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
 274    if (mTreeOwner != reqAsTreeOwner)
 275      return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
 276                                          aOriginalRequestor, aFoundItem);
 277    return NS_OK;
 278  }
 279
 280  // finally, failing everything else, search all windows
 281  return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor,
 282                                       aFoundItem);
 283}
 284
 285nsresult
 286nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
 287                                                   nsIDocShellTreeItem* aRequestor,
 288                                                   nsIDocShellTreeItem* aOriginalRequestor,
 289                                                   nsIDocShellTreeItem** aFoundItem)
 290{
 291  // search for the item across the list of top-level windows
 292  nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 293  if (!wwatch)
 294    return NS_OK;
 295
 296  return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor,
 297                                  aFoundItem);
 298}
 299
 300void
 301nsDocShellTreeOwner::EnsurePrompter()
 302{
 303  if (mPrompter)
 304    return;
 305
 306  nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 307  if (wwatch && mWebBrowser) {
 308    nsCOMPtr<nsIDOMWindow> domWindow;
 309    mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 310    if (domWindow)
 311      wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter));
 312  }
 313}
 314
 315void
 316nsDocShellTreeOwner::EnsureAuthPrompter()
 317{
 318  if (mAuthPrompter)
 319    return;
 320
 321  nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 322  if (wwatch && mWebBrowser) {
 323    nsCOMPtr<nsIDOMWindow> domWindow;
 324    mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 325    if (domWindow)
 326      wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter));
 327  }
 328}
 329
 330void
 331nsDocShellTreeOwner::AddToWatcher()
 332{
 333  if (mWebBrowser) {
 334    nsCOMPtr<nsIDOMWindow> domWindow;
 335    mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 336    if (domWindow) {
 337      nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 338      if (wwatch) {
 339        nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 340        if (webBrowserChrome)
 341          wwatch->AddWindow(domWindow, webBrowserChrome);
 342      }
 343    }
 344  }
 345}
 346
 347void
 348nsDocShellTreeOwner::RemoveFromWatcher()
 349{
 350  if (mWebBrowser) {
 351    nsCOMPtr<nsIDOMWindow> domWindow;
 352    mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 353    if (domWindow) {
 354      nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 355      if (wwatch)
 356        wwatch->RemoveWindow(domWindow);
 357    }
 358  }
 359}
 360
 361
 362NS_IMETHODIMP
 363nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
 364                                       bool aPrimary, bool aTargetable,
 365                                       const nsAString& aID)
 366{
 367   if(mTreeOwner)
 368      return mTreeOwner->ContentShellAdded(aContentShell, aPrimary,
 369                                           aTargetable, aID);
 370
 371   if (aPrimary)
 372      mPrimaryContentShell = aContentShell;
 373   return NS_OK;
 374}
 375
 376NS_IMETHODIMP
 377nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
 378{
 379  if(mTreeOwner)
 380    return mTreeOwner->ContentShellRemoved(aContentShell);
 381
 382  if(mPrimaryContentShell == aContentShell)
 383    mPrimaryContentShell = nsnull;
 384
 385  return NS_OK;
 386}
 387
 388NS_IMETHODIMP
 389nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell)
 390{
 391   NS_ENSURE_ARG_POINTER(aShell);
 392
 393   if(mTreeOwner)
 394       return mTreeOwner->GetPrimaryContentShell(aShell);
 395
 396   *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShellAsItem.get());
 397   NS_IF_ADDREF(*aShell);
 398
 399   return NS_OK;
 400}
 401
 402NS_IMETHODIMP
 403nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
 404                                 PRInt32 aCX, PRInt32 aCY)
 405{
 406   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 407
 408   NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
 409
 410   if(mTreeOwner)
 411      return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
 412
 413   if(aShellItem == mWebBrowser->mDocShellAsItem)
 414      return webBrowserChrome->SizeBrowserTo(aCX, aCY);
 415
 416   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
 417   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
 418
 419   nsCOMPtr<nsIDOMDocument> domDocument;
 420   webNav->GetDocument(getter_AddRefs(domDocument));
 421   NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE);
 422
 423   nsCOMPtr<nsIDOMElement> domElement;
 424   domDocument->GetDocumentElement(getter_AddRefs(domElement));
 425   NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE);
 426
 427   // Set the preferred Size
 428   //XXX
 429   NS_ERROR("Implement this");
 430   /*
 431   Set the preferred size on the aShellItem.
 432   */
 433
 434   nsRefPtr<nsPresContext> presContext;
 435   mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
 436   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 437
 438   nsIPresShell *presShell = presContext->GetPresShell();
 439   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 440
 441   NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE,
 442      NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE);
 443   
 444   nsRect shellArea = presContext->GetVisibleArea();
 445
 446   PRInt32 browserCX = presContext->AppUnitsToDevPixels(shellArea.width);
 447   PRInt32 browserCY = presContext->AppUnitsToDevPixels(shellArea.height);
 448
 449   return webBrowserChrome->SizeBrowserTo(browserCX, browserCY);
 450}
 451
 452NS_IMETHODIMP
 453nsDocShellTreeOwner::SetPersistence(bool aPersistPosition,
 454                                    bool aPersistSize,
 455                                    bool aPersistSizeMode)
 456{
 457  return NS_ERROR_NOT_IMPLEMENTED;
 458}
 459
 460NS_IMETHODIMP
 461nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition,
 462                                    bool* aPersistSize,
 463                                    bool* aPersistSizeMode)
 464{
 465  return NS_ERROR_NOT_IMPLEMENTED;
 466}
 467
 468NS_IMETHODIMP
 469nsDocShellTreeOwner::GetTargetableShellCount(PRUint32* aResult)
 470{
 471  if(mTreeOwner) {
 472    mTreeOwner->GetTargetableShellCount(aResult);
 473  } else {
 474    *aResult = 0;
 475  }
 476
 477  return NS_OK;
 478}
 479
 480//*****************************************************************************
 481// nsDocShellTreeOwner::nsIBaseWindow
 482//*****************************************************************************   
 483
 484
 485NS_IMETHODIMP
 486nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
 487                                nsIWidget* aParentWidget, PRInt32 aX,
 488                                PRInt32 aY, PRInt32 aCX, PRInt32 aCY)   
 489{
 490  return NS_ERROR_NULL_POINTER;
 491}
 492
 493NS_IMETHODIMP
 494nsDocShellTreeOwner::Create()
 495{
 496  return NS_ERROR_NULL_POINTER;
 497}
 498
 499NS_IMETHODIMP
 500nsDocShellTreeOwner::Destroy()
 501{
 502  nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 503  if (webBrowserChrome)
 504  {
 505    return webBrowserChrome->DestroyBrowserWindow();
 506  }
 507
 508  return NS_ERROR_NULL_POINTER;
 509}
 510
 511NS_IMETHODIMP
 512nsDocShellTreeOwner::SetPosition(PRInt32 aX, PRInt32 aY)
 513{
 514  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 515  if (ownerWin)
 516  {
 517    return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
 518                                   aX, aY, 0, 0);
 519  }
 520  return NS_ERROR_NULL_POINTER;
 521}
 522
 523NS_IMETHODIMP
 524nsDocShellTreeOwner::GetPosition(PRInt32* aX, PRInt32* aY)
 525{
 526  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 527  if (ownerWin)
 528  {
 529    return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
 530                                   aX, aY, nsnull, nsnull);
 531  }
 532  return NS_ERROR_NULL_POINTER;
 533}
 534
 535NS_IMETHODIMP
 536nsDocShellTreeOwner::SetSize(PRInt32 aCX, PRInt32 aCY, bool aRepaint)
 537{
 538  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 539  if (ownerWin)
 540  {
 541    return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
 542                                   0, 0, aCX, aCY);
 543  }
 544  return NS_ERROR_NULL_POINTER;
 545}
 546
 547NS_IMETHODIMP
 548nsDocShellTreeOwner::GetSize(PRInt32* aCX, PRInt32* aCY)
 549{
 550  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 551  if (ownerWin)
 552  {
 553    return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
 554                                   nsnull, nsnull, aCX, aCY);
 555  }
 556  return NS_ERROR_NULL_POINTER;
 557}
 558
 559NS_IMETHODIMP
 560nsDocShellTreeOwner::SetPositionAndSize(PRInt32 aX, PRInt32 aY, PRInt32 aCX,
 561                                        PRInt32 aCY, bool aRepaint)
 562{
 563  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 564  if (ownerWin)
 565  {
 566    return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
 567                                   nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
 568                                   aX, aY, aCX, aCY);
 569  }
 570  return NS_ERROR_NULL_POINTER;
 571}
 572
 573NS_IMETHODIMP
 574nsDocShellTreeOwner::GetPositionAndSize(PRInt32* aX, PRInt32* aY, PRInt32* aCX,
 575                                        PRInt32* aCY)
 576{
 577  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 578  if (ownerWin)
 579  {
 580    return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
 581                                   nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
 582                                   aX, aY, aCX, aCY);
 583  }
 584  return NS_ERROR_NULL_POINTER;
 585}
 586
 587NS_IMETHODIMP
 588nsDocShellTreeOwner::Repaint(bool aForce)
 589{
 590  return NS_ERROR_NULL_POINTER;
 591}
 592
 593NS_IMETHODIMP
 594nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget)
 595{
 596  return NS_ERROR_NULL_POINTER;
 597}
 598
 599NS_IMETHODIMP
 600nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget)
 601{
 602  return NS_ERROR_NULL_POINTER;
 603}
 604
 605NS_IMETHODIMP
 606nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
 607{
 608  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 609  if (ownerWin)
 610  {
 611    return ownerWin->GetSiteWindow(aParentNativeWindow);
 612  }
 613  return NS_ERROR_NULL_POINTER;
 614}
 615
 616NS_IMETHODIMP
 617nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 618{
 619  return NS_ERROR_NULL_POINTER;
 620}
 621
 622NS_IMETHODIMP
 623nsDocShellTreeOwner::GetVisibility(bool* aVisibility)
 624{
 625  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 626  if (ownerWin)
 627  {
 628    return ownerWin->GetVisibility(aVisibility);
 629  }
 630  return NS_ERROR_NULL_POINTER;
 631}
 632
 633NS_IMETHODIMP
 634nsDocShellTreeOwner::SetVisibility(bool aVisibility)
 635{
 636  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 637  if (ownerWin)
 638  {
 639    return ownerWin->SetVisibility(aVisibility);
 640  }
 641  return NS_ERROR_NULL_POINTER;
 642}
 643
 644NS_IMETHODIMP
 645nsDocShellTreeOwner::GetEnabled(bool *aEnabled)
 646{
 647  NS_ENSURE_ARG_POINTER(aEnabled);
 648  *aEnabled = true;
 649  return NS_ERROR_NOT_IMPLEMENTED;
 650}
 651
 652NS_IMETHODIMP
 653nsDocShellTreeOwner::SetEnabled(bool aEnabled)
 654{
 655  return NS_ERROR_NOT_IMPLEMENTED;
 656}
 657
 658NS_IMETHODIMP
 659nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget)
 660{
 661    return NS_ERROR_NULL_POINTER;
 662}
 663
 664NS_IMETHODIMP
 665nsDocShellTreeOwner::SetFocus()
 666{
 667  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 668  if (ownerWin)
 669  {
 670    return ownerWin->SetFocus();
 671  }
 672  return NS_ERROR_NULL_POINTER;
 673}
 674
 675NS_IMETHODIMP
 676nsDocShellTreeOwner::GetTitle(PRUnichar** aTitle)
 677{
 678  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 679  if (ownerWin)
 680  {
 681    return ownerWin->GetTitle(aTitle);
 682  }
 683  return NS_ERROR_NULL_POINTER;
 684}
 685
 686NS_IMETHODIMP
 687nsDocShellTreeOwner::SetTitle(const PRUnichar* aTitle)
 688{
 689  nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
 690  if (ownerWin)
 691  {
 692    return ownerWin->SetTitle(aTitle);
 693  }
 694  return NS_ERROR_NULL_POINTER;
 695}
 696
 697
 698//*****************************************************************************
 699// nsDocShellTreeOwner::nsIWebProgressListener
 700//*****************************************************************************   
 701
 702
 703NS_IMETHODIMP
 704nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress,
 705                                      nsIRequest* aRequest,
 706                                      PRInt32 aCurSelfProgress,
 707                                      PRInt32 aMaxSelfProgress, 
 708                                      PRInt32 aCurTotalProgress,
 709                                      PRInt32 aMaxTotalProgress)
 710{
 711    // In the absence of DOM document creation event, this method is the
 712    // most convenient place to install the mouse listener on the
 713    // DOM document.
 714    return AddChromeListeners();
 715}
 716
 717NS_IMETHODIMP
 718nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress,
 719                                   nsIRequest* aRequest,
 720                                   PRUint32 aProgressStateFlags,
 721                                   nsresult aStatus)
 722{
 723    return NS_OK;
 724}
 725
 726NS_IMETHODIMP
 727nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
 728                                      nsIRequest* aRequest,
 729                                      nsIURI* aURI,
 730                                      PRUint32 aFlags)
 731{
 732    return NS_OK;
 733}
 734
 735NS_IMETHODIMP 
 736nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
 737                                    nsIRequest* aRequest,
 738                                    nsresult aStatus,
 739                                    const PRUnichar* aMessage)
 740{
 741    return NS_OK;
 742}
 743
 744NS_IMETHODIMP 
 745nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, 
 746                                      nsIRequest *aRequest, 
 747                                      PRUint32 state)
 748{
 749    return NS_OK;
 750}
 751
 752
 753//*****************************************************************************
 754// nsDocShellTreeOwner: Helpers
 755//*****************************************************************************   
 756
 757//*****************************************************************************
 758// nsDocShellTreeOwner: Accessors
 759//*****************************************************************************   
 760
 761void
 762nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
 763{
 764  if ( !aWebBrowser )
 765    RemoveChromeListeners();
 766  if (aWebBrowser != mWebBrowser) {
 767    mPrompter = 0;
 768    mAuthPrompter = 0;
 769  }
 770
 771  mWebBrowser = aWebBrowser;
 772}
 773
 774nsWebBrowser *
 775nsDocShellTreeOwner::WebBrowser()
 776{
 777   return mWebBrowser;
 778}
 779
 780NS_IMETHODIMP
 781nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
 782{ 
 783  if(aTreeOwner) {
 784    nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner));
 785    NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG);
 786    NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG);
 787    mTreeOwner = aTreeOwner;
 788  }
 789  else {
 790    mTreeOwner = nsnull;
 791    nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 792    if (!webBrowserChrome)
 793      NS_ENSURE_SUCCESS(SetWebBrowserChrome(nsnull), NS_ERROR_FAILURE);
 794  }
 795
 796  return NS_OK;
 797}
 798
 799NS_IMETHODIMP
 800nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome)
 801{
 802  if(!aWebBrowserChrome) {
 803    mWebBrowserChrome = nsnull;
 804    mOwnerWin = nsnull;
 805    mOwnerRequestor = nsnull;
 806    mWebBrowserChromeWeak = 0;
 807  } else {
 808    nsCOMPtr<nsISupportsWeakReference> supportsweak =
 809                                           do_QueryInterface(aWebBrowserChrome);
 810    if (supportsweak) {
 811      supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak));
 812    } else {
 813      nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome));
 814      nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome));
 815
 816      // it's ok for ownerWin or requestor to be null.
 817      mWebBrowserChrome = aWebBrowserChrome;
 818      mOwnerWin = ownerWin;
 819      mOwnerRequestor = requestor;
 820    }
 821  }
 822  return NS_OK;
 823}
 824
 825
 826//
 827// AddChromeListeners
 828//
 829// Hook up things to the chrome like context menus and tooltips, if the chrome
 830// has implemented the right interfaces.
 831//
 832NS_IMETHODIMP
 833nsDocShellTreeOwner::AddChromeListeners()
 834{
 835  nsresult rv = NS_OK;
 836
 837  nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 838  if (!webBrowserChrome)
 839    return NS_ERROR_FAILURE;
 840
 841  // install tooltips
 842  if ( !mChromeTooltipListener ) { 
 843    nsCOMPtr<nsITooltipListener>
 844                           tooltipListener(do_QueryInterface(webBrowserChrome));
 845    if ( tooltipListener ) {
 846      mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser,
 847                                                         webBrowserChrome);
 848      if ( mChromeTooltipListener ) {
 849        NS_ADDREF(mChromeTooltipListener);
 850        rv = mChromeTooltipListener->AddChromeListeners();
 851      }
 852      else
 853        rv = NS_ERROR_OUT_OF_MEMORY;
 854    }
 855  }
 856  
 857  // install context menus
 858  if ( !mChromeContextMenuListener ) {
 859    nsCOMPtr<nsIContextMenuListener2>
 860                          contextListener2(do_QueryInterface(webBrowserChrome));
 861    nsCOMPtr<nsIContextMenuListener>
 862                           contextListener(do_QueryInterface(webBrowserChrome));
 863    if ( contextListener2 || contextListener ) {
 864      mChromeContextMenuListener =
 865                   new ChromeContextMenuListener(mWebBrowser, webBrowserChrome);
 866      if ( mChromeContextMenuListener ) {
 867        NS_ADDREF(mChromeContextMenuListener);
 868        rv = mChromeContextMenuListener->AddChromeListeners();
 869      }
 870      else
 871        rv = NS_ERROR_OUT_OF_MEMORY;
 872    }
 873  }
 874
 875  // register dragover and drop event listeners with the listener manager
 876  nsCOMPtr<nsIDOMEventTarget> target;
 877  GetDOMEventTarget(mWebBrowser, getter_AddRefs(target));
 878
 879  nsEventListenerManager* elmP = target->GetListenerManager(true);
 880  if (elmP) {
 881    elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"),
 882                                 NS_EVENT_FLAG_BUBBLE |
 883                                 NS_EVENT_FLAG_SYSTEM_EVENT);
 884    elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"),
 885                                 NS_EVENT_FLAG_BUBBLE |
 886                                 NS_EVENT_FLAG_SYSTEM_EVENT);
 887  }
 888
 889  return rv;
 890  
 891} // AddChromeListeners
 892
 893
 894NS_IMETHODIMP
 895nsDocShellTreeOwner::RemoveChromeListeners()
 896{
 897  if ( mChromeTooltipListener ) {
 898    mChromeTooltipListener->RemoveChromeListeners();
 899    NS_RELEASE(mChromeTooltipListener);
 900  }
 901  if ( mChromeContextMenuListener ) {
 902    mChromeContextMenuListener->RemoveChromeListeners();
 903    NS_RELEASE(mChromeContextMenuListener);
 904  }
 905
 906  nsCOMPtr<nsIDOMEventTarget> piTarget;
 907  GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget));
 908  if (!piTarget)
 909    return NS_OK;
 910
 911  nsEventListenerManager* elmP = piTarget->GetListenerManager(true);
 912  if (elmP)
 913  {
 914    elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"),
 915                                    NS_EVENT_FLAG_BUBBLE |
 916                                    NS_EVENT_FLAG_SYSTEM_EVENT);
 917    elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"),
 918                                    NS_EVENT_FLAG_BUBBLE |
 919                                    NS_EVENT_FLAG_SYSTEM_EVENT);
 920  }
 921
 922  return NS_OK;
 923}
 924
 925NS_IMETHODIMP
 926nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent)
 927{
 928  nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
 929  NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG);
 930
 931  nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
 932  if (domNSEvent) {
 933    bool defaultPrevented;
 934    domNSEvent->GetPreventDefault(&defaultPrevented);
 935    if (defaultPrevented)
 936      return NS_OK;
 937  }
 938
 939  nsCOMPtr<nsIDroppedLinkHandler> handler = do_GetService("@mozilla.org/content/dropped-link-handler;1");
 940  if (handler) {
 941    nsAutoString eventType;
 942    aEvent->GetType(eventType);
 943    if (eventType.EqualsLiteral("dragover")) {
 944      bool canDropLink;
 945      handler->CanDropLink(dragEvent, false, &canDropLink);
 946      if (canDropLink)
 947        aEvent->PreventDefault();
 948    }
 949    else if (eventType.EqualsLiteral("drop")) {
 950      nsIWebNavigation* webnav = static_cast<nsIWebNavigation *>(mWebBrowser);
 951
 952      nsAutoString link, name;
 953      if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) {
 954        if (!link.IsEmpty()) {
 955          webnav->LoadURI(link.get(), 0, nsnull, nsnull, nsnull);
 956        }
 957      }
 958      else {
 959        aEvent->StopPropagation();
 960        aEvent->PreventDefault();
 961      }
 962    }
 963  }
 964
 965  return NS_OK;
 966}
 967
 968already_AddRefed<nsIWebBrowserChrome>
 969nsDocShellTreeOwner::GetWebBrowserChrome()
 970{
 971  nsCOMPtr<nsIWebBrowserChrome> chrome;
 972  if (mWebBrowserChromeWeak) {
 973    chrome = do_QueryReferent(mWebBrowserChromeWeak);
 974  } else if (mWebBrowserChrome) {
 975    chrome = mWebBrowserChrome;
 976  }
 977  return chrome.forget();
 978}
 979
 980already_AddRefed<nsIEmbeddingSiteWindow>
 981nsDocShellTreeOwner::GetOwnerWin()
 982{
 983  nsCOMPtr<nsIEmbeddingSiteWindow> win;
 984  if (mWebBrowserChromeWeak) {
 985    win = do_QueryReferent(mWebBrowserChromeWeak);
 986  } else if (mOwnerWin) {
 987    win = mOwnerWin;
 988  }
 989  return win.forget();
 990}
 991
 992already_AddRefed<nsIInterfaceRequestor>
 993nsDocShellTreeOwner::GetOwnerRequestor()
 994{
 995  nsCOMPtr<nsIInterfaceRequestor> req;
 996  if (mWebBrowserChromeWeak) {
 997    req = do_QueryReferent(mWebBrowserChromeWeak);
 998  } else if (mOwnerRequestor) {
 999    req = mOwnerRequestor;
1000  }
1001  return req.forget();
1002}
1003
1004
1005///////////////////////////////////////////////////////////////////////////////
1006// DefaultTooltipTextProvider
1007
1008class DefaultTooltipTextProvider : public nsITooltipTextProvider
1009{
1010public:
1011    DefaultTooltipTextProvider();
1012
1013    NS_DECL_ISUPPORTS
1014    NS_DECL_NSITOOLTIPTEXTPROVIDER
1015    
1016protected:
1017    nsCOMPtr<nsIAtom>   mTag_dialog;
1018    nsCOMPtr<nsIAtom>   mTag_dialogheader;
1019    nsCOMPtr<nsIAtom>   mTag_window;
1020};
1021
1022NS_IMPL_THREADSAFE_ISUPPORTS1(DefaultTooltipTextProvider, nsITooltipTextProvider)
1023
1024DefaultTooltipTextProvider::DefaultTooltipTextProvider()
1025{
1026    // There are certain element types which we don't want to use
1027    // as tool tip text. 
1028    mTag_dialog       = do_GetAtom("dialog");
1029    mTag_dialogheader = do_GetAtom("dialogheader");
1030    mTag_window       = do_GetAtom("window");   
1031}
1032
1033//
1034// UseSVGTitle
1035//
1036// A helper routine that determines whether we're still interested
1037// in SVG titles. We need to stop at the SVG root element that
1038// has a document node parent
1039//
1040static bool
1041UseSVGTitle(nsIDOMElement *currElement)
1042{
1043  nsCOMPtr<nsIDOMSVGElement> svgContent(do_QueryInterface(currElement));
1044  if (!svgContent)
1045    return false;
1046
1047  nsCOMPtr<nsIDOMNode> parent;
1048  currElement->GetParentNode(getter_AddRefs(parent));
1049  if (!parent)
1050    return false;
1051
1052  PRUint16 nodeType;
1053  nsresult rv = parent->GetNodeType(&nodeType);
1054
1055  return NS_SUCCEEDED(rv) && nodeType != nsIDOMNode::DOCUMENT_NODE;
1056}
1057
1058/* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
1059NS_IMETHODIMP
1060DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, PRUnichar **aText,
1061                                        bool *_retval)
1062{
1063  NS_ENSURE_ARG_POINTER(aNode);
1064  NS_ENSURE_ARG_POINTER(aText);
1065    
1066  nsString outText;
1067
1068  bool lookingForSVGTitle = true;
1069  bool found = false;
1070  nsCOMPtr<nsIDOMNode> current ( aNode );
1071
1072  // If the element implement the constraint validation API and has no title,
1073  // show the validation message, if any.
1074  nsCOMPtr<nsIConstraintValidation> cvElement = do_QueryInterface(current);
1075  if (cvElement) {
1076    nsCOMPtr<nsIContent> content = do_QueryInterface(cvElement);
1077    nsCOMPtr<nsIAtom> titleAtom = do_GetAtom("title");
1078
1079    nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(content);
1080    bool formHasNoValidate = false;
1081    mozilla::dom::Element* form = formControl->GetFormElement();
1082    if (form) {
1083      nsCOMPtr<nsIAtom> noValidateAtom = do_GetAtom("novalidate");
1084      formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom);
1085    }
1086
1087    if (!content->HasAttr(kNameSpaceID_None, titleAtom) &&
1088        !formHasNoValidate) {
1089      cvElement->GetValidationMessage(outText);
1090      found = !outText.IsEmpty();
1091    }
1092  }
1093
1094  while ( !found && current ) {
1095    nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) );
1096    if ( currElement ) {
1097      nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
1098      if (content) {
1099        nsIAtom *tagAtom = content->Tag();
1100        if (tagAtom != mTag_dialog &&
1101            tagAtom != mTag_dialogheader &&
1102            tagAtom != mTag_window) {
1103          // first try the normal title attribute...
1104          currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
1105          if ( outText.Length() )
1106            found = true;
1107          else {
1108            // ...ok, that didn't work, try it in the XLink namespace
1109            NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink");
1110            nsCOMPtr<mozilla::dom::Link> linkContent(do_QueryInterface(currElement));
1111            if (linkContent) {
1112              nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal());
1113              if (uri) {
1114                currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText);
1115                if ( outText.Length() )
1116                  found = true;
1117              }
1118            }
1119            else {
1120              if (lookingForSVGTitle) {
1121                lookingForSVGTitle = UseSVGTitle(currElement);
1122              }
1123              if (lookingForSVGTitle) {
1124                nsCOMPtr<nsIDOMNodeList>childNodes;
1125                aNode->GetChildNodes(getter_AddRefs(childNodes));
1126                PRUint32 childNodeCount;
1127                childNodes->GetLength(&childNodeCount);
1128                for (PRUint32 i = 0; i < childNodeCount; i++) {
1129                  nsCOMPtr<nsIDOMNode>childNode;
1130                  childNodes->Item(i, getter_AddRefs(childNode));
1131                  nsCOMPtr<nsIDOMSVGTitleElement> titleElement(do_QueryInterface(childNode));
1132                  if (titleElement) {
1133                    titleElement->GetTextContent(outText);
1134                    if ( outText.Length() )
1135                      found = true;
1136                    break;
1137                  }
1138                }
1139              }
1140            }
1141          }
1142        }
1143      }
1144    }
1145    
1146    // not found here, walk up to the parent and keep trying
1147    if ( !found ) {
1148      nsCOMPtr<nsIDOMNode> temp ( current );
1149      temp->GetParentNode(getter_AddRefs(current));
1150    }
1151  } // while not found
1152
1153  *_retval = found;
1154  *aText = (found) ? ToNewUnicode(outText) : nsnull;
1155
1156  return NS_OK;
1157}
1158
1159///////////////////////////////////////////////////////////////////////////////
1160
1161NS_IMPL_ISUPPORTS1(ChromeTooltipListener, nsIDOMEventListener)
1162
1163//
1164// ChromeTooltipListener ctor
1165//
1166
1167ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
1168                                             nsIWebBrowserChrome* inChrome) 
1169  : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
1170     mTooltipListenerInstalled(false),
1171     mMouseClientX(0), mMouseClientY(0),
1172     mShowingTooltip(false)
1173{
1174  mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
1175  if (!mTooltipTextProvider) {
1176    nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
1177    mTooltipTextProvider = do_QueryInterface(pProvider);
1178  }
1179} // ctor
1180
1181
1182//
1183// ChromeTooltipListener dtor
1184//
1185ChromeTooltipListener::~ChromeTooltipListener()
1186{
1187
1188} // dtor
1189
1190
1191//
1192// AddChromeListeners
1193//
1194// Hook up things to the chrome like context menus and tooltips, if the chrome
1195// has implemented the right interfaces.
1196//
1197NS_IMETHODIMP
1198ChromeTooltipListener::AddChromeListeners()
1199{  
1200  if (!mEventTarget)
1201    GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1202  
1203  // Register the appropriate events for tooltips, but only if
1204  // the embedding chrome cares.
1205  nsresult rv = NS_OK;
1206  nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1207  if ( tooltipListener && !mTooltipListenerInstalled ) {
1208    rv = AddTooltipListener();
1209    if ( NS_FAILED(rv) )
1210      return rv;
1211  }
1212  
1213  return rv;
1214  
1215} // AddChromeListeners
1216
1217
1218//
1219// AddTooltipListener
1220//
1221// Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
1222// "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
1223// of how many succeed so we can clean up correctly in Release().
1224//
1225NS_IMETHODIMP
1226ChromeTooltipListener::AddTooltipListener()
1227{
1228  if (mEventTarget) {
1229    nsresult rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"),
1230                                                 this, false, false);
1231    NS_ENSURE_SUCCESS(rv, rv);
1232    rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
1233                                        false, false);
1234    NS_ENSURE_SUCCESS(rv, rv);
1235    rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this,
1236                                        false, false);
1237    NS_ENSURE_SUCCESS(rv, rv);
1238    rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
1239                                        false, false);
1240    NS_ENSURE_SUCCESS(rv, rv);
1241
1242    mTooltipListenerInstalled = true;
1243  }
1244
1245  return NS_OK;
1246}
1247
1248
1249//
1250// RemoveChromeListeners
1251//
1252// Unsubscribe from the various things we've hooked up to the window root.
1253//
1254NS_IMETHODIMP
1255ChromeTooltipListener::RemoveChromeListeners ( )
1256{
1257  HideTooltip();
1258
1259  if ( mTooltipListenerInstalled )
1260    RemoveTooltipListener();
1261  
1262  mEventTarget = nsnull;
1263  
1264  // it really doesn't matter if these fail...
1265  return NS_OK;
1266  
1267} // RemoveChromeTooltipListeners
1268
1269
1270
1271//
1272// RemoveTooltipListener
1273//
1274// Unsubscribe from all the various tooltip events that we were listening to
1275//
1276NS_IMETHODIMP 
1277ChromeTooltipListener::RemoveTooltipListener()
1278{
1279  if (mEventTarget) {
1280    nsresult rv =
1281      mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this,
1282                                        false);
1283    NS_ENSURE_SUCCESS(rv, rv);
1284    rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
1285                                           this, false);
1286    NS_ENSURE_SUCCESS(rv, rv);
1287    rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this,
1288                                           false);
1289    NS_ENSURE_SUCCESS(rv, rv);
1290    rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
1291                                           this, false);
1292    NS_ENSURE_SUCCESS(rv, rv);
1293
1294    mTooltipListenerInstalled = false;
1295  }
1296
1297  return NS_OK;
1298}
1299
1300NS_IMETHODIMP
1301ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
1302{
1303  nsAutoString eventType;
1304  aEvent->GetType(eventType);
1305
1306  if (eventType.EqualsLiteral("keydown") ||
1307      eventType.EqualsLiteral("mousedown") ||
1308      eventType.EqualsLiteral("mouseout"))
1309    return HideTooltip();
1310  if (eventType.EqualsLiteral("mousemove"))
1311    return MouseMove(aEvent);
1312
1313  NS_ERROR("Unexpected event type");
1314  return NS_OK;
1315}
1316
1317//
1318// MouseMove
1319//
1320// If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
1321// timer fires, we cache the node in |mPossibleTooltipNode|.
1322//
1323nsresult
1324ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
1325{
1326  nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
1327  if (!mouseEvent)
1328    return NS_OK;
1329
1330  // stash the coordinates of the event so that we can still get back to it from within the 
1331  // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
1332  // even when the mouse doesn't change position! To get around this, we make sure the
1333  // mouse has really moved before proceeding.
1334  PRInt32 newMouseX, newMouseY;
1335  mouseEvent->GetClientX(&newMouseX);
1336  mouseEvent->GetClientY(&newMouseY);
1337  if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
1338    return NS_OK;
1339  mMouseClientX = newMouseX; mMouseClientY = newMouseY;
1340  mouseEvent->GetScreenX(&mMouseScreenX);
1341  mouseEvent->GetScreenY(&mMouseScreenY);
1342
1343  // We want to close the tip if it is being displayed and the mouse moves. Recall 
1344  // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
1345  // moves, we want to make sure we reset the timer to show it, so that the delay
1346  // is from when the mouse stops moving, not when it enters the element.
1347  if ( mShowingTooltip )
1348    return HideTooltip();
1349  if ( mTooltipTimer )
1350    mTooltipTimer->Cancel();
1351
1352  mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
1353  if ( mTooltipTimer ) {
1354    nsCOMPtr<nsIDOMEventTarget> eventTarget;
1355    aMouseEvent->GetTarget(getter_AddRefs(eventTarget));
1356    if ( eventTarget )
1357      mPossibleTooltipNode = do_QueryInterface(eventTarget);
1358    if ( mPossibleTooltipNode ) {
1359      nsresult rv =
1360        mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
1361          LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
1362          nsITimer::TYPE_ONE_SHOT);
1363      if (NS_FAILED(rv))
1364        mPossibleTooltipNode = nsnull;
1365    }
1366  }
1367  else
1368    NS_WARNING ( "Could not create a timer for tooltip tracking" );
1369    
1370  return NS_OK;
1371  
1372} // MouseMove
1373
1374
1375//
1376// ShowTooltip
1377//
1378// Tell the registered chrome that they should show the tooltip
1379//
1380NS_IMETHODIMP
1381ChromeTooltipListener::ShowTooltip(PRInt32 inXCoords, PRInt32 inYCoords,
1382                                   const nsAString & inTipText)
1383{
1384  nsresult rv = NS_OK;
1385  
1386  // do the work to call the client
1387  nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1388  if ( tooltipListener ) {
1389    rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); 
1390    if ( NS_SUCCEEDED(rv) )
1391      mShowingTooltip = true;
1392  }
1393
1394  return rv;
1395  
1396} // ShowTooltip
1397
1398
1399//
1400// HideTooltip
1401//
1402// Tell the registered chrome that they should rollup the tooltip
1403// NOTE: This routine is safe to call even if the popup is already closed.
1404//
1405NS_IMETHODIMP
1406ChromeTooltipListener::HideTooltip()
1407{
1408  nsresult rv = NS_OK;
1409  
1410  // shut down the relevant timers
1411  if ( mTooltipTimer ) {
1412    mTooltipTimer->Cancel();
1413    mTooltipTimer = nsnull;
1414    // release tooltip target
1415    mPossibleTooltipNode = nsnull;
1416  }
1417  if ( mAutoHideTimer ) {
1418    mAutoHideTimer->Cancel();
1419    mAutoHideTimer = nsnull;
1420  }
1421
1422  // if we're showing the tip, tell the chrome to hide it
1423  if ( mShowingTooltip ) {
1424    nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1425    if ( tooltipListener ) {
1426      rv = tooltipListener->OnHideTooltip ( );
1427      if ( NS_SUCCEEDED(rv) )
1428        mShowingTooltip = false;
1429    }
1430  }
1431
1432  return rv;
1433  
1434} // HideTooltip
1435
1436
1437//
1438// sTooltipCallback
1439//
1440// A timer callback, fired when the mouse has hovered inside of a frame for the 
1441// appropriate amount of time. Getting to this point means that we should show the
1442// tooltip, but only after we determine there is an appropriate TITLE element.
1443//
1444// This relies on certain things being cached into the |aChromeTooltipListener| object passed to
1445// us by the timer:
1446//   -- the x/y coordinates of the mouse      (mMouseClientY, mMouseClientX)
1447//   -- the dom node the user hovered over    (mPossibleTooltipNode)
1448//
1449void
1450ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
1451                                        void *aChromeTooltipListener)
1452{
1453  ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>
1454                                           (aChromeTooltipListener);
1455  if ( self && self->mPossibleTooltipNode ){
1456    // The actual coordinates we want to put the tooltip at are relative to the
1457    // toplevel docshell of our mWebBrowser.  We know what the screen
1458    // coordinates of the mouse event were, which means we just need the screen
1459    // coordinates of the docshell.  Unfortunately, there is no good way to
1460    // find those short of groveling for the presentation in that docshell and
1461    // finding the screen coords of its toplevel widget...
1462    nsCOMPtr<nsIDocShell> docShell =
1463      do_GetInterface(static_cast<nsIWebBrowser*>(self->mWebBrowser));
1464    nsCOMPtr<nsIPresShell> shell;
1465    if (docShell) {
1466      docShell->GetPresShell(getter_AddRefs(shell));
1467    }
1468
1469    nsIWidget* widget = nsnull;
1470    if (shell) {
1471      nsIViewManager* vm = shell->GetViewManager();
1472      if (vm) {
1473        nsIView* view = vm->GetRootView();
1474        if (view) {
1475          nsPoint offset;
1476          widget = view->GetNearestWidget(&offset);
1477        }
1478      }
1479    }
1480
1481    if (!widget) {
1482      // release tooltip target if there is one, NO MATTER WHAT
1483      self->mPossibleTooltipNode = nsnull;
1484      return;
1485    }
1486
1487    // if there is text associated with the node, show the tip and fire
1488    // off a timer to auto-hide it.
1489
1490    nsXPIDLString tooltipText;
1491    if (self->mTooltipTextProvider) {
1492      bool textFound = false;
1493
1494      self->mTooltipTextProvider->GetNodeText(
1495          self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
1496      
1497      if (textFound) {
1498        nsString tipText(tooltipText);
1499        self->CreateAutoHideTimer();
1500        nsIntPoint screenDot = widget->WidgetToScreenOffset();
1501        self->ShowTooltip (self->mMouseScreenX - screenDot.x,
1502                           self->mMouseScreenY - screenDot.y,
1503                           tipText);
1504      }
1505    }
1506    
1507    // release tooltip target if there is one, NO MATTER WHAT
1508    self->mPossibleTooltipNode = nsnull;
1509  } // if "self" data valid
1510  
1511} // sTooltipCallback
1512
1513
1514//
1515// CreateAutoHideTimer
1516//
1517// Create a new timer to see if we should auto-hide. It's ok if this fails.
1518//
1519void
1520ChromeTooltipListener::CreateAutoHideTimer()
1521{
1522  // just to be anal (er, safe)
1523  if ( mAutoHideTimer ) {
1524    mAutoHideTimer->Cancel();
1525    mAutoHideTimer = nsnull;
1526  }
1527  
1528  mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
1529  if ( mAutoHideTimer )
1530    mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, 
1531                                         nsITimer::TYPE_ONE_SHOT);
1532
1533} // CreateAutoHideTimer
1534
1535
1536//
1537// sAutoHideCallback
1538//
1539// This fires after a tooltip has been open for a certain length of time. Just tell
1540// the listener to close the popup. We don't have to worry, because HideTooltip() can
1541// be called multiple times, even if the tip has already been closed.
1542//
1543void
1544ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
1545{
1546  ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener);
1547  if ( self )
1548    self->HideTooltip();
1549
1550  // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
1551  
1552} // sAutoHideCallback
1553
1554
1555NS_IMPL_ISUPPORTS1(ChromeContextMenuListener, nsIDOMEventListener)
1556
1557
1558//
1559// ChromeTooltipListener ctor
1560//
1561ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) 
1562  : mContextMenuListenerInstalled(false),
1563    mWebBrowser(inBrowser),
1564    mWebBrowserChrome(inChrome)
1565{
1566} // ctor
1567
1568
1569//
1570// ChromeTooltipListener dtor
1571//
1572ChromeContextMenuListener::~ChromeContextMenuListener()
1573{
1574} // dtor
1575
1576
1577//
1578// AddContextMenuListener
1579//
1580// Subscribe to the events that will allow us to track context menus. Bascially, this
1581// is just the context-menu DOM event.
1582//
1583NS_IMETHODIMP
1584ChromeContextMenuListener::AddContextMenuListener()
1585{
1586  if (mEventTarget) {
1587    nsresult rv =
1588      mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
1589                                     false, false);
1590    NS_ENSURE_SUCCESS(rv, rv);
1591
1592    mContextMenuListenerInstalled = true;
1593  }
1594
1595  return NS_OK;
1596}
1597
1598
1599//
1600// RemoveContextMenuListener
1601//
1602// Unsubscribe from all the various context menu events that we were listening to. 
1603//
1604NS_IMETHODIMP 
1605ChromeContextMenuListener::RemoveContextMenuListener()
1606{
1607  if (mEventTarget) {
1608    nsresult rv =
1609      mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
1610                                        false);
1611    NS_ENSURE_SUCCESS(rv, rv);
1612
1613    mContextMenuListenerInstalled = false;
1614  }
1615
1616  return NS_OK;
1617}
1618
1619
1620//
1621// AddChromeListeners
1622//
1623// Hook up things to the chrome like context menus and tooltips, if the chrome
1624// has implemented the right interfaces.
1625//
1626NS_IMETHODIMP
1627ChromeContextMenuListener::AddChromeListeners()
1628{  
1629  if (!mEventTarget)
1630    GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1631  
1632  // Register the appropriate events for context menus, but only if
1633  // the embedding chrome cares.
1634  nsresult rv = NS_OK;
1635
1636  nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) );
1637  nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
1638  if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled )
1639    rv = AddContextMenuListener();
1640
1641  return rv;
1642  
1643} // AddChromeListeners
1644
1645
1646//
1647// RemoveChromeListeners
1648//
1649// Unsubscribe from the various things we've hooked up to the window root.
1650//
1651NS_IMETHODIMP
1652ChromeContextMenuListener::RemoveChromeListeners()
1653{
1654  if ( mContextMenuListenerInstalled )
1655    RemoveContextMenuListener();
1656  
1657  mEventTarget = nsnull;
1658  
1659  // it really doesn't matter if these fail...
1660  return NS_OK;
1661  
1662} // RemoveChromeTooltipListeners
1663
1664
1665
1666//
1667// ContextMenu
1668//
1669// We're on call to show the context menu. Dig around in the DOM to
1670// find the type of object we're dealing with and notify the front
1671// end chrome.
1672//
1673NS_IMETHODIMP
1674ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent)
1675{
1676  nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
1677  NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED);
1678
1679  nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aMouseEvent);
1680
1681  if (domNSEve

Large files files are truncated, but you can click here to view the full file