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.

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

mercurial