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();
927 WidgetDragEvent
* asWidgetDropEvent
=
928 dragEvent
->WidgetEventPtr()->AsDragEvent();
929 asWidgetDropEvent
->UpdateDefaultPreventedOnContent(
930 asWidgetDropEvent
->mCurrentTarget
);
932 } else if (eventType
.EqualsLiteral("drop")) {
933 nsCOMPtr
<nsIWebNavigation
> webnav
=
934 static_cast<nsIWebNavigation
*>(mWebBrowser
);
936 // The page might have cancelled the dragover event itself, so check to
937 // make sure that the link can be dropped first.
938 bool canDropLink
= false;
939 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
944 nsTArray
<RefPtr
<nsIDroppedLinkItem
>> links
;
945 if (webnav
&& NS_SUCCEEDED(handler
->DropLinks(dragEvent
, true, links
))) {
946 if (links
.Length() >= 1) {
947 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
;
948 handler
->GetTriggeringPrincipal(dragEvent
,
949 getter_AddRefs(triggeringPrincipal
));
950 if (triggeringPrincipal
) {
951 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
=
952 GetWebBrowserChrome();
953 if (webBrowserChrome
) {
954 nsCOMPtr
<nsIBrowserChild
> browserChild
=
955 do_QueryInterface(webBrowserChrome
);
957 nsresult rv
= browserChild
->RemoteDropLinks(links
);
962 if (NS_SUCCEEDED(links
[0]->GetUrl(url
))) {
963 if (!url
.IsEmpty()) {
965 MOZ_ASSERT(triggeringPrincipal
,
966 "nsDocShellTreeOwner::HandleEvent: Need a valid "
967 "triggeringPrincipal");
969 LoadURIOptions loadURIOptions
;
970 loadURIOptions
.mTriggeringPrincipal
= triggeringPrincipal
;
971 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
972 handler
->GetCsp(dragEvent
, getter_AddRefs(csp
));
973 loadURIOptions
.mCsp
= csp
;
974 webnav
->FixupAndLoadURIString(url
, loadURIOptions
);
980 aEvent
->StopPropagation();
981 aEvent
->PreventDefault();
982 WidgetDragEvent
* asWidgetDropEvent
=
983 dragEvent
->WidgetEventPtr()->AsDragEvent();
984 asWidgetDropEvent
->UpdateDefaultPreventedOnContent(
985 asWidgetDropEvent
->mCurrentTarget
);
992 already_AddRefed
<nsIWebBrowserChrome
>
993 nsDocShellTreeOwner::GetWebBrowserChrome() {
994 nsCOMPtr
<nsIWebBrowserChrome
> chrome
;
995 if (mWebBrowserChromeWeak
) {
996 chrome
= do_QueryReferent(mWebBrowserChromeWeak
);
997 } else if (mWebBrowserChrome
) {
998 chrome
= mWebBrowserChrome
;
1000 return chrome
.forget();
1003 already_AddRefed
<nsIBaseWindow
> nsDocShellTreeOwner::GetOwnerWin() {
1004 nsCOMPtr
<nsIBaseWindow
> win
;
1005 if (mWebBrowserChromeWeak
) {
1006 win
= do_QueryReferent(mWebBrowserChromeWeak
);
1007 } else if (mOwnerWin
) {
1010 return win
.forget();
1013 already_AddRefed
<nsIInterfaceRequestor
>
1014 nsDocShellTreeOwner::GetOwnerRequestor() {
1015 nsCOMPtr
<nsIInterfaceRequestor
> req
;
1016 if (mWebBrowserChromeWeak
) {
1017 req
= do_QueryReferent(mWebBrowserChromeWeak
);
1018 } else if (mOwnerRequestor
) {
1019 req
= mOwnerRequestor
;
1021 return req
.forget();
1024 NS_IMPL_ISUPPORTS(ChromeTooltipListener
, nsIDOMEventListener
)
1026 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser
* aInBrowser
,
1027 nsIWebBrowserChrome
* aInChrome
)
1028 : mWebBrowser(aInBrowser
),
1029 mWebBrowserChrome(aInChrome
),
1030 mTooltipListenerInstalled(false),
1031 mShowingTooltip(false),
1032 mTooltipShownOnce(false) {}
1034 ChromeTooltipListener::~ChromeTooltipListener() {}
1036 nsITooltipTextProvider
* ChromeTooltipListener::GetTooltipTextProvider() {
1037 if (!mTooltipTextProvider
) {
1038 mTooltipTextProvider
= do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID
);
1041 if (!mTooltipTextProvider
) {
1042 mTooltipTextProvider
=
1043 do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID
);
1046 return mTooltipTextProvider
;
1049 // Hook up things to the chrome like context menus and tooltips, if the chrome
1050 // has implemented the right interfaces.
1052 ChromeTooltipListener::AddChromeListeners() {
1053 if (!mEventTarget
) {
1054 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(mEventTarget
));
1057 // Register the appropriate events for tooltips, but only if
1058 // the embedding chrome cares.
1059 nsresult rv
= NS_OK
;
1060 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1061 do_QueryInterface(mWebBrowserChrome
));
1062 if (tooltipListener
&& !mTooltipListenerInstalled
) {
1063 rv
= AddTooltipListener();
1064 if (NS_FAILED(rv
)) {
1072 // Subscribe to the events that will allow us to track tooltips. We need "mouse"
1073 // for mouseExit, "mouse motion" for mouseMove, and "key" for keyDown. As we
1074 // add the listeners, keep track of how many succeed so we can clean up
1075 // correctly in Release().
1077 ChromeTooltipListener::AddTooltipListener() {
1079 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"keydown"_ns
, this, false,
1081 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousedown"_ns
, this, false,
1083 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mouseout"_ns
, this, false,
1085 MOZ_TRY(mEventTarget
->AddSystemEventListener(u
"mousemove"_ns
, this, false,
1088 mTooltipListenerInstalled
= true;
1094 // Unsubscribe from the various things we've hooked up to the window root.
1096 ChromeTooltipListener::RemoveChromeListeners() {
1099 if (mTooltipListenerInstalled
) {
1100 RemoveTooltipListener();
1103 mEventTarget
= nullptr;
1105 // it really doesn't matter if these fail...
1109 // Unsubscribe from all the various tooltip events that we were listening to.
1111 ChromeTooltipListener::RemoveTooltipListener() {
1113 mEventTarget
->RemoveSystemEventListener(u
"keydown"_ns
, this, false);
1114 mEventTarget
->RemoveSystemEventListener(u
"mousedown"_ns
, this, false);
1115 mEventTarget
->RemoveSystemEventListener(u
"mouseout"_ns
, this, false);
1116 mEventTarget
->RemoveSystemEventListener(u
"mousemove"_ns
, this, false);
1117 mTooltipListenerInstalled
= false;
1124 ChromeTooltipListener::HandleEvent(Event
* aEvent
) {
1125 nsAutoString eventType
;
1126 aEvent
->GetType(eventType
);
1128 if (eventType
.EqualsLiteral("mousedown")) {
1129 return HideTooltip();
1130 } else if (eventType
.EqualsLiteral("keydown")) {
1131 WidgetKeyboardEvent
* keyEvent
= aEvent
->WidgetEventPtr()->AsKeyboardEvent();
1132 if (nsXULTooltipListener::KeyEventHidesTooltip(*keyEvent
)) {
1133 return HideTooltip();
1136 } else if (eventType
.EqualsLiteral("mouseout")) {
1137 // Reset flag so that tooltip will display on the next MouseMove
1138 mTooltipShownOnce
= false;
1139 return HideTooltip();
1140 } else if (eventType
.EqualsLiteral("mousemove")) {
1141 return MouseMove(aEvent
);
1144 NS_ERROR("Unexpected event type");
1148 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If
1149 // the timer fires, we cache the node in |mPossibleTooltipNode|.
1150 nsresult
ChromeTooltipListener::MouseMove(Event
* aMouseEvent
) {
1151 if (!nsXULTooltipListener::ShowTooltips()) {
1155 MouseEvent
* mouseEvent
= aMouseEvent
->AsMouseEvent();
1160 // stash the coordinates of the event so that we can still get back to it from
1161 // within the timer callback. On win32, we'll get a MouseMove event even when
1162 // a popup goes away -- even when the mouse doesn't change position! To get
1163 // around this, we make sure the mouse has really moved before proceeding.
1164 CSSIntPoint newMouseClientPoint
= mouseEvent
->ClientPoint();
1165 if (mMouseClientPoint
== newMouseClientPoint
) {
1169 // Filter out minor mouse movements.
1170 if (mShowingTooltip
&&
1171 (abs(mMouseClientPoint
.x
- newMouseClientPoint
.x
) <=
1172 kTooltipMouseMoveTolerance
) &&
1173 (abs(mMouseClientPoint
.y
- newMouseClientPoint
.y
) <=
1174 kTooltipMouseMoveTolerance
)) {
1178 mMouseClientPoint
= newMouseClientPoint
;
1179 mMouseScreenPoint
= mouseEvent
->ScreenPointLayoutDevicePix();
1181 if (mTooltipTimer
) {
1182 mTooltipTimer
->Cancel();
1183 mTooltipTimer
= nullptr;
1186 if (!mShowingTooltip
) {
1187 nsIEventTarget
* target
= nullptr;
1188 if (nsCOMPtr
<EventTarget
> eventTarget
= aMouseEvent
->GetComposedTarget()) {
1189 mPossibleTooltipNode
= nsINode::FromEventTarget(eventTarget
);
1190 nsCOMPtr
<nsIGlobalObject
> global(eventTarget
->GetOwnerGlobal());
1192 target
= global
->EventTargetFor(TaskCategory::UI
);
1196 if (mPossibleTooltipNode
) {
1197 nsresult rv
= NS_NewTimerWithFuncCallback(
1198 getter_AddRefs(mTooltipTimer
), sTooltipCallback
, this,
1199 LookAndFeel::GetInt(LookAndFeel::IntID::TooltipDelay
, 500),
1200 nsITimer::TYPE_ONE_SHOT
, "ChromeTooltipListener::MouseMove", target
);
1201 if (NS_FAILED(rv
)) {
1202 mPossibleTooltipNode
= nullptr;
1203 NS_WARNING("Could not create a timer for tooltip tracking");
1207 mTooltipShownOnce
= true;
1208 return HideTooltip();
1214 // Tell the registered chrome that they should show the tooltip.
1216 ChromeTooltipListener::ShowTooltip(int32_t aInXCoords
, int32_t aInYCoords
,
1217 const nsAString
& aInTipText
,
1218 const nsAString
& aTipDir
) {
1219 nsresult rv
= NS_OK
;
1221 // do the work to call the client
1222 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1223 do_QueryInterface(mWebBrowserChrome
));
1224 if (tooltipListener
) {
1225 rv
= tooltipListener
->OnShowTooltip(aInXCoords
, aInYCoords
, aInTipText
,
1227 if (NS_SUCCEEDED(rv
)) {
1228 mShowingTooltip
= true;
1235 // Tell the registered chrome that they should rollup the tooltip
1236 // NOTE: This routine is safe to call even if the popup is already closed.
1238 ChromeTooltipListener::HideTooltip() {
1239 nsresult rv
= NS_OK
;
1241 // shut down the relevant timers
1242 if (mTooltipTimer
) {
1243 mTooltipTimer
->Cancel();
1244 mTooltipTimer
= nullptr;
1245 // release tooltip target
1246 mPossibleTooltipNode
= nullptr;
1247 mLastDocshell
= nullptr;
1250 // if we're showing the tip, tell the chrome to hide it
1251 if (mShowingTooltip
) {
1252 nsCOMPtr
<nsITooltipListener
> tooltipListener(
1253 do_QueryInterface(mWebBrowserChrome
));
1254 if (tooltipListener
) {
1255 rv
= tooltipListener
->OnHideTooltip();
1256 if (NS_SUCCEEDED(rv
)) {
1257 mShowingTooltip
= false;
1265 bool ChromeTooltipListener::WebProgressShowedTooltip(
1266 nsIWebProgress
* aWebProgress
) {
1267 nsCOMPtr
<nsIDocShell
> docshell
= do_QueryInterface(aWebProgress
);
1268 nsCOMPtr
<nsIDocShell
> lastUsed
= do_QueryReferent(mLastDocshell
);
1270 if (lastUsed
== docshell
) {
1273 // We can't use the docshell hierarchy here, because when the parent
1274 // docshell is navigated, the child docshell is disconnected (ie its
1275 // references to the parent are nulled out) despite it still being
1276 // alive here. So we use the document hierarchy instead:
1277 Document
* document
= lastUsed
->GetDocument();
1279 document
= document
->GetInProcessParentDocument();
1284 lastUsed
= document
->GetDocShell();
1289 // A timer callback, fired when the mouse has hovered inside of a frame for the
1290 // appropriate amount of time. Getting to this point means that we should show
1291 // the tooltip, but only after we determine there is an appropriate TITLE
1294 // This relies on certain things being cached into the |aChromeTooltipListener|
1295 // object passed to us by the timer:
1296 // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1297 // -- the dom node the user hovered over (mPossibleTooltipNode)
1298 void ChromeTooltipListener::sTooltipCallback(nsITimer
* aTimer
,
1299 void* aChromeTooltipListener
) {
1300 auto* self
= static_cast<ChromeTooltipListener
*>(aChromeTooltipListener
);
1301 if (!self
|| !self
->mPossibleTooltipNode
) {
1304 // release tooltip target once done, no matter what we do here.
1305 auto cleanup
= MakeScopeExit([&] { self
->mPossibleTooltipNode
= nullptr; });
1306 if (!self
->mPossibleTooltipNode
->IsInComposedDoc()) {
1309 // Check that the document or its ancestors haven't been replaced.
1311 Document
* doc
= self
->mPossibleTooltipNode
->OwnerDoc();
1313 if (!doc
->IsCurrentActiveDocument()) {
1316 doc
= doc
->GetInProcessParentDocument();
1320 nsCOMPtr
<nsIDocShell
> docShell
=
1321 do_GetInterface(static_cast<nsIWebBrowser
*>(self
->mWebBrowser
));
1322 if (!docShell
|| !docShell
->GetBrowsingContext()->IsActive()) {
1326 // if there is text associated with the node, show the tip and fire
1327 // off a timer to auto-hide it.
1328 nsITooltipTextProvider
* tooltipProvider
= self
->GetTooltipTextProvider();
1329 if (!tooltipProvider
) {
1332 nsString tooltipText
;
1333 nsString directionText
;
1334 bool textFound
= false;
1335 tooltipProvider
->GetNodeText(self
->mPossibleTooltipNode
,
1336 getter_Copies(tooltipText
),
1337 getter_Copies(directionText
), &textFound
);
1339 if (textFound
&& (!self
->mTooltipShownOnce
||
1340 tooltipText
!= self
->mLastShownTooltipText
)) {
1341 // ShowTooltip expects screen-relative position.
1342 self
->ShowTooltip(self
->mMouseScreenPoint
.x
, self
->mMouseScreenPoint
.y
,
1343 tooltipText
, directionText
);
1344 self
->mLastShownTooltipText
= std::move(tooltipText
);
1345 self
->mLastDocshell
= do_GetWeakReference(
1346 self
->mPossibleTooltipNode
->OwnerDoc()->GetDocShell());