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/LookAndFeel.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/dom/DragEvent.h"
52 #include "mozilla/dom/Event.h" // for Event
53 #include "mozilla/dom/File.h" // for input type=file
54 #include "mozilla/dom/FileList.h" // for input type=file
55 #include "mozilla/dom/LoadURIOptionsBinding.h"
56 #include "mozilla/PresShell.h"
57 #include "mozilla/TextEvents.h"
59 using namespace mozilla
;
60 using namespace mozilla::dom
;
62 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
63 // a |EventTarget| via the window root and chrome event handler.
64 static nsresult
GetDOMEventTarget(nsWebBrowser
* aInBrowser
,
65 EventTarget
** aTarget
) {
67 return NS_ERROR_INVALID_POINTER
;
70 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
71 aInBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
73 return NS_ERROR_FAILURE
;
76 auto* outerWindow
= nsPIDOMWindowOuter::From(domWindow
);
77 nsPIDOMWindowOuter
* rootWindow
= outerWindow
->GetPrivateRoot();
78 NS_ENSURE_TRUE(rootWindow
, NS_ERROR_FAILURE
);
79 nsCOMPtr
<EventTarget
> target
= rootWindow
->GetChromeEventHandler();
80 NS_ENSURE_TRUE(target
, NS_ERROR_FAILURE
);
81 target
.forget(aTarget
);
86 nsDocShellTreeOwner::nsDocShellTreeOwner()
87 : mWebBrowser(nullptr),
89 mPrimaryContentShell(nullptr),
90 mWebBrowserChrome(nullptr),
92 mOwnerRequestor(nullptr) {}
94 nsDocShellTreeOwner::~nsDocShellTreeOwner() { RemoveChromeListeners(); }
96 NS_IMPL_ADDREF(nsDocShellTreeOwner
)
97 NS_IMPL_RELEASE(nsDocShellTreeOwner
)
99 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner
)
100 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDocShellTreeOwner
)
101 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner
)
102 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
103 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
104 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
105 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener
)
106 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
109 // The class that listens to the chrome events and tells the embedding chrome to
110 // show tooltips, as appropriate. Handles registering itself with the DOM with
111 // AddChromeListeners() and removing itself with RemoveChromeListeners().
112 class ChromeTooltipListener final
: public nsIDOMEventListener
{
114 virtual ~ChromeTooltipListener();
119 ChromeTooltipListener(nsWebBrowser
* aInBrowser
,
120 nsIWebBrowserChrome
* aInChrome
);
122 NS_DECL_NSIDOMEVENTLISTENER
123 NS_IMETHOD
MouseMove(mozilla::dom::Event
* aMouseEvent
);
125 // Add/remove the relevant listeners, based on what interfaces the embedding
126 // chrome implements.
127 NS_IMETHOD
AddChromeListeners();
128 NS_IMETHOD
RemoveChromeListeners();
130 NS_IMETHOD
HideTooltip();
132 bool WebProgressShowedTooltip(nsIWebProgress
* aWebProgress
);
135 // pixel tolerance for mousemove event
136 static constexpr CSSIntCoord kTooltipMouseMoveTolerance
= 7;
138 NS_IMETHOD
AddTooltipListener();
139 NS_IMETHOD
RemoveTooltipListener();
141 NS_IMETHOD
ShowTooltip(int32_t aInXCoords
, int32_t aInYCoords
,
142 const nsAString
& aInTipText
,
143 const nsAString
& aDirText
);
144 nsITooltipTextProvider
* GetTooltipTextProvider();
146 nsWebBrowser
* mWebBrowser
;
147 nsCOMPtr
<mozilla::dom::EventTarget
> mEventTarget
;
148 nsCOMPtr
<nsITooltipTextProvider
> mTooltipTextProvider
;
150 // This must be a strong ref in order to make sure we can hide the tooltip if
151 // the window goes away while we're displaying one. If we don't hold a strong
152 // ref, the chrome might have been disposed of before we get a chance to tell
153 // it, and no one would ever tell us of that fact.
154 nsCOMPtr
<nsIWebBrowserChrome
> mWebBrowserChrome
;
156 bool mTooltipListenerInstalled
;
158 nsCOMPtr
<nsITimer
> mTooltipTimer
;
159 static void sTooltipCallback(nsITimer
* aTimer
, void* aListener
);
161 // Mouse coordinates for last mousemove event we saw
162 CSSIntPoint mMouseClientPoint
;
164 // Mouse coordinates for tooltip event
165 LayoutDeviceIntPoint mMouseScreenPoint
;
167 bool mShowingTooltip
;
169 bool mTooltipShownOnce
;
171 // The string of text that we last displayed.
172 nsString mLastShownTooltipText
;
174 nsWeakPtr mLastDocshell
;
176 // The node hovered over that fired the timer. This may turn into the node
177 // that triggered the tooltip, but only if the timer ever gets around to
178 // firing. This is a strong reference, because the tooltip content can be
179 // destroyed while we're waiting for the tooltip to pop up, and we need to
180 // detect that. It's set only when the tooltip timer is created and launched.
181 // The timer must either fire or be cancelled (or possibly released?), and we
182 // release this reference in each of those cases. So we don't leak.
183 nsCOMPtr
<nsINode
> mPossibleTooltipNode
;
186 //*****************************************************************************
187 // nsDocShellTreeOwner::nsIInterfaceRequestor
188 //*****************************************************************************
191 nsDocShellTreeOwner::GetInterface(const nsIID
& aIID
, void** aSink
) {
192 NS_ENSURE_ARG_POINTER(aSink
);
194 if (NS_SUCCEEDED(QueryInterface(aIID
, aSink
))) {
198 if (aIID
.Equals(NS_GET_IID(nsIWebBrowserChromeFocus
))) {
199 if (mWebBrowserChromeWeak
!= nullptr) {
200 return mWebBrowserChromeWeak
->QueryReferent(aIID
, aSink
);
202 return mOwnerWin
->QueryInterface(aIID
, aSink
);
205 if (aIID
.Equals(NS_GET_IID(nsIPrompt
))) {
206 nsCOMPtr
<nsIPrompt
> prompt
;
210 prompt
.forget(aSink
);
213 return NS_NOINTERFACE
;
216 if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
))) {
217 nsCOMPtr
<nsIAuthPrompt
> prompt
;
218 EnsureAuthPrompter();
219 prompt
= mAuthPrompter
;
221 prompt
.forget(aSink
);
224 return NS_NOINTERFACE
;
227 nsCOMPtr
<nsIInterfaceRequestor
> req
= GetOwnerRequestor();
229 return req
->GetInterface(aIID
, aSink
);
232 return NS_NOINTERFACE
;
235 //*****************************************************************************
236 // nsDocShellTreeOwner::nsIDocShellTreeOwner
237 //*****************************************************************************
239 void nsDocShellTreeOwner::EnsurePrompter() {
244 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
245 if (wwatch
&& mWebBrowser
) {
246 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
247 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
249 wwatch
->GetNewPrompter(domWindow
, getter_AddRefs(mPrompter
));
254 void nsDocShellTreeOwner::EnsureAuthPrompter() {
259 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
260 if (wwatch
&& mWebBrowser
) {
261 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
262 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
264 wwatch
->GetNewAuthPrompter(domWindow
, getter_AddRefs(mAuthPrompter
));
269 void nsDocShellTreeOwner::AddToWatcher() {
271 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
272 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
274 nsCOMPtr
<nsPIWindowWatcher
> wwatch(
275 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
277 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
278 if (webBrowserChrome
) {
279 wwatch
->AddWindow(domWindow
, webBrowserChrome
);
286 void nsDocShellTreeOwner::RemoveFromWatcher() {
288 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
289 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
291 nsCOMPtr
<nsPIWindowWatcher
> wwatch(
292 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
294 wwatch
->RemoveWindow(domWindow
);
300 void nsDocShellTreeOwner::EnsureContentTreeOwner() {
301 if (mContentTreeOwner
) {
305 mContentTreeOwner
= new nsDocShellTreeOwner();
306 nsCOMPtr
<nsIWebBrowserChrome
> browserChrome
= GetWebBrowserChrome();
308 mContentTreeOwner
->SetWebBrowserChrome(browserChrome
);
312 mContentTreeOwner
->WebBrowser(mWebBrowser
);
317 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem
* aContentShell
,
319 if (mTreeOwner
) return mTreeOwner
->ContentShellAdded(aContentShell
, aPrimary
);
321 EnsureContentTreeOwner();
322 aContentShell
->SetTreeOwner(mContentTreeOwner
);
325 mPrimaryContentShell
= aContentShell
;
326 mPrimaryRemoteTab
= nullptr;
332 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem
* aContentShell
) {
334 return mTreeOwner
->ContentShellRemoved(aContentShell
);
337 if (mPrimaryContentShell
== aContentShell
) {
338 mPrimaryContentShell
= nullptr;
345 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem
** aShell
) {
346 NS_ENSURE_ARG_POINTER(aShell
);
349 return mTreeOwner
->GetPrimaryContentShell(aShell
);
352 nsCOMPtr
<nsIDocShellTreeItem
> shell
;
353 if (!mPrimaryRemoteTab
) {
355 mPrimaryContentShell
? mPrimaryContentShell
: mWebBrowser
->mDocShell
;
357 shell
.forget(aShell
);
363 nsDocShellTreeOwner::RemoteTabAdded(nsIRemoteTab
* aTab
, bool aPrimary
) {
365 return mTreeOwner
->RemoteTabAdded(aTab
, aPrimary
);
369 mPrimaryRemoteTab
= aTab
;
370 mPrimaryContentShell
= nullptr;
371 } else if (mPrimaryRemoteTab
== aTab
) {
372 mPrimaryRemoteTab
= nullptr;
379 nsDocShellTreeOwner::RemoteTabRemoved(nsIRemoteTab
* aTab
) {
381 return mTreeOwner
->RemoteTabRemoved(aTab
);
384 if (aTab
== mPrimaryRemoteTab
) {
385 mPrimaryRemoteTab
= nullptr;
392 nsDocShellTreeOwner::GetPrimaryRemoteTab(nsIRemoteTab
** aTab
) {
394 return mTreeOwner
->GetPrimaryRemoteTab(aTab
);
397 nsCOMPtr
<nsIRemoteTab
> tab
= mPrimaryRemoteTab
;
403 nsDocShellTreeOwner::GetPrimaryContentBrowsingContext(
404 mozilla::dom::BrowsingContext
** aBc
) {
406 return mTreeOwner
->GetPrimaryContentBrowsingContext(aBc
);
408 if (mPrimaryRemoteTab
) {
409 return mPrimaryRemoteTab
->GetBrowsingContext(aBc
);
411 if (mPrimaryContentShell
) {
412 return mPrimaryContentShell
->GetBrowsingContextXPCOM(aBc
);
414 if (mWebBrowser
->mDocShell
) {
415 return mWebBrowser
->mDocShell
->GetBrowsingContextXPCOM(aBc
);
422 nsDocShellTreeOwner::GetPrimaryContentSize(int32_t* aWidth
, int32_t* aHeight
) {
423 return NS_ERROR_NOT_IMPLEMENTED
;
427 nsDocShellTreeOwner::SetPrimaryContentSize(int32_t aWidth
, int32_t aHeight
) {
428 return NS_ERROR_NOT_IMPLEMENTED
;
432 nsDocShellTreeOwner::GetRootShellSize(int32_t* aWidth
, int32_t* aHeight
) {
433 return NS_ERROR_NOT_IMPLEMENTED
;
437 nsDocShellTreeOwner::SetRootShellSize(int32_t aWidth
, int32_t aHeight
) {
438 return NS_ERROR_NOT_IMPLEMENTED
;
442 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem
* aShellItem
, int32_t aCX
,
444 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
446 NS_ENSURE_STATE(mTreeOwner
|| webBrowserChrome
);
448 if (nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
= mTreeOwner
) {
449 return treeOwner
->SizeShellTo(aShellItem
, aCX
, aCY
);
452 if (aShellItem
== mWebBrowser
->mDocShell
) {
453 nsCOMPtr
<nsIBrowserChild
> browserChild
=
454 do_QueryInterface(webBrowserChrome
);
456 // The XUL window to resize is in the parent process, but there we
457 // won't be able to get the size of aShellItem. We can ask the parent
458 // process to change our size instead.
459 nsCOMPtr
<nsIBaseWindow
> shellAsWin(do_QueryInterface(aShellItem
));
460 NS_ENSURE_TRUE(shellAsWin
, NS_ERROR_FAILURE
);
462 LayoutDeviceIntSize shellSize
;
463 shellAsWin
->GetSize(&shellSize
.width
, &shellSize
.height
);
464 LayoutDeviceIntSize deltaSize
= LayoutDeviceIntSize(aCX
, aCY
) - shellSize
;
466 LayoutDeviceIntSize currentSize
;
467 GetSize(¤tSize
.width
, ¤tSize
.height
);
469 LayoutDeviceIntSize newSize
= currentSize
+ deltaSize
;
470 return SetSize(newSize
.width
, newSize
.height
, true);
472 // XXX: this is weird, but we used to call a method here
473 // (webBrowserChrome->SizeBrowserTo()) whose implementations all failed
475 return NS_ERROR_NOT_IMPLEMENTED
;
478 MOZ_ASSERT_UNREACHABLE("This is unimplemented, API should be cleaned up");
479 return NS_ERROR_NOT_IMPLEMENTED
;
483 nsDocShellTreeOwner::SetPersistence(bool aPersistPosition
, bool aPersistSize
,
484 bool aPersistSizeMode
) {
485 return NS_ERROR_NOT_IMPLEMENTED
;
489 nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition
, bool* aPersistSize
,
490 bool* aPersistSizeMode
) {
491 return NS_ERROR_NOT_IMPLEMENTED
;
495 nsDocShellTreeOwner::GetTabCount(uint32_t* aResult
) {
497 return mTreeOwner
->GetTabCount(aResult
);
505 nsDocShellTreeOwner::GetHasPrimaryContent(bool* aResult
) {
506 *aResult
= mPrimaryRemoteTab
|| mPrimaryContentShell
;
510 //*****************************************************************************
511 // nsDocShellTreeOwner::nsIBaseWindow
512 //*****************************************************************************
515 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow
,
516 nsIWidget
* aParentWidget
, int32_t aX
,
517 int32_t aY
, int32_t aCX
, int32_t aCY
) {
518 return NS_ERROR_NULL_POINTER
;
522 nsDocShellTreeOwner::Destroy() {
523 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
524 if (webBrowserChrome
) {
525 // XXX: this is weird, but we used to call a method here
526 // (webBrowserChrome->DestroyBrowserWindow()) whose implementations all
527 // failed like this, so...
528 return NS_ERROR_NOT_IMPLEMENTED
;
531 return NS_ERROR_NULL_POINTER
;
534 double nsDocShellTreeOwner::GetWidgetCSSToDeviceScale() {
535 return mWebBrowser
? mWebBrowser
->GetWidgetCSSToDeviceScale() : 1.0;
539 nsDocShellTreeOwner::GetDevicePixelsPerDesktopPixel(double* aScale
) {
541 return mWebBrowser
->GetDevicePixelsPerDesktopPixel(aScale
);
549 nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX
, int32_t aY
) {
551 nsresult rv
= mWebBrowser
->SetPositionDesktopPix(aX
, aY
);
552 NS_ENSURE_SUCCESS(rv
, rv
);
556 GetDevicePixelsPerDesktopPixel(&scale
);
557 return SetPosition(NSToIntRound(aX
* scale
), NSToIntRound(aY
* scale
));
561 nsDocShellTreeOwner::SetPosition(int32_t aX
, int32_t aY
) {
562 return SetDimensions(
563 {DimensionKind::Outer
, Some(aX
), Some(aY
), Nothing(), Nothing()});
567 nsDocShellTreeOwner::GetPosition(int32_t* aX
, int32_t* aY
) {
568 return GetDimensions(DimensionKind::Outer
, aX
, aY
, nullptr, nullptr);
572 nsDocShellTreeOwner::SetSize(int32_t aCX
, int32_t aCY
, bool aRepaint
) {
573 return SetDimensions(
574 {DimensionKind::Outer
, Nothing(), Nothing(), Some(aCX
), Some(aCY
)});
578 nsDocShellTreeOwner::GetSize(int32_t* aCX
, int32_t* aCY
) {
579 return GetDimensions(DimensionKind::Outer
, nullptr, nullptr, aCX
, aCY
);
583 nsDocShellTreeOwner::SetPositionAndSize(int32_t aX
, int32_t aY
, int32_t aCX
,
584 int32_t aCY
, uint32_t aFlags
) {
585 return SetDimensions(
586 {DimensionKind::Outer
, Some(aX
), Some(aY
), Some(aCX
), Some(aCY
)});
590 nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX
, int32_t* aY
, int32_t* aCX
,
592 return GetDimensions(DimensionKind::Outer
, aX
, aY
, aCX
, aCY
);
596 nsDocShellTreeOwner::SetDimensions(DimensionRequest
&& aRequest
) {
597 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
599 return ownerWin
->SetDimensions(std::move(aRequest
));
602 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
603 NS_ENSURE_STATE(webBrowserChrome
);
604 return webBrowserChrome
->SetDimensions(std::move(aRequest
));
608 nsDocShellTreeOwner::GetDimensions(DimensionKind aDimensionKind
, int32_t* aX
,
609 int32_t* aY
, int32_t* aCX
, int32_t* aCY
) {
610 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
612 return ownerWin
->GetDimensions(aDimensionKind
, aX
, aY
, aCX
, aCY
);
615 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
616 NS_ENSURE_STATE(webBrowserChrome
);
617 return webBrowserChrome
->GetDimensions(aDimensionKind
, aX
, aY
, aCX
, aCY
);
621 nsDocShellTreeOwner::Repaint(bool aForce
) { return NS_ERROR_NULL_POINTER
; }
624 nsDocShellTreeOwner::GetParentWidget(nsIWidget
** aParentWidget
) {
625 return NS_ERROR_NULL_POINTER
;
629 nsDocShellTreeOwner::SetParentWidget(nsIWidget
* aParentWidget
) {
630 return NS_ERROR_NULL_POINTER
;
634 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow
* aParentNativeWindow
) {
635 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
637 return ownerWin
->GetParentNativeWindow(aParentNativeWindow
);
639 return NS_ERROR_NULL_POINTER
;
643 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow
) {
644 return NS_ERROR_NULL_POINTER
;
648 nsDocShellTreeOwner::GetNativeHandle(nsAString
& aNativeHandle
) {
649 // the nativeHandle should be accessed from nsIAppWindow
650 return NS_ERROR_NOT_IMPLEMENTED
;
654 nsDocShellTreeOwner::GetVisibility(bool* aVisibility
) {
655 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
657 return ownerWin
->GetVisibility(aVisibility
);
660 return NS_ERROR_NOT_IMPLEMENTED
;
664 nsDocShellTreeOwner::SetVisibility(bool aVisibility
) {
665 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
667 return ownerWin
->SetVisibility(aVisibility
);
669 return NS_ERROR_NULL_POINTER
;
673 nsDocShellTreeOwner::GetEnabled(bool* aEnabled
) {
674 NS_ENSURE_ARG_POINTER(aEnabled
);
676 return NS_ERROR_NOT_IMPLEMENTED
;
680 nsDocShellTreeOwner::SetEnabled(bool aEnabled
) {
681 return NS_ERROR_NOT_IMPLEMENTED
;
685 nsDocShellTreeOwner::GetMainWidget(nsIWidget
** aMainWidget
) {
686 return NS_ERROR_NULL_POINTER
;
690 nsDocShellTreeOwner::GetTitle(nsAString
& aTitle
) {
691 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
693 return ownerWin
->GetTitle(aTitle
);
695 return NS_ERROR_NULL_POINTER
;
699 nsDocShellTreeOwner::SetTitle(const nsAString
& aTitle
) {
700 nsCOMPtr
<nsIBaseWindow
> ownerWin
= GetOwnerWin();
702 return ownerWin
->SetTitle(aTitle
);
704 return NS_ERROR_NULL_POINTER
;
707 //*****************************************************************************
708 // nsDocShellTreeOwner::nsIWebProgressListener
709 //*****************************************************************************
712 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress
* aProgress
,
713 nsIRequest
* aRequest
,
714 int32_t aCurSelfProgress
,
715 int32_t aMaxSelfProgress
,
716 int32_t aCurTotalProgress
,
717 int32_t aMaxTotalProgress
) {
718 // In the absence of DOM document creation event, this method is the
719 // most convenient place to install the mouse listener on the
721 return AddChromeListeners();
725 nsDocShellTreeOwner::OnStateChange(nsIWebProgress
* aProgress
,
726 nsIRequest
* aRequest
,
727 uint32_t aProgressStateFlags
,
733 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress
* aWebProgress
,
734 nsIRequest
* aRequest
, nsIURI
* aURI
,
736 if (mChromeTooltipListener
&& aWebProgress
&&
737 !(aFlags
& nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT
) &&
738 mChromeTooltipListener
->WebProgressShowedTooltip(aWebProgress
)) {
739 mChromeTooltipListener
->HideTooltip();
745 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress
* aWebProgress
,
746 nsIRequest
* aRequest
, nsresult aStatus
,
747 const char16_t
* aMessage
) {
752 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress
* aWebProgress
,
753 nsIRequest
* aRequest
, uint32_t aState
) {
758 nsDocShellTreeOwner::OnContentBlockingEvent(nsIWebProgress
* aWebProgress
,
759 nsIRequest
* aRequest
,
764 //*****************************************************************************
765 // nsDocShellTreeOwner: Accessors
766 //*****************************************************************************
768 void nsDocShellTreeOwner::WebBrowser(nsWebBrowser
* aWebBrowser
) {
770 RemoveChromeListeners();
772 if (aWebBrowser
!= mWebBrowser
) {
774 mAuthPrompter
= nullptr;
777 mWebBrowser
= aWebBrowser
;
779 if (mContentTreeOwner
) {
780 mContentTreeOwner
->WebBrowser(aWebBrowser
);
782 mContentTreeOwner
= nullptr;
787 nsWebBrowser
* nsDocShellTreeOwner::WebBrowser() { return mWebBrowser
; }
790 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
) {
792 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome(do_GetInterface(aTreeOwner
));
793 NS_ENSURE_TRUE(webBrowserChrome
, NS_ERROR_INVALID_ARG
);
794 NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome
),
795 NS_ERROR_INVALID_ARG
);
796 mTreeOwner
= aTreeOwner
;
798 mTreeOwner
= nullptr;
799 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
800 if (!webBrowserChrome
) {
801 NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE
);
809 nsDocShellTreeOwner::SetWebBrowserChrome(
810 nsIWebBrowserChrome
* aWebBrowserChrome
) {
811 if (!aWebBrowserChrome
) {
812 mWebBrowserChrome
= nullptr;
814 mOwnerRequestor
= nullptr;
815 mWebBrowserChromeWeak
= nullptr;
817 nsCOMPtr
<nsISupportsWeakReference
> supportsweak
=
818 do_QueryInterface(aWebBrowserChrome
);
820 supportsweak
->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak
));
822 nsCOMPtr
<nsIBaseWindow
> ownerWin(do_QueryInterface(aWebBrowserChrome
));
823 nsCOMPtr
<nsIInterfaceRequestor
> requestor(
824 do_QueryInterface(aWebBrowserChrome
));
826 // it's ok for ownerWin or requestor to be null.
827 mWebBrowserChrome
= aWebBrowserChrome
;
828 mOwnerWin
= ownerWin
;
829 mOwnerRequestor
= requestor
;
833 if (mContentTreeOwner
) {
834 mContentTreeOwner
->SetWebBrowserChrome(aWebBrowserChrome
);
840 // Hook up things to the chrome like context menus and tooltips, if the chrome
841 // has implemented the right interfaces.
843 nsDocShellTreeOwner::AddChromeListeners() {
846 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
847 if (!webBrowserChrome
) {
848 return NS_ERROR_FAILURE
;
852 if (!mChromeTooltipListener
) {
853 nsCOMPtr
<nsITooltipListener
> tooltipListener(
854 do_QueryInterface(webBrowserChrome
));
855 if (tooltipListener
) {
856 mChromeTooltipListener
=
857 new ChromeTooltipListener(mWebBrowser
, webBrowserChrome
);
858 rv
= mChromeTooltipListener
->AddChromeListeners();
862 nsCOMPtr
<EventTarget
> target
;
863 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(target
));
865 // register dragover and drop event listeners with the listener manager
866 MOZ_ASSERT(target
, "how does this happen? (see bug 1659758)");
868 if (EventListenerManager
* elmP
= target
->GetOrCreateListenerManager()) {
869 elmP
->AddEventListenerByType(this, u
"dragover"_ns
,
870 TrustedEventsAtSystemGroupBubble());
871 elmP
->AddEventListenerByType(this, u
"drop"_ns
,
872 TrustedEventsAtSystemGroupBubble());
880 nsDocShellTreeOwner::RemoveChromeListeners() {
881 if (mChromeTooltipListener
) {
882 mChromeTooltipListener
->RemoveChromeListeners();
883 mChromeTooltipListener
= nullptr;
886 nsCOMPtr
<EventTarget
> piTarget
;
887 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(piTarget
));
892 EventListenerManager
* elmP
= piTarget
->GetOrCreateListenerManager();
894 elmP
->RemoveEventListenerByType(this, u
"dragover"_ns
,
895 TrustedEventsAtSystemGroupBubble());
896 elmP
->RemoveEventListenerByType(this, u
"drop"_ns
,
897 TrustedEventsAtSystemGroupBubble());
904 nsDocShellTreeOwner::HandleEvent(Event
* aEvent
) {
905 DragEvent
* dragEvent
= aEvent
? aEvent
->AsDragEvent() : nullptr;
906 if (NS_WARN_IF(!dragEvent
)) {
907 return NS_ERROR_INVALID_ARG
;
910 if (dragEvent
->DefaultPrevented()) {
914 nsCOMPtr
<nsIDroppedLinkHandler
> handler
=
915 do_GetService("@mozilla.org/content/dropped-link-handler;1");
920 nsAutoString eventType
;
921 aEvent
->GetType(eventType
);
922 if (eventType
.EqualsLiteral("dragover")) {
923 bool canDropLink
= false;
924 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
926 aEvent
->PreventDefault();
928 } else if (eventType
.EqualsLiteral("drop")) {
929 nsIWebNavigation
* webnav
= static_cast<nsIWebNavigation
*>(mWebBrowser
);
931 // The page might have cancelled the dragover event itself, so check to
932 // make sure that the link can be dropped first.
933 bool canDropLink
= false;
934 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
939 nsTArray
<RefPtr
<nsIDroppedLinkItem
>> links
;
940 if (webnav
&& NS_SUCCEEDED(handler
->DropLinks(dragEvent
, true, links
))) {
941 if (links
.Length() >= 1) {
942 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
943 handler
->GetTriggeringPrincipal(dragEvent
,
944 getter_AddRefs(triggeringPrincipal
));
945 if (triggeringPrincipal
) {
946 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
=
947 GetWebBrowserChrome();
948 if (webBrowserChrome
) {
949 nsCOMPtr
<nsIBrowserChild
> browserChild
=
950 do_QueryInterface(webBrowserChrome
);
952 nsresult rv
= browserChild
->RemoteDropLinks(links
);
957 if (NS_SUCCEEDED(links
[0]->GetUrl(url
))) {
958 if (!url
.IsEmpty()) {
960 MOZ_ASSERT(triggeringPrincipal
,
961 "nsDocShellTreeOwner::HandleEvent: Need a valid "
962 "triggeringPrincipal");
964 LoadURIOptions loadURIOptions
;
965 loadURIOptions
.mTriggeringPrincipal
= triggeringPrincipal
;
966 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
967 handler
->GetCsp(dragEvent
, getter_AddRefs(csp
));
968 loadURIOptions
.mCsp
= csp
;
969 webnav
->FixupAndLoadURIString(url
, loadURIOptions
);
975 aEvent
->StopPropagation();
976 aEvent
->PreventDefault();
983 already_AddRefed
<nsIWebBrowserChrome
>
984 nsDocShellTreeOwner::GetWebBrowserChrome() {
985 nsCOMPtr
<nsIWebBrowserChrome
> chrome
;
986 if (mWebBrowserChromeWeak
) {
987 chrome
= do_QueryReferent(mWebBrowserChromeWeak
);
988 } else if (mWebBrowserChrome
) {
989 chrome
= mWebBrowserChrome
;
991 return chrome
.forget();
994 already_AddRefed
<nsIBaseWindow
> nsDocShellTreeOwner::GetOwnerWin() {
995 nsCOMPtr
<nsIBaseWindow
> win
;
996 if (mWebBrowserChromeWeak
) {
997 win
= do_QueryReferent(mWebBrowserChromeWeak
);
998 } else if (mOwnerWin
) {
1001 return win
.forget();
1004 already_AddRefed
<nsIInterfaceRequestor
>
1005 nsDocShellTreeOwner::GetOwnerRequestor() {
1006 nsCOMPtr
<nsIInterfaceRequestor
> req
;
1007 if (mWebBrowserChromeWeak
) {
1008 req
= do_QueryReferent(mWebBrowserChromeWeak
);
1009 } else if (mOwnerRequestor
) {
1010 req
= mOwnerRequestor
;
1012 return req
.forget();
1015 NS_IMPL_ISUPPORTS(ChromeTooltipListener
, nsIDOMEventListener
)
1017 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser
* aInBrowser
,
1018 nsIWebBrowserChrome
* aInChrome
)
1019 : mWebBrowser(aInBrowser
),
1020 mWebBrowserChrome(aInChrome
),
1021 mTooltipListenerInstalled(false),
1022 mShowingTooltip(false),
1023 mTooltipShownOnce(false) {}
1025 ChromeTooltipListener::~ChromeTooltipListener() {}
1027 nsITooltipTextProvider
* ChromeTooltipListener::GetTooltipTextProvider() {
1028 if (!mTooltipTextProvider
) {
1029 mTooltipTextProvider
= do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID
);
1032 if (!mTooltipTextProvider
) {
1033 mTooltipTextProvider
=
1034 do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID
);
1037 return mTooltipTextProvider
;
1040 // Hook up things to the chrome like context menus and tooltips, if the chrome
1041 // has implemented the right interfaces.
1043 ChromeTooltipListener::AddChromeListeners() {
1044 if (!mEventTarget
) {
1045 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(mEventTarget
));
1048 // Register the appropriate events for tooltips, but only if
1049 // the embedding chrome cares.
1050 nsresult rv
= NS_OK
;
1051 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1052 do_QueryInterface(mWebBrowserChrome
));
1053 if (tooltipListener
&& !mTooltipListenerInstalled
) {
1054 rv
= AddTooltipListener();
1055 if (NS_FAILED(rv
)) {
1063 // Subscribe to the events that will allow us to track tooltips. We need "mouse"
1064 // for mouseExit, "mouse motion" for mouseMove, and "key" for keyDown. As we
1065 // add the listeners, keep track of how many succeed so we can clean up
1066 // correctly in Release().
1068 ChromeTooltipListener::AddTooltipListener() {
1070 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"keydown"_ns
, this, false,
1072 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousedown"_ns
, this, false,
1074 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mouseout"_ns
, this, false,
1076 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousemove"_ns
, this, false,
1079 mTooltipListenerInstalled
= true;
1085 // Unsubscribe from the various things we've hooked up to the window root.
1087 ChromeTooltipListener::RemoveChromeListeners() {
1090 if (mTooltipListenerInstalled
) {
1091 RemoveTooltipListener();
1094 mEventTarget
= nullptr;
1096 // it really doesn't matter if these fail...
1100 // Unsubscribe from all the various tooltip events that we were listening to.
1102 ChromeTooltipListener::RemoveTooltipListener() {
1104 mEventTarget
->RemoveSystemEventListener(u
"keydown"_ns
, this, false);
1105 mEventTarget
->RemoveSystemEventListener(u
"mousedown"_ns
, this, false);
1106 mEventTarget
->RemoveSystemEventListener(u
"mouseout"_ns
, this, false);
1107 mEventTarget
->RemoveSystemEventListener(u
"mousemove"_ns
, this, false);
1108 mTooltipListenerInstalled
= false;
1115 ChromeTooltipListener::HandleEvent(Event
* aEvent
) {
1116 nsAutoString eventType
;
1117 aEvent
->GetType(eventType
);
1119 if (eventType
.EqualsLiteral("mousedown")) {
1120 return HideTooltip();
1121 } else if (eventType
.EqualsLiteral("keydown")) {
1122 WidgetKeyboardEvent
* keyEvent
= aEvent
->WidgetEventPtr()->AsKeyboardEvent();
1123 if (nsXULTooltipListener::KeyEventHidesTooltip(*keyEvent
)) {
1124 return HideTooltip();
1127 } else if (eventType
.EqualsLiteral("mouseout")) {
1128 // Reset flag so that tooltip will display on the next MouseMove
1129 mTooltipShownOnce
= false;
1130 return HideTooltip();
1131 } else if (eventType
.EqualsLiteral("mousemove")) {
1132 return MouseMove(aEvent
);
1135 NS_ERROR("Unexpected event type");
1139 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If
1140 // the timer fires, we cache the node in |mPossibleTooltipNode|.
1141 nsresult
ChromeTooltipListener::MouseMove(Event
* aMouseEvent
) {
1142 if (!nsXULTooltipListener::ShowTooltips()) {
1146 MouseEvent
* mouseEvent
= aMouseEvent
->AsMouseEvent();
1151 // stash the coordinates of the event so that we can still get back to it from
1152 // within the timer callback. On win32, we'll get a MouseMove event even when
1153 // a popup goes away -- even when the mouse doesn't change position! To get
1154 // around this, we make sure the mouse has really moved before proceeding.
1155 CSSIntPoint newMouseClientPoint
= mouseEvent
->ClientPoint();
1156 if (mMouseClientPoint
== newMouseClientPoint
) {
1160 // Filter out minor mouse movements.
1161 if (mShowingTooltip
&&
1162 (abs(mMouseClientPoint
.x
- newMouseClientPoint
.x
) <=
1163 kTooltipMouseMoveTolerance
) &&
1164 (abs(mMouseClientPoint
.y
- newMouseClientPoint
.y
) <=
1165 kTooltipMouseMoveTolerance
)) {
1169 mMouseClientPoint
= newMouseClientPoint
;
1170 mMouseScreenPoint
= mouseEvent
->ScreenPointLayoutDevicePix();
1172 if (mTooltipTimer
) {
1173 mTooltipTimer
->Cancel();
1174 mTooltipTimer
= nullptr;
1177 if (!mShowingTooltip
) {
1178 nsIEventTarget
* target
= nullptr;
1179 if (nsCOMPtr
<EventTarget
> eventTarget
= aMouseEvent
->GetComposedTarget()) {
1180 mPossibleTooltipNode
= nsINode::FromEventTarget(eventTarget
);
1181 nsCOMPtr
<nsIGlobalObject
> global(eventTarget
->GetOwnerGlobal());
1183 target
= global
->EventTargetFor(TaskCategory::UI
);
1187 if (mPossibleTooltipNode
) {
1188 nsresult rv
= NS_NewTimerWithFuncCallback(
1189 getter_AddRefs(mTooltipTimer
), sTooltipCallback
, this,
1190 LookAndFeel::GetInt(LookAndFeel::IntID::TooltipDelay
, 500),
1191 nsITimer::TYPE_ONE_SHOT
, "ChromeTooltipListener::MouseMove", target
);
1192 if (NS_FAILED(rv
)) {
1193 mPossibleTooltipNode
= nullptr;
1194 NS_WARNING("Could not create a timer for tooltip tracking");
1198 mTooltipShownOnce
= true;
1199 return HideTooltip();
1205 // Tell the registered chrome that they should show the tooltip.
1207 ChromeTooltipListener::ShowTooltip(int32_t aInXCoords
, int32_t aInYCoords
,
1208 const nsAString
& aInTipText
,
1209 const nsAString
& aTipDir
) {
1210 nsresult rv
= NS_OK
;
1212 // do the work to call the client
1213 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1214 do_QueryInterface(mWebBrowserChrome
));
1215 if (tooltipListener
) {
1216 rv
= tooltipListener
->OnShowTooltip(aInXCoords
, aInYCoords
, aInTipText
,
1218 if (NS_SUCCEEDED(rv
)) {
1219 mShowingTooltip
= true;
1226 // Tell the registered chrome that they should rollup the tooltip
1227 // NOTE: This routine is safe to call even if the popup is already closed.
1229 ChromeTooltipListener::HideTooltip() {
1230 nsresult rv
= NS_OK
;
1232 // shut down the relevant timers
1233 if (mTooltipTimer
) {
1234 mTooltipTimer
->Cancel();
1235 mTooltipTimer
= nullptr;
1236 // release tooltip target
1237 mPossibleTooltipNode
= nullptr;
1238 mLastDocshell
= nullptr;
1241 // if we're showing the tip, tell the chrome to hide it
1242 if (mShowingTooltip
) {
1243 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1244 do_QueryInterface(mWebBrowserChrome
));
1245 if (tooltipListener
) {
1246 rv
= tooltipListener
->OnHideTooltip();
1247 if (NS_SUCCEEDED(rv
)) {
1248 mShowingTooltip
= false;
1256 bool ChromeTooltipListener::WebProgressShowedTooltip(
1257 nsIWebProgress
* aWebProgress
) {
1258 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryInterface(aWebProgress
);
1259 nsCOMPtr
<nsIDocShell
> lastUsed
= do_QueryReferent(mLastDocshell
);
1261 if (lastUsed
== docshell
) {
1264 // We can't use the docshell hierarchy here, because when the parent
1265 // docshell is navigated, the child docshell is disconnected (ie its
1266 // references to the parent are nulled out) despite it still being
1267 // alive here. So we use the document hierarchy instead:
1268 Document
* document
= lastUsed
->GetDocument();
1270 document
= document
->GetInProcessParentDocument();
1275 lastUsed
= document
->GetDocShell();
1280 // A timer callback, fired when the mouse has hovered inside of a frame for the
1281 // appropriate amount of time. Getting to this point means that we should show
1282 // the tooltip, but only after we determine there is an appropriate TITLE
1285 // This relies on certain things being cached into the |aChromeTooltipListener|
1286 // object passed to us by the timer:
1287 // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1288 // -- the dom node the user hovered over (mPossibleTooltipNode)
1289 void ChromeTooltipListener::sTooltipCallback(nsITimer
* aTimer
,
1290 void* aChromeTooltipListener
) {
1291 auto* self
= static_cast<ChromeTooltipListener
*>(aChromeTooltipListener
);
1292 if (!self
|| !self
->mPossibleTooltipNode
) {
1295 // release tooltip target once done, no matter what we do here.
1296 auto cleanup
= MakeScopeExit([&] { self
->mPossibleTooltipNode
= nullptr; });
1297 if (!self
->mPossibleTooltipNode
->IsInComposedDoc()) {
1300 // Check that the document or its ancestors haven't been replaced.
1302 Document
* doc
= self
->mPossibleTooltipNode
->OwnerDoc();
1304 if (!doc
->IsCurrentActiveDocument()) {
1307 doc
= doc
->GetInProcessParentDocument();
1311 nsCOMPtr
<nsIDocShell
> docShell
=
1312 do_GetInterface(static_cast<nsIWebBrowser
*>(self
->mWebBrowser
));
1313 if (!docShell
|| !docShell
->GetBrowsingContext()->IsActive()) {
1317 // if there is text associated with the node, show the tip and fire
1318 // off a timer to auto-hide it.
1319 nsITooltipTextProvider
* tooltipProvider
= self
->GetTooltipTextProvider();
1320 if (!tooltipProvider
) {
1323 nsString tooltipText
;
1324 nsString directionText
;
1325 bool textFound
= false;
1326 tooltipProvider
->GetNodeText(self
->mPossibleTooltipNode
,
1327 getter_Copies(tooltipText
),
1328 getter_Copies(directionText
), &textFound
);
1330 if (textFound
&& (!self
->mTooltipShownOnce
||
1331 tooltipText
!= self
->mLastShownTooltipText
)) {
1332 // ShowTooltip expects screen-relative position.
1333 self
->ShowTooltip(self
->mMouseScreenPoint
.x
, self
->mMouseScreenPoint
.y
,
1334 tooltipText
, directionText
);
1335 self
->mLastShownTooltipText
= std::move(tooltipText
);
1336 self
->mLastDocshell
= do_GetWeakReference(
1337 self
->mPossibleTooltipNode
->OwnerDoc()->GetDocShell());