1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsDocShellTreeOwner.h"
9 #include "nsWebBrowser.h"
12 #include "nsContentUtils.h"
14 #include "mozilla/ReflowInput.h"
15 #include "mozilla/ScopeExit.h"
16 #include "nsComponentManagerUtils.h"
19 #include "nsReadableUtils.h"
20 #include "nsUnicharUtils.h"
21 #include "mozilla/StaticPrefs_ui.h"
23 // Interfaces needed to be included
24 #include "nsPresContext.h"
25 #include "nsITooltipListener.h"
28 #include "mozilla/dom/Document.h"
29 #include "mozilla/dom/Element.h"
30 #include "mozilla/dom/MouseEvent.h"
31 #include "mozilla/dom/SVGTitleElement.h"
32 #include "nsIFormControl.h"
33 #include "nsIWebNavigation.h"
34 #include "nsPIDOMWindow.h"
35 #include "nsPIWindowRoot.h"
36 #include "nsIWindowWatcher.h"
37 #include "nsPIWindowWatcher.h"
38 #include "nsIPrompt.h"
39 #include "nsIRemoteTab.h"
40 #include "nsIBrowserChild.h"
42 #include "nsIWebBrowserChromeFocus.h"
43 #include "nsIContent.h"
44 #include "nsServiceManagerUtils.h"
45 #include "nsViewManager.h"
47 #include "nsXULTooltipListener.h"
48 #include "nsIConstraintValidation.h"
49 #include "mozilla/Attributes.h"
50 #include "mozilla/EventListenerManager.h"
51 #include "mozilla/Try.h"
52 #include "mozilla/dom/DragEvent.h"
53 #include "mozilla/dom/Event.h" // for Event
54 #include "mozilla/dom/File.h" // for input type=file
55 #include "mozilla/dom/FileList.h" // for input type=file
56 #include "mozilla/dom/LoadURIOptionsBinding.h"
57 #include "mozilla/PresShell.h"
58 #include "mozilla/TextEvents.h"
60 using namespace mozilla
;
61 using namespace mozilla::dom
;
63 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
64 // a |EventTarget| via the window root and chrome event handler.
65 static nsresult
GetDOMEventTarget(nsWebBrowser
* aInBrowser
,
66 EventTarget
** aTarget
) {
68 return NS_ERROR_INVALID_POINTER
;
71 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
72 aInBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
74 return NS_ERROR_FAILURE
;
77 auto* outerWindow
= nsPIDOMWindowOuter::From(domWindow
);
78 nsPIDOMWindowOuter
* rootWindow
= outerWindow
->GetPrivateRoot();
79 NS_ENSURE_TRUE(rootWindow
, NS_ERROR_FAILURE
);
80 nsCOMPtr
<EventTarget
> target
= rootWindow
->GetChromeEventHandler();
81 NS_ENSURE_TRUE(target
, NS_ERROR_FAILURE
);
82 target
.forget(aTarget
);
87 nsDocShellTreeOwner::nsDocShellTreeOwner()
88 : mWebBrowser(nullptr),
90 mPrimaryContentShell(nullptr),
91 mWebBrowserChrome(nullptr),
93 mOwnerRequestor(nullptr) {}
95 nsDocShellTreeOwner::~nsDocShellTreeOwner() { RemoveChromeListeners(); }
97 NS_IMPL_ADDREF(nsDocShellTreeOwner
)
98 NS_IMPL_RELEASE(nsDocShellTreeOwner
)
100 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner
)
101 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDocShellTreeOwner
)
102 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner
)
103 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
104 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
105 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
106 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener
)
107 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
110 // The class that listens to the chrome events and tells the embedding chrome to
111 // show tooltips, as appropriate. Handles registering itself with the DOM with
112 // AddChromeListeners() and removing itself with RemoveChromeListeners().
113 class ChromeTooltipListener final
: public nsIDOMEventListener
{
115 virtual ~ChromeTooltipListener();
120 ChromeTooltipListener(nsWebBrowser
* aInBrowser
,
121 nsIWebBrowserChrome
* aInChrome
);
123 NS_DECL_NSIDOMEVENTLISTENER
124 NS_IMETHOD
MouseMove(mozilla::dom::Event
* aMouseEvent
);
126 // Add/remove the relevant listeners, based on what interfaces the embedding
127 // chrome implements.
128 NS_IMETHOD
AddChromeListeners();
129 NS_IMETHOD
RemoveChromeListeners();
131 NS_IMETHOD
HideTooltip();
133 bool WebProgressShowedTooltip(nsIWebProgress
* aWebProgress
);
136 // pixel tolerance for mousemove event
137 static constexpr CSSIntCoord kTooltipMouseMoveTolerance
= 7;
139 NS_IMETHOD
AddTooltipListener();
140 NS_IMETHOD
RemoveTooltipListener();
142 NS_IMETHOD
ShowTooltip(int32_t aInXCoords
, int32_t aInYCoords
,
143 const nsAString
& aInTipText
,
144 const nsAString
& aDirText
);
145 nsITooltipTextProvider
* GetTooltipTextProvider();
147 nsWebBrowser
* mWebBrowser
;
148 nsCOMPtr
<mozilla::dom::EventTarget
> mEventTarget
;
149 nsCOMPtr
<nsITooltipTextProvider
> mTooltipTextProvider
;
151 // This must be a strong ref in order to make sure we can hide the tooltip if
152 // the window goes away while we're displaying one. If we don't hold a strong
153 // ref, the chrome might have been disposed of before we get a chance to tell
154 // it, and no one would ever tell us of that fact.
155 nsCOMPtr
<nsIWebBrowserChrome
> mWebBrowserChrome
;
157 bool mTooltipListenerInstalled
;
159 nsCOMPtr
<nsITimer
> mTooltipTimer
;
160 static void sTooltipCallback(nsITimer
* aTimer
, void* aListener
);
162 // Mouse coordinates for last mousemove event we saw
163 CSSIntPoint mMouseClientPoint
;
165 // Mouse coordinates for tooltip event
166 LayoutDeviceIntPoint mMouseScreenPoint
;
168 bool mShowingTooltip
;
170 bool mTooltipShownOnce
;
172 // The string of text that we last displayed.
173 nsString mLastShownTooltipText
;
175 nsWeakPtr mLastDocshell
;
177 // The node hovered over that fired the timer. This may turn into the node
178 // that triggered the tooltip, but only if the timer ever gets around to
179 // firing. This is a strong reference, because the tooltip content can be
180 // destroyed while we're waiting for the tooltip to pop up, and we need to
181 // detect that. It's set only when the tooltip timer is created and launched.
182 // The timer must either fire or be cancelled (or possibly released?), and we
183 // release this reference in each of those cases. So we don't leak.
184 nsCOMPtr
<nsINode
> mPossibleTooltipNode
;
187 //*****************************************************************************
188 // nsDocShellTreeOwner::nsIInterfaceRequestor
189 //*****************************************************************************
192 nsDocShellTreeOwner::GetInterface(const nsIID
& aIID
, void** aSink
) {
193 NS_ENSURE_ARG_POINTER(aSink
);
195 if (NS_SUCCEEDED(QueryInterface(aIID
, aSink
))) {
199 if (aIID
.Equals(NS_GET_IID(nsIWebBrowserChromeFocus
))) {
200 if (mWebBrowserChromeWeak
!= nullptr) {
201 return mWebBrowserChromeWeak
->QueryReferent(aIID
, aSink
);
203 return mOwnerWin
->QueryInterface(aIID
, aSink
);
206 if (aIID
.Equals(NS_GET_IID(nsIPrompt
))) {
207 nsCOMPtr
<nsIPrompt
> prompt
;
211 prompt
.forget(aSink
);
214 return NS_NOINTERFACE
;
217 if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
))) {
218 nsCOMPtr
<nsIAuthPrompt
> prompt
;
219 EnsureAuthPrompter();
220 prompt
= mAuthPrompter
;
222 prompt
.forget(aSink
);
225 return NS_NOINTERFACE
;
228 nsCOMPtr
<nsIInterfaceRequestor
> req
= GetOwnerRequestor();
230 return req
->GetInterface(aIID
, aSink
);
233 return NS_NOINTERFACE
;
236 //*****************************************************************************
237 // nsDocShellTreeOwner::nsIDocShellTreeOwner
238 //*****************************************************************************
240 void nsDocShellTreeOwner::EnsurePrompter() {
245 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
246 if (wwatch
&& mWebBrowser
) {
247 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
248 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
250 wwatch
->GetNewPrompter(domWindow
, getter_AddRefs(mPrompter
));
255 void nsDocShellTreeOwner::EnsureAuthPrompter() {
260 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
261 if (wwatch
&& mWebBrowser
) {
262 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
263 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
265 wwatch
->GetNewAuthPrompter(domWindow
, getter_AddRefs(mAuthPrompter
));
270 void nsDocShellTreeOwner::AddToWatcher() {
272 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
273 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
275 nsCOMPtr
<nsPIWindowWatcher
> wwatch(
276 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
278 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
279 if (webBrowserChrome
) {
280 wwatch
->AddWindow(domWindow
, webBrowserChrome
);
287 void nsDocShellTreeOwner::RemoveFromWatcher() {
289 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
290 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
292 nsCOMPtr
<nsPIWindowWatcher
> wwatch(
293 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
295 wwatch
->RemoveWindow(domWindow
);
301 void nsDocShellTreeOwner::EnsureContentTreeOwner() {
302 if (mContentTreeOwner
) {
306 mContentTreeOwner
= new nsDocShellTreeOwner();
307 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= GetWebBrowserChrome();
309 mContentTreeOwner
->SetWebBrowserChrome(browserChrome
);
313 mContentTreeOwner
->WebBrowser(mWebBrowser
);
318 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem
* aContentShell
,
320 if (mTreeOwner
) return mTreeOwner
->ContentShellAdded(aContentShell
, aPrimary
);
322 EnsureContentTreeOwner();
323 aContentShell
->SetTreeOwner(mContentTreeOwner
);
326 mPrimaryContentShell
= aContentShell
;
327 mPrimaryRemoteTab
= nullptr;
333 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem
* aContentShell
) {
335 return mTreeOwner
->ContentShellRemoved(aContentShell
);
338 if (mPrimaryContentShell
== aContentShell
) {
339 mPrimaryContentShell
= nullptr;
346 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem
** aShell
) {
347 NS_ENSURE_ARG_POINTER(aShell
);
350 return mTreeOwner
->GetPrimaryContentShell(aShell
);
353 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
354 if (!mPrimaryRemoteTab
) {
356 mPrimaryContentShell
? mPrimaryContentShell
: mWebBrowser
->mDocShell
;
358 shell
.forget(aShell
);
364 nsDocShellTreeOwner::RemoteTabAdded(nsIRemoteTab
* aTab
, bool aPrimary
) {
366 return mTreeOwner
->RemoteTabAdded(aTab
, aPrimary
);
370 mPrimaryRemoteTab
= aTab
;
371 mPrimaryContentShell
= nullptr;
372 } else if (mPrimaryRemoteTab
== aTab
) {
373 mPrimaryRemoteTab
= nullptr;
380 nsDocShellTreeOwner::RemoteTabRemoved(nsIRemoteTab
* aTab
) {
382 return mTreeOwner
->RemoteTabRemoved(aTab
);
385 if (aTab
== mPrimaryRemoteTab
) {
386 mPrimaryRemoteTab
= nullptr;
393 nsDocShellTreeOwner::GetPrimaryRemoteTab(nsIRemoteTab
** aTab
) {
395 return mTreeOwner
->GetPrimaryRemoteTab(aTab
);
398 nsCOMPtr
<nsIRemoteTab
> tab
= mPrimaryRemoteTab
;
404 nsDocShellTreeOwner::GetPrimaryContentBrowsingContext(
405 mozilla::dom::BrowsingContext
** aBc
) {
407 return mTreeOwner
->GetPrimaryContentBrowsingContext(aBc
);
409 if (mPrimaryRemoteTab
) {
410 return mPrimaryRemoteTab
->GetBrowsingContext(aBc
);
412 if (mPrimaryContentShell
) {
413 return mPrimaryContentShell
->GetBrowsingContextXPCOM(aBc
);
415 if (mWebBrowser
->mDocShell
) {
416 return mWebBrowser
->mDocShell
->GetBrowsingContextXPCOM(aBc
);
423 nsDocShellTreeOwner::GetPrimaryContentSize(int32_t* aWidth
, int32_t* aHeight
) {
424 return NS_ERROR_NOT_IMPLEMENTED
;
428 nsDocShellTreeOwner::SetPrimaryContentSize(int32_t aWidth
, int32_t aHeight
) {
429 return NS_ERROR_NOT_IMPLEMENTED
;
433 nsDocShellTreeOwner::GetRootShellSize(int32_t* aWidth
, int32_t* aHeight
) {
434 return NS_ERROR_NOT_IMPLEMENTED
;
438 nsDocShellTreeOwner::SetRootShellSize(int32_t aWidth
, int32_t aHeight
) {
439 return NS_ERROR_NOT_IMPLEMENTED
;
443 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem
* aShellItem
, int32_t aCX
,
445 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
447 NS_ENSURE_STATE(mTreeOwner
|| webBrowserChrome
);
449 if (nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= mTreeOwner
) {
450 return treeOwner
->SizeShellTo(aShellItem
, aCX
, aCY
);
453 if (aShellItem
== mWebBrowser
->mDocShell
) {
454 nsCOMPtr
<nsIBrowserChild
> browserChild
=
455 do_QueryInterface(webBrowserChrome
);
457 // The XUL window to resize is in the parent process, but there we
458 // won't be able to get the size of aShellItem. We can ask the parent
459 // process to change our size instead.
460 nsCOMPtr
<nsIBaseWindow
> shellAsWin(do_QueryInterface(aShellItem
));
461 NS_ENSURE_TRUE(shellAsWin
, NS_ERROR_FAILURE
);
463 LayoutDeviceIntSize shellSize
;
464 shellAsWin
->GetSize(&shellSize
.width
, &shellSize
.height
);
465 LayoutDeviceIntSize deltaSize
= LayoutDeviceIntSize(aCX
, aCY
) - shellSize
;
467 LayoutDeviceIntSize currentSize
;
468 GetSize(¤tSize
.width
, ¤tSize
.height
);
470 LayoutDeviceIntSize newSize
= currentSize
+ deltaSize
;
471 return SetSize(newSize
.width
, newSize
.height
, true);
473 // XXX: this is weird, but we used to call a method here
474 // (webBrowserChrome->SizeBrowserTo()) whose implementations all failed
476 return NS_ERROR_NOT_IMPLEMENTED
;
479 MOZ_ASSERT_UNREACHABLE("This is unimplemented, API should be cleaned up");
480 return NS_ERROR_NOT_IMPLEMENTED
;
484 nsDocShellTreeOwner::SetPersistence(bool aPersistPosition
, bool aPersistSize
,
485 bool aPersistSizeMode
) {
486 return NS_ERROR_NOT_IMPLEMENTED
;
490 nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition
, bool* aPersistSize
,
491 bool* aPersistSizeMode
) {
492 return NS_ERROR_NOT_IMPLEMENTED
;
496 nsDocShellTreeOwner::GetTabCount(uint32_t* aResult
) {
498 return mTreeOwner
->GetTabCount(aResult
);
506 nsDocShellTreeOwner::GetHasPrimaryContent(bool* aResult
) {
507 *aResult
= mPrimaryRemoteTab
|| mPrimaryContentShell
;
511 //*****************************************************************************
512 // nsDocShellTreeOwner::nsIBaseWindow
513 //*****************************************************************************
516 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow
,
517 nsIWidget
* aParentWidget
, int32_t aX
,
518 int32_t aY
, int32_t aCX
, int32_t aCY
) {
519 return NS_ERROR_NULL_POINTER
;
523 nsDocShellTreeOwner::Destroy() {
524 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
525 if (webBrowserChrome
) {
526 // XXX: this is weird, but we used to call a method here
527 // (webBrowserChrome->DestroyBrowserWindow()) whose implementations all
528 // failed like this, so...
529 return NS_ERROR_NOT_IMPLEMENTED
;
532 return NS_ERROR_NULL_POINTER
;
535 double nsDocShellTreeOwner::GetWidgetCSSToDeviceScale() {
536 return mWebBrowser
? mWebBrowser
->GetWidgetCSSToDeviceScale() : 1.0;
540 nsDocShellTreeOwner::GetDevicePixelsPerDesktopPixel(double* aScale
) {
542 return mWebBrowser
->GetDevicePixelsPerDesktopPixel(aScale
);
550 nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX
, int32_t aY
) {
552 nsresult rv
= mWebBrowser
->SetPositionDesktopPix(aX
, aY
);
553 NS_ENSURE_SUCCESS(rv
, rv
);
557 GetDevicePixelsPerDesktopPixel(&scale
);
558 return SetPosition(NSToIntRound(aX
* scale
), NSToIntRound(aY
* scale
));
562 nsDocShellTreeOwner::SetPosition(int32_t aX
, int32_t aY
) {
563 return SetDimensions(
564 {DimensionKind::Outer
, Some(aX
), Some(aY
), Nothing(), Nothing()});
568 nsDocShellTreeOwner::GetPosition(int32_t* aX
, int32_t* aY
) {
569 return GetDimensions(DimensionKind::Outer
, aX
, aY
, nullptr, nullptr);
573 nsDocShellTreeOwner::SetSize(int32_t aCX
, int32_t aCY
, bool aRepaint
) {
574 return SetDimensions(
575 {DimensionKind::Outer
, Nothing(), Nothing(), Some(aCX
), Some(aCY
)});
579 nsDocShellTreeOwner::GetSize(int32_t* aCX
, int32_t* aCY
) {
580 return GetDimensions(DimensionKind::Outer
, nullptr, nullptr, aCX
, aCY
);
584 nsDocShellTreeOwner::SetPositionAndSize(int32_t aX
, int32_t aY
, int32_t aCX
,
585 int32_t aCY
, uint32_t aFlags
) {
586 return SetDimensions(
587 {DimensionKind::Outer
, Some(aX
), Some(aY
), Some(aCX
), Some(aCY
)});
591 nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX
, int32_t* aY
, int32_t* aCX
,
593 return GetDimensions(DimensionKind::Outer
, aX
, aY
, aCX
, aCY
);
597 nsDocShellTreeOwner::SetDimensions(DimensionRequest
&& aRequest
) {
598 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
600 return ownerWin
->SetDimensions(std::move(aRequest
));
603 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
604 NS_ENSURE_STATE(webBrowserChrome
);
605 return webBrowserChrome
->SetDimensions(std::move(aRequest
));
609 nsDocShellTreeOwner::GetDimensions(DimensionKind aDimensionKind
, int32_t* aX
,
610 int32_t* aY
, int32_t* aCX
, int32_t* aCY
) {
611 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
613 return ownerWin
->GetDimensions(aDimensionKind
, aX
, aY
, aCX
, aCY
);
616 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
617 NS_ENSURE_STATE(webBrowserChrome
);
618 return webBrowserChrome
->GetDimensions(aDimensionKind
, aX
, aY
, aCX
, aCY
);
622 nsDocShellTreeOwner::Repaint(bool aForce
) { return NS_ERROR_NULL_POINTER
; }
625 nsDocShellTreeOwner::GetParentWidget(nsIWidget
** aParentWidget
) {
626 return NS_ERROR_NULL_POINTER
;
630 nsDocShellTreeOwner::SetParentWidget(nsIWidget
* aParentWidget
) {
631 return NS_ERROR_NULL_POINTER
;
635 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow
* aParentNativeWindow
) {
636 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
638 return ownerWin
->GetParentNativeWindow(aParentNativeWindow
);
640 return NS_ERROR_NULL_POINTER
;
644 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow
) {
645 return NS_ERROR_NULL_POINTER
;
649 nsDocShellTreeOwner::GetNativeHandle(nsAString
& aNativeHandle
) {
650 // the nativeHandle should be accessed from nsIAppWindow
651 return NS_ERROR_NOT_IMPLEMENTED
;
655 nsDocShellTreeOwner::GetVisibility(bool* aVisibility
) {
656 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
658 return ownerWin
->GetVisibility(aVisibility
);
661 return NS_ERROR_NOT_IMPLEMENTED
;
665 nsDocShellTreeOwner::SetVisibility(bool aVisibility
) {
666 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
668 return ownerWin
->SetVisibility(aVisibility
);
670 return NS_ERROR_NULL_POINTER
;
674 nsDocShellTreeOwner::GetEnabled(bool* aEnabled
) {
675 NS_ENSURE_ARG_POINTER(aEnabled
);
677 return NS_ERROR_NOT_IMPLEMENTED
;
681 nsDocShellTreeOwner::SetEnabled(bool aEnabled
) {
682 return NS_ERROR_NOT_IMPLEMENTED
;
686 nsDocShellTreeOwner::GetMainWidget(nsIWidget
** aMainWidget
) {
687 return NS_ERROR_NULL_POINTER
;
691 nsDocShellTreeOwner::GetTitle(nsAString
& aTitle
) {
692 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
694 return ownerWin
->GetTitle(aTitle
);
696 return NS_ERROR_NULL_POINTER
;
700 nsDocShellTreeOwner::SetTitle(const nsAString
& aTitle
) {
701 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
703 return ownerWin
->SetTitle(aTitle
);
705 return NS_ERROR_NULL_POINTER
;
708 //*****************************************************************************
709 // nsDocShellTreeOwner::nsIWebProgressListener
710 //*****************************************************************************
713 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress
* aProgress
,
714 nsIRequest
* aRequest
,
715 int32_t aCurSelfProgress
,
716 int32_t aMaxSelfProgress
,
717 int32_t aCurTotalProgress
,
718 int32_t aMaxTotalProgress
) {
719 // In the absence of DOM document creation event, this method is the
720 // most convenient place to install the mouse listener on the
722 return AddChromeListeners();
726 nsDocShellTreeOwner::OnStateChange(nsIWebProgress
* aProgress
,
727 nsIRequest
* aRequest
,
728 uint32_t aProgressStateFlags
,
734 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress
* aWebProgress
,
735 nsIRequest
* aRequest
, nsIURI
* aURI
,
737 if (mChromeTooltipListener
&& aWebProgress
&&
738 !(aFlags
& nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT
) &&
739 mChromeTooltipListener
->WebProgressShowedTooltip(aWebProgress
)) {
740 mChromeTooltipListener
->HideTooltip();
746 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress
* aWebProgress
,
747 nsIRequest
* aRequest
, nsresult aStatus
,
748 const char16_t
* aMessage
) {
753 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress
* aWebProgress
,
754 nsIRequest
* aRequest
, uint32_t aState
) {
759 nsDocShellTreeOwner::OnContentBlockingEvent(nsIWebProgress
* aWebProgress
,
760 nsIRequest
* aRequest
,
765 //*****************************************************************************
766 // nsDocShellTreeOwner: Accessors
767 //*****************************************************************************
769 void nsDocShellTreeOwner::WebBrowser(nsWebBrowser
* aWebBrowser
) {
771 RemoveChromeListeners();
773 if (aWebBrowser
!= mWebBrowser
) {
775 mAuthPrompter
= nullptr;
778 mWebBrowser
= aWebBrowser
;
780 if (mContentTreeOwner
) {
781 mContentTreeOwner
->WebBrowser(aWebBrowser
);
783 mContentTreeOwner
= nullptr;
788 nsWebBrowser
* nsDocShellTreeOwner::WebBrowser() { return mWebBrowser
; }
791 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
) {
793 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome(do_GetInterface(aTreeOwner
));
794 NS_ENSURE_TRUE(webBrowserChrome
, NS_ERROR_INVALID_ARG
);
795 NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome
),
796 NS_ERROR_INVALID_ARG
);
797 mTreeOwner
= aTreeOwner
;
799 mTreeOwner
= nullptr;
800 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
801 if (!webBrowserChrome
) {
802 NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE
);
810 nsDocShellTreeOwner::SetWebBrowserChrome(
811 nsIWebBrowserChrome
* aWebBrowserChrome
) {
812 if (!aWebBrowserChrome
) {
813 mWebBrowserChrome
= nullptr;
815 mOwnerRequestor
= nullptr;
816 mWebBrowserChromeWeak
= nullptr;
818 nsCOMPtr
<nsISupportsWeakReference
> supportsweak
=
819 do_QueryInterface(aWebBrowserChrome
);
821 supportsweak
->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak
));
823 nsCOMPtr
<nsIBaseWindow
> ownerWin(do_QueryInterface(aWebBrowserChrome
));
824 nsCOMPtr
<nsIInterfaceRequestor
> requestor(
825 do_QueryInterface(aWebBrowserChrome
));
827 // it's ok for ownerWin or requestor to be null.
828 mWebBrowserChrome
= aWebBrowserChrome
;
829 mOwnerWin
= ownerWin
;
830 mOwnerRequestor
= requestor
;
834 if (mContentTreeOwner
) {
835 mContentTreeOwner
->SetWebBrowserChrome(aWebBrowserChrome
);
841 // Hook up things to the chrome like context menus and tooltips, if the chrome
842 // has implemented the right interfaces.
844 nsDocShellTreeOwner::AddChromeListeners() {
847 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
848 if (!webBrowserChrome
) {
849 return NS_ERROR_FAILURE
;
853 if (!mChromeTooltipListener
) {
854 nsCOMPtr
<nsITooltipListener
> tooltipListener(
855 do_QueryInterface(webBrowserChrome
));
856 if (tooltipListener
) {
857 mChromeTooltipListener
=
858 new ChromeTooltipListener(mWebBrowser
, webBrowserChrome
);
859 rv
= mChromeTooltipListener
->AddChromeListeners();
863 nsCOMPtr
<EventTarget
> target
;
864 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(target
));
866 // register dragover and drop event listeners with the listener manager
867 MOZ_ASSERT(target
, "how does this happen? (see bug 1659758)");
869 if (EventListenerManager
* elmP
= target
->GetOrCreateListenerManager()) {
870 elmP
->AddEventListenerByType(this, u
"dragover"_ns
,
871 TrustedEventsAtSystemGroupBubble());
872 elmP
->AddEventListenerByType(this, u
"drop"_ns
,
873 TrustedEventsAtSystemGroupBubble());
881 nsDocShellTreeOwner::RemoveChromeListeners() {
882 if (mChromeTooltipListener
) {
883 mChromeTooltipListener
->RemoveChromeListeners();
884 mChromeTooltipListener
= nullptr;
887 nsCOMPtr
<EventTarget
> piTarget
;
888 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(piTarget
));
893 EventListenerManager
* elmP
= piTarget
->GetOrCreateListenerManager();
895 elmP
->RemoveEventListenerByType(this, u
"dragover"_ns
,
896 TrustedEventsAtSystemGroupBubble());
897 elmP
->RemoveEventListenerByType(this, u
"drop"_ns
,
898 TrustedEventsAtSystemGroupBubble());
905 nsDocShellTreeOwner::HandleEvent(Event
* aEvent
) {
906 DragEvent
* dragEvent
= aEvent
? aEvent
->AsDragEvent() : nullptr;
907 if (NS_WARN_IF(!dragEvent
)) {
908 return NS_ERROR_INVALID_ARG
;
911 if (dragEvent
->DefaultPrevented()) {
915 nsCOMPtr
<nsIDroppedLinkHandler
> handler
=
916 do_GetService("@mozilla.org/content/dropped-link-handler;1");
921 nsAutoString eventType
;
922 aEvent
->GetType(eventType
);
923 if (eventType
.EqualsLiteral("dragover")) {
924 bool canDropLink
= false;
925 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
927 aEvent
->PreventDefault();
929 } else if (eventType
.EqualsLiteral("drop")) {
930 nsCOMPtr
<nsIWebNavigation
> webnav
=
931 static_cast<nsIWebNavigation
*>(mWebBrowser
);
933 // The page might have cancelled the dragover event itself, so check to
934 // make sure that the link can be dropped first.
935 bool canDropLink
= false;
936 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
941 nsTArray
<RefPtr
<nsIDroppedLinkItem
>> links
;
942 if (webnav
&& NS_SUCCEEDED(handler
->DropLinks(dragEvent
, true, links
))) {
943 if (links
.Length() >= 1) {
944 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
945 handler
->GetTriggeringPrincipal(dragEvent
,
946 getter_AddRefs(triggeringPrincipal
));
947 if (triggeringPrincipal
) {
948 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
=
949 GetWebBrowserChrome();
950 if (webBrowserChrome
) {
951 nsCOMPtr
<nsIBrowserChild
> browserChild
=
952 do_QueryInterface(webBrowserChrome
);
954 nsresult rv
= browserChild
->RemoteDropLinks(links
);
959 if (NS_SUCCEEDED(links
[0]->GetUrl(url
))) {
960 if (!url
.IsEmpty()) {
962 MOZ_ASSERT(triggeringPrincipal
,
963 "nsDocShellTreeOwner::HandleEvent: Need a valid "
964 "triggeringPrincipal");
966 LoadURIOptions loadURIOptions
;
967 loadURIOptions
.mTriggeringPrincipal
= triggeringPrincipal
;
968 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
969 handler
->GetCsp(dragEvent
, getter_AddRefs(csp
));
970 loadURIOptions
.mCsp
= csp
;
971 webnav
->FixupAndLoadURIString(url
, loadURIOptions
);
977 aEvent
->StopPropagation();
978 aEvent
->PreventDefault();
985 already_AddRefed
<nsIWebBrowserChrome
>
986 nsDocShellTreeOwner::GetWebBrowserChrome() {
987 nsCOMPtr
<nsIWebBrowserChrome
> chrome
;
988 if (mWebBrowserChromeWeak
) {
989 chrome
= do_QueryReferent(mWebBrowserChromeWeak
);
990 } else if (mWebBrowserChrome
) {
991 chrome
= mWebBrowserChrome
;
993 return chrome
.forget();
996 already_AddRefed
<nsIBaseWindow
> nsDocShellTreeOwner::GetOwnerWin() {
997 nsCOMPtr
<nsIBaseWindow
> win
;
998 if (mWebBrowserChromeWeak
) {
999 win
= do_QueryReferent(mWebBrowserChromeWeak
);
1000 } else if (mOwnerWin
) {
1003 return win
.forget();
1006 already_AddRefed
<nsIInterfaceRequestor
>
1007 nsDocShellTreeOwner::GetOwnerRequestor() {
1008 nsCOMPtr
<nsIInterfaceRequestor
> req
;
1009 if (mWebBrowserChromeWeak
) {
1010 req
= do_QueryReferent(mWebBrowserChromeWeak
);
1011 } else if (mOwnerRequestor
) {
1012 req
= mOwnerRequestor
;
1014 return req
.forget();
1017 NS_IMPL_ISUPPORTS(ChromeTooltipListener
, nsIDOMEventListener
)
1019 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser
* aInBrowser
,
1020 nsIWebBrowserChrome
* aInChrome
)
1021 : mWebBrowser(aInBrowser
),
1022 mWebBrowserChrome(aInChrome
),
1023 mTooltipListenerInstalled(false),
1024 mShowingTooltip(false),
1025 mTooltipShownOnce(false) {}
1027 ChromeTooltipListener::~ChromeTooltipListener() {}
1029 nsITooltipTextProvider
* ChromeTooltipListener::GetTooltipTextProvider() {
1030 if (!mTooltipTextProvider
) {
1031 mTooltipTextProvider
= do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID
);
1034 if (!mTooltipTextProvider
) {
1035 mTooltipTextProvider
=
1036 do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID
);
1039 return mTooltipTextProvider
;
1042 // Hook up things to the chrome like context menus and tooltips, if the chrome
1043 // has implemented the right interfaces.
1045 ChromeTooltipListener::AddChromeListeners() {
1046 if (!mEventTarget
) {
1047 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(mEventTarget
));
1050 // Register the appropriate events for tooltips, but only if
1051 // the embedding chrome cares.
1052 nsresult rv
= NS_OK
;
1053 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1054 do_QueryInterface(mWebBrowserChrome
));
1055 if (tooltipListener
&& !mTooltipListenerInstalled
) {
1056 rv
= AddTooltipListener();
1057 if (NS_FAILED(rv
)) {
1065 // Subscribe to the events that will allow us to track tooltips. We need "mouse"
1066 // for mouseExit, "mouse motion" for mouseMove, and "key" for keyDown. As we
1067 // add the listeners, keep track of how many succeed so we can clean up
1068 // correctly in Release().
1070 ChromeTooltipListener::AddTooltipListener() {
1072 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"keydown"_ns
, this, false,
1074 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousedown"_ns
, this, false,
1076 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mouseout"_ns
, this, false,
1078 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousemove"_ns
, this, false,
1081 mTooltipListenerInstalled
= true;
1087 // Unsubscribe from the various things we've hooked up to the window root.
1089 ChromeTooltipListener::RemoveChromeListeners() {
1092 if (mTooltipListenerInstalled
) {
1093 RemoveTooltipListener();
1096 mEventTarget
= nullptr;
1098 // it really doesn't matter if these fail...
1102 // Unsubscribe from all the various tooltip events that we were listening to.
1104 ChromeTooltipListener::RemoveTooltipListener() {
1106 mEventTarget
->RemoveSystemEventListener(u
"keydown"_ns
, this, false);
1107 mEventTarget
->RemoveSystemEventListener(u
"mousedown"_ns
, this, false);
1108 mEventTarget
->RemoveSystemEventListener(u
"mouseout"_ns
, this, false);
1109 mEventTarget
->RemoveSystemEventListener(u
"mousemove"_ns
, this, false);
1110 mTooltipListenerInstalled
= false;
1117 ChromeTooltipListener::HandleEvent(Event
* aEvent
) {
1118 nsAutoString eventType
;
1119 aEvent
->GetType(eventType
);
1121 if (eventType
.EqualsLiteral("mousedown")) {
1122 return HideTooltip();
1123 } else if (eventType
.EqualsLiteral("keydown")) {
1124 WidgetKeyboardEvent
* keyEvent
= aEvent
->WidgetEventPtr()->AsKeyboardEvent();
1125 if (nsXULTooltipListener::KeyEventHidesTooltip(*keyEvent
)) {
1126 return HideTooltip();
1129 } else if (eventType
.EqualsLiteral("mouseout")) {
1130 // Reset flag so that tooltip will display on the next MouseMove
1131 mTooltipShownOnce
= false;
1132 return HideTooltip();
1133 } else if (eventType
.EqualsLiteral("mousemove")) {
1134 return MouseMove(aEvent
);
1137 NS_ERROR("Unexpected event type");
1141 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If
1142 // the timer fires, we cache the node in |mPossibleTooltipNode|.
1143 nsresult
ChromeTooltipListener::MouseMove(Event
* aMouseEvent
) {
1144 if (!nsXULTooltipListener::ShowTooltips()) {
1148 MouseEvent
* mouseEvent
= aMouseEvent
->AsMouseEvent();
1153 // stash the coordinates of the event so that we can still get back to it from
1154 // within the timer callback. On win32, we'll get a MouseMove event even when
1155 // a popup goes away -- even when the mouse doesn't change position! To get
1156 // around this, we make sure the mouse has really moved before proceeding.
1157 CSSIntPoint newMouseClientPoint
= mouseEvent
->ClientPoint();
1158 if (mMouseClientPoint
== newMouseClientPoint
) {
1162 // Filter out minor mouse movements.
1163 if (mShowingTooltip
&&
1164 (abs(mMouseClientPoint
.x
- newMouseClientPoint
.x
) <=
1165 kTooltipMouseMoveTolerance
) &&
1166 (abs(mMouseClientPoint
.y
- newMouseClientPoint
.y
) <=
1167 kTooltipMouseMoveTolerance
)) {
1171 mMouseClientPoint
= newMouseClientPoint
;
1172 mMouseScreenPoint
= mouseEvent
->ScreenPointLayoutDevicePix();
1174 if (mTooltipTimer
) {
1175 mTooltipTimer
->Cancel();
1176 mTooltipTimer
= nullptr;
1179 if (!mShowingTooltip
) {
1180 if (nsCOMPtr
<EventTarget
> eventTarget
= aMouseEvent
->GetOriginalTarget()) {
1181 mPossibleTooltipNode
= nsINode::FromEventTarget(eventTarget
);
1184 if (mPossibleTooltipNode
) {
1185 nsresult rv
= NS_NewTimerWithFuncCallback(
1186 getter_AddRefs(mTooltipTimer
), sTooltipCallback
, this,
1187 StaticPrefs::ui_tooltip_delay_ms(), nsITimer::TYPE_ONE_SHOT
,
1188 "ChromeTooltipListener::MouseMove", GetMainThreadSerialEventTarget());
1189 if (NS_FAILED(rv
)) {
1190 mPossibleTooltipNode
= nullptr;
1191 NS_WARNING("Could not create a timer for tooltip tracking");
1195 mTooltipShownOnce
= true;
1196 return HideTooltip();
1202 // Tell the registered chrome that they should show the tooltip.
1204 ChromeTooltipListener::ShowTooltip(int32_t aInXCoords
, int32_t aInYCoords
,
1205 const nsAString
& aInTipText
,
1206 const nsAString
& aTipDir
) {
1207 nsresult rv
= NS_OK
;
1209 // do the work to call the client
1210 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1211 do_QueryInterface(mWebBrowserChrome
));
1212 if (tooltipListener
) {
1213 rv
= tooltipListener
->OnShowTooltip(aInXCoords
, aInYCoords
, aInTipText
,
1215 if (NS_SUCCEEDED(rv
)) {
1216 mShowingTooltip
= true;
1223 // Tell the registered chrome that they should rollup the tooltip
1224 // NOTE: This routine is safe to call even if the popup is already closed.
1226 ChromeTooltipListener::HideTooltip() {
1227 nsresult rv
= NS_OK
;
1229 // shut down the relevant timers
1230 if (mTooltipTimer
) {
1231 mTooltipTimer
->Cancel();
1232 mTooltipTimer
= nullptr;
1233 // release tooltip target
1234 mPossibleTooltipNode
= nullptr;
1235 mLastDocshell
= nullptr;
1238 // if we're showing the tip, tell the chrome to hide it
1239 if (mShowingTooltip
) {
1240 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1241 do_QueryInterface(mWebBrowserChrome
));
1242 if (tooltipListener
) {
1243 rv
= tooltipListener
->OnHideTooltip();
1244 if (NS_SUCCEEDED(rv
)) {
1245 mShowingTooltip
= false;
1253 bool ChromeTooltipListener::WebProgressShowedTooltip(
1254 nsIWebProgress
* aWebProgress
) {
1255 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryInterface(aWebProgress
);
1256 nsCOMPtr
<nsIDocShell
> lastUsed
= do_QueryReferent(mLastDocshell
);
1258 if (lastUsed
== docshell
) {
1261 // We can't use the docshell hierarchy here, because when the parent
1262 // docshell is navigated, the child docshell is disconnected (ie its
1263 // references to the parent are nulled out) despite it still being
1264 // alive here. So we use the document hierarchy instead:
1265 Document
* document
= lastUsed
->GetDocument();
1267 document
= document
->GetInProcessParentDocument();
1272 lastUsed
= document
->GetDocShell();
1277 // A timer callback, fired when the mouse has hovered inside of a frame for the
1278 // appropriate amount of time. Getting to this point means that we should show
1279 // the tooltip, but only after we determine there is an appropriate TITLE
1282 // This relies on certain things being cached into the |aChromeTooltipListener|
1283 // object passed to us by the timer:
1284 // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1285 // -- the dom node the user hovered over (mPossibleTooltipNode)
1286 void ChromeTooltipListener::sTooltipCallback(nsITimer
* aTimer
,
1287 void* aChromeTooltipListener
) {
1288 auto* self
= static_cast<ChromeTooltipListener
*>(aChromeTooltipListener
);
1289 if (!self
|| !self
->mPossibleTooltipNode
) {
1292 // release tooltip target once done, no matter what we do here.
1293 auto cleanup
= MakeScopeExit([&] { self
->mPossibleTooltipNode
= nullptr; });
1294 if (!self
->mPossibleTooltipNode
->IsInComposedDoc()) {
1297 // Check that the document or its ancestors haven't been replaced.
1299 Document
* doc
= self
->mPossibleTooltipNode
->OwnerDoc();
1301 if (!doc
->IsCurrentActiveDocument()) {
1304 doc
= doc
->GetInProcessParentDocument();
1308 nsCOMPtr
<nsIDocShell
> docShell
=
1309 do_GetInterface(static_cast<nsIWebBrowser
*>(self
->mWebBrowser
));
1310 if (!docShell
|| !docShell
->GetBrowsingContext()->IsActive()) {
1314 // if there is text associated with the node, show the tip and fire
1315 // off a timer to auto-hide it.
1316 nsITooltipTextProvider
* tooltipProvider
= self
->GetTooltipTextProvider();
1317 if (!tooltipProvider
) {
1320 nsString tooltipText
;
1321 nsString directionText
;
1322 bool textFound
= false;
1323 tooltipProvider
->GetNodeText(self
->mPossibleTooltipNode
,
1324 getter_Copies(tooltipText
),
1325 getter_Copies(directionText
), &textFound
);
1327 if (textFound
&& (!self
->mTooltipShownOnce
||
1328 tooltipText
!= self
->mLastShownTooltipText
)) {
1329 // ShowTooltip expects screen-relative position.
1330 self
->ShowTooltip(self
->mMouseScreenPoint
.x
, self
->mMouseScreenPoint
.y
,
1331 tooltipText
, directionText
);
1332 self
->mLastShownTooltipText
= std::move(tooltipText
);
1333 self
->mLastDocshell
= do_GetWeakReference(
1334 self
->mPossibleTooltipNode
->OwnerDoc()->GetDocShell());