1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDocShellTreeOwner.h"
8 #include "nsWebBrowser.h"
11 #include "nsStyleCoord.h"
13 #include "nsHTMLReflowState.h"
14 #include "nsIServiceManager.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsXPIDLString.h"
18 #include "nsReadableUtils.h"
19 #include "nsUnicharUtils.h"
20 #include "nsISimpleEnumerator.h"
21 #include "mozilla/LookAndFeel.h"
23 // Interfaces needed to be included
24 #include "nsPresContext.h"
25 #include "nsIContextMenuListener.h"
26 #include "nsIContextMenuListener2.h"
27 #include "nsITooltipListener.h"
28 #include "nsIDOMNode.h"
29 #include "nsIDOMNodeList.h"
30 #include "nsIDOMDocument.h"
31 #include "nsIDOMDocumentType.h"
32 #include "nsIDOMElement.h"
34 #include "mozilla/dom/Element.h"
35 #include "mozilla/dom/SVGTitleElement.h"
36 #include "nsIDOMEvent.h"
37 #include "nsIDOMMouseEvent.h"
38 #include "nsIFormControl.h"
39 #include "nsIDOMHTMLInputElement.h"
40 #include "nsIDOMHTMLTextAreaElement.h"
41 #include "nsIDOMHTMLHtmlElement.h"
42 #include "nsIDOMHTMLAppletElement.h"
43 #include "nsIDOMHTMLObjectElement.h"
44 #include "nsIDOMHTMLEmbedElement.h"
45 #include "nsIDOMHTMLDocument.h"
46 #include "nsIImageLoadingContent.h"
47 #include "nsIWebNavigation.h"
48 #include "nsIDOMHTMLElement.h"
49 #include "nsIPresShell.h"
50 #include "nsPIDOMWindow.h"
51 #include "nsPIWindowRoot.h"
52 #include "nsIDOMWindowCollection.h"
53 #include "nsIWindowWatcher.h"
54 #include "nsPIWindowWatcher.h"
55 #include "nsIPrompt.h"
57 #include "nsIWebBrowserChromeFocus.h"
58 #include "nsIContent.h"
59 #include "imgIContainer.h"
60 #include "nsContextMenuInfo.h"
61 #include "nsPresContext.h"
62 #include "nsViewManager.h"
64 #include "nsIDOMDragEvent.h"
65 #include "nsIConstraintValidation.h"
66 #include "mozilla/Attributes.h"
67 #include "mozilla/EventListenerManager.h"
68 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
70 using namespace mozilla
;
71 using namespace mozilla::dom
;
76 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
77 // a |EventTarget| via the window root and chrome event handler.
80 GetDOMEventTarget(nsWebBrowser
* inBrowser
, EventTarget
** aTarget
)
82 NS_ENSURE_ARG_POINTER(inBrowser
);
84 nsCOMPtr
<nsIDOMWindow
> domWindow
;
85 inBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
86 NS_ENSURE_TRUE(domWindow
, NS_ERROR_FAILURE
);
88 nsCOMPtr
<nsPIDOMWindow
> domWindowPrivate
= do_QueryInterface(domWindow
);
89 NS_ENSURE_TRUE(domWindowPrivate
, NS_ERROR_FAILURE
);
90 nsPIDOMWindow
*rootWindow
= domWindowPrivate
->GetPrivateRoot();
91 NS_ENSURE_TRUE(rootWindow
, NS_ERROR_FAILURE
);
92 nsCOMPtr
<EventTarget
> target
=
93 rootWindow
->GetChromeEventHandler();
94 NS_ENSURE_TRUE(target
, NS_ERROR_FAILURE
);
95 target
.forget(aTarget
);
101 //*****************************************************************************
102 //*** nsDocShellTreeOwner: Object Management
103 //*****************************************************************************
105 nsDocShellTreeOwner::nsDocShellTreeOwner() :
106 mWebBrowser(nullptr),
108 mPrimaryContentShell(nullptr),
109 mWebBrowserChrome(nullptr),
111 mOwnerRequestor(nullptr),
112 mChromeTooltipListener(nullptr),
113 mChromeContextMenuListener(nullptr)
117 nsDocShellTreeOwner::~nsDocShellTreeOwner()
119 RemoveChromeListeners();
122 //*****************************************************************************
123 // nsDocShellTreeOwner::nsISupports
124 //*****************************************************************************
126 NS_IMPL_ADDREF(nsDocShellTreeOwner
)
127 NS_IMPL_RELEASE(nsDocShellTreeOwner
)
129 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner
)
130 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDocShellTreeOwner
)
131 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner
)
132 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
133 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
134 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
135 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener
)
136 NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner
)
137 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
140 //*****************************************************************************
141 // nsDocShellTreeOwner::nsIInterfaceRequestor
142 //*****************************************************************************
145 nsDocShellTreeOwner::GetInterface(const nsIID
& aIID
, void** aSink
)
147 NS_ENSURE_ARG_POINTER(aSink
);
149 if(NS_SUCCEEDED(QueryInterface(aIID
, aSink
)))
152 if (aIID
.Equals(NS_GET_IID(nsIWebBrowserChromeFocus
))) {
153 if (mWebBrowserChromeWeak
!= nullptr)
154 return mWebBrowserChromeWeak
->QueryReferent(aIID
, aSink
);
155 return mOwnerWin
->QueryInterface(aIID
, aSink
);
158 if (aIID
.Equals(NS_GET_IID(nsIPrompt
))) {
167 return NS_NOINTERFACE
;
170 if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
))) {
171 nsIAuthPrompt
*prompt
;
172 EnsureAuthPrompter();
173 prompt
= mAuthPrompter
;
179 return NS_NOINTERFACE
;
182 nsCOMPtr
<nsIInterfaceRequestor
> req
= GetOwnerRequestor();
184 return req
->GetInterface(aIID
, aSink
);
186 return NS_NOINTERFACE
;
189 //*****************************************************************************
190 // nsDocShellTreeOwner::nsIDocShellTreeOwner
191 //*****************************************************************************
194 nsDocShellTreeOwner::FindItemWithName(const char16_t
* aName
,
195 nsIDocShellTreeItem
* aRequestor
,
196 nsIDocShellTreeItem
* aOriginalRequestor
,
197 nsIDocShellTreeItem
** aFoundItem
)
199 NS_ENSURE_ARG(aName
);
200 NS_ENSURE_ARG_POINTER(aFoundItem
);
201 *aFoundItem
= nullptr; // if we don't find one, we return NS_OK and a null result
204 nsAutoString
name(aName
);
207 return NS_OK
; // stymied
212 if(name
.LowerCaseEqualsLiteral("_blank"))
214 // _main is an IE target which should be case-insensitive but isn't
215 // see bug 217886 for details
216 // XXXbz what if our browser isn't targetable? We need to handle that somehow.
217 if(name
.LowerCaseEqualsLiteral("_content") || name
.EqualsLiteral("_main")) {
218 *aFoundItem
= mWebBrowser
->mDocShell
;
219 NS_IF_ADDREF(*aFoundItem
);
223 if (!SameCOMIdentity(aRequestor
, mWebBrowser
->mDocShell
)) {
224 // This isn't a request coming up from our kid, so check with said kid
225 nsISupports
* thisSupports
= static_cast<nsIDocShellTreeOwner
*>(this);
226 rv
= mWebBrowser
->mDocShell
->FindItemWithName(aName
, thisSupports
,
227 aOriginalRequestor
, aFoundItem
);
228 if (NS_FAILED(rv
) || *aFoundItem
) {
233 // next, if we have a parent and it isn't the requestor, ask it
235 nsCOMPtr
<nsIDocShellTreeOwner
> reqAsTreeOwner(do_QueryInterface(aRequestor
));
236 if (mTreeOwner
!= reqAsTreeOwner
)
237 return mTreeOwner
->FindItemWithName(aName
, mWebBrowser
->mDocShell
,
238 aOriginalRequestor
, aFoundItem
);
242 // finally, failing everything else, search all windows
243 return FindItemWithNameAcrossWindows(aName
, aRequestor
, aOriginalRequestor
,
248 nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const char16_t
* aName
,
249 nsIDocShellTreeItem
* aRequestor
,
250 nsIDocShellTreeItem
* aOriginalRequestor
,
251 nsIDocShellTreeItem
** aFoundItem
)
253 // search for the item across the list of top-level windows
254 nsCOMPtr
<nsPIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
258 return wwatch
->FindItemWithName(aName
, aRequestor
, aOriginalRequestor
,
263 nsDocShellTreeOwner::EnsurePrompter()
268 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
269 if (wwatch
&& mWebBrowser
) {
270 nsCOMPtr
<nsIDOMWindow
> domWindow
;
271 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
273 wwatch
->GetNewPrompter(domWindow
, getter_AddRefs(mPrompter
));
278 nsDocShellTreeOwner::EnsureAuthPrompter()
283 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
284 if (wwatch
&& mWebBrowser
) {
285 nsCOMPtr
<nsIDOMWindow
> domWindow
;
286 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
288 wwatch
->GetNewAuthPrompter(domWindow
, getter_AddRefs(mAuthPrompter
));
293 nsDocShellTreeOwner::AddToWatcher()
296 nsCOMPtr
<nsIDOMWindow
> domWindow
;
297 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
299 nsCOMPtr
<nsPIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
301 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
302 if (webBrowserChrome
)
303 wwatch
->AddWindow(domWindow
, webBrowserChrome
);
310 nsDocShellTreeOwner::RemoveFromWatcher()
313 nsCOMPtr
<nsIDOMWindow
> domWindow
;
314 mWebBrowser
->GetContentDOMWindow(getter_AddRefs(domWindow
));
316 nsCOMPtr
<nsPIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
318 wwatch
->RemoveWindow(domWindow
);
325 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem
* aContentShell
,
326 bool aPrimary
, bool aTargetable
,
327 const nsAString
& aID
)
330 return mTreeOwner
->ContentShellAdded(aContentShell
, aPrimary
,
334 mPrimaryContentShell
= aContentShell
;
339 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem
* aContentShell
)
342 return mTreeOwner
->ContentShellRemoved(aContentShell
);
344 if(mPrimaryContentShell
== aContentShell
)
345 mPrimaryContentShell
= nullptr;
351 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem
** aShell
)
353 NS_ENSURE_ARG_POINTER(aShell
);
356 return mTreeOwner
->GetPrimaryContentShell(aShell
);
358 *aShell
= (mPrimaryContentShell
? mPrimaryContentShell
: mWebBrowser
->mDocShell
);
359 NS_IF_ADDREF(*aShell
);
365 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem
* aShellItem
,
366 int32_t aCX
, int32_t aCY
)
368 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
370 NS_ENSURE_STATE(mTreeOwner
|| webBrowserChrome
);
373 return mTreeOwner
->SizeShellTo(aShellItem
, aCX
, aCY
);
375 if(aShellItem
== mWebBrowser
->mDocShell
)
376 return webBrowserChrome
->SizeBrowserTo(aCX
, aCY
);
378 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(aShellItem
));
379 NS_ENSURE_TRUE(webNav
, NS_ERROR_FAILURE
);
381 nsCOMPtr
<nsIDOMDocument
> domDocument
;
382 webNav
->GetDocument(getter_AddRefs(domDocument
));
383 NS_ENSURE_TRUE(domDocument
, NS_ERROR_FAILURE
);
385 nsCOMPtr
<nsIDOMElement
> domElement
;
386 domDocument
->GetDocumentElement(getter_AddRefs(domElement
));
387 NS_ENSURE_TRUE(domElement
, NS_ERROR_FAILURE
);
389 // Set the preferred Size
391 NS_ERROR("Implement this");
393 Set the preferred size on the aShellItem.
396 nsRefPtr
<nsPresContext
> presContext
;
397 mWebBrowser
->mDocShell
->GetPresContext(getter_AddRefs(presContext
));
398 NS_ENSURE_TRUE(presContext
, NS_ERROR_FAILURE
);
400 nsIPresShell
*presShell
= presContext
->GetPresShell();
401 NS_ENSURE_TRUE(presShell
, NS_ERROR_FAILURE
);
403 NS_ENSURE_SUCCESS(presShell
->ResizeReflow(NS_UNCONSTRAINEDSIZE
,
404 NS_UNCONSTRAINEDSIZE
), NS_ERROR_FAILURE
);
406 nsRect shellArea
= presContext
->GetVisibleArea();
408 int32_t browserCX
= presContext
->AppUnitsToDevPixels(shellArea
.width
);
409 int32_t browserCY
= presContext
->AppUnitsToDevPixels(shellArea
.height
);
411 return webBrowserChrome
->SizeBrowserTo(browserCX
, browserCY
);
415 nsDocShellTreeOwner::SetPersistence(bool aPersistPosition
,
417 bool aPersistSizeMode
)
419 return NS_ERROR_NOT_IMPLEMENTED
;
423 nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition
,
425 bool* aPersistSizeMode
)
427 return NS_ERROR_NOT_IMPLEMENTED
;
431 nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult
)
434 mTreeOwner
->GetTargetableShellCount(aResult
);
442 //*****************************************************************************
443 // nsDocShellTreeOwner::nsIBaseWindow
444 //*****************************************************************************
448 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow
,
449 nsIWidget
* aParentWidget
, int32_t aX
,
450 int32_t aY
, int32_t aCX
, int32_t aCY
)
452 return NS_ERROR_NULL_POINTER
;
456 nsDocShellTreeOwner::Create()
458 return NS_ERROR_NULL_POINTER
;
462 nsDocShellTreeOwner::Destroy()
464 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
465 if (webBrowserChrome
)
467 return webBrowserChrome
->DestroyBrowserWindow();
470 return NS_ERROR_NULL_POINTER
;
474 nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale
)
477 return mWebBrowser
->GetUnscaledDevicePixelsPerCSSPixel(aScale
);
485 nsDocShellTreeOwner::SetPosition(int32_t aX
, int32_t aY
)
487 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
490 return ownerWin
->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION
,
493 return NS_ERROR_NULL_POINTER
;
497 nsDocShellTreeOwner::GetPosition(int32_t* aX
, int32_t* aY
)
499 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
502 return ownerWin
->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION
,
503 aX
, aY
, nullptr, nullptr);
505 return NS_ERROR_NULL_POINTER
;
509 nsDocShellTreeOwner::SetSize(int32_t aCX
, int32_t aCY
, bool aRepaint
)
511 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
514 return ownerWin
->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER
,
517 return NS_ERROR_NULL_POINTER
;
521 nsDocShellTreeOwner::GetSize(int32_t* aCX
, int32_t* aCY
)
523 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
526 return ownerWin
->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER
,
527 nullptr, nullptr, aCX
, aCY
);
529 return NS_ERROR_NULL_POINTER
;
533 nsDocShellTreeOwner::SetPositionAndSize(int32_t aX
, int32_t aY
, int32_t aCX
,
534 int32_t aCY
, bool aRepaint
)
536 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
539 return ownerWin
->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER
|
540 nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION
,
543 return NS_ERROR_NULL_POINTER
;
547 nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX
, int32_t* aY
, int32_t* aCX
,
550 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
553 return ownerWin
->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER
|
554 nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION
,
557 return NS_ERROR_NULL_POINTER
;
561 nsDocShellTreeOwner::Repaint(bool aForce
)
563 return NS_ERROR_NULL_POINTER
;
567 nsDocShellTreeOwner::GetParentWidget(nsIWidget
** aParentWidget
)
569 return NS_ERROR_NULL_POINTER
;
573 nsDocShellTreeOwner::SetParentWidget(nsIWidget
* aParentWidget
)
575 return NS_ERROR_NULL_POINTER
;
579 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow
* aParentNativeWindow
)
581 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
584 return ownerWin
->GetSiteWindow(aParentNativeWindow
);
586 return NS_ERROR_NULL_POINTER
;
590 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow
)
592 return NS_ERROR_NULL_POINTER
;
596 nsDocShellTreeOwner::GetNativeHandle(nsAString
& aNativeHandle
)
598 // the nativeHandle should be accessed from nsIXULWindow
599 return NS_ERROR_NOT_IMPLEMENTED
;
603 nsDocShellTreeOwner::GetVisibility(bool* aVisibility
)
605 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
608 return ownerWin
->GetVisibility(aVisibility
);
610 return NS_ERROR_NULL_POINTER
;
614 nsDocShellTreeOwner::SetVisibility(bool aVisibility
)
616 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
619 return ownerWin
->SetVisibility(aVisibility
);
621 return NS_ERROR_NULL_POINTER
;
625 nsDocShellTreeOwner::GetEnabled(bool *aEnabled
)
627 NS_ENSURE_ARG_POINTER(aEnabled
);
629 return NS_ERROR_NOT_IMPLEMENTED
;
633 nsDocShellTreeOwner::SetEnabled(bool aEnabled
)
635 return NS_ERROR_NOT_IMPLEMENTED
;
639 nsDocShellTreeOwner::GetMainWidget(nsIWidget
** aMainWidget
)
641 return NS_ERROR_NULL_POINTER
;
645 nsDocShellTreeOwner::SetFocus()
647 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
650 return ownerWin
->SetFocus();
652 return NS_ERROR_NULL_POINTER
;
656 nsDocShellTreeOwner::GetTitle(char16_t
** aTitle
)
658 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
661 return ownerWin
->GetTitle(aTitle
);
663 return NS_ERROR_NULL_POINTER
;
667 nsDocShellTreeOwner::SetTitle(const char16_t
* aTitle
)
669 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin
= GetOwnerWin();
672 return ownerWin
->SetTitle(aTitle
);
674 return NS_ERROR_NULL_POINTER
;
678 //*****************************************************************************
679 // nsDocShellTreeOwner::nsIWebProgressListener
680 //*****************************************************************************
684 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress
* aProgress
,
685 nsIRequest
* aRequest
,
686 int32_t aCurSelfProgress
,
687 int32_t aMaxSelfProgress
,
688 int32_t aCurTotalProgress
,
689 int32_t aMaxTotalProgress
)
691 // In the absence of DOM document creation event, this method is the
692 // most convenient place to install the mouse listener on the
694 return AddChromeListeners();
698 nsDocShellTreeOwner::OnStateChange(nsIWebProgress
* aProgress
,
699 nsIRequest
* aRequest
,
700 uint32_t aProgressStateFlags
,
707 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress
* aWebProgress
,
708 nsIRequest
* aRequest
,
716 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress
* aWebProgress
,
717 nsIRequest
* aRequest
,
719 const char16_t
* aMessage
)
725 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress
*aWebProgress
,
726 nsIRequest
*aRequest
,
733 //*****************************************************************************
734 // nsDocShellTreeOwner: Helpers
735 //*****************************************************************************
737 //*****************************************************************************
738 // nsDocShellTreeOwner: Accessors
739 //*****************************************************************************
742 nsDocShellTreeOwner::WebBrowser(nsWebBrowser
* aWebBrowser
)
745 RemoveChromeListeners();
746 if (aWebBrowser
!= mWebBrowser
) {
751 mWebBrowser
= aWebBrowser
;
755 nsDocShellTreeOwner::WebBrowser()
761 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner
* aTreeOwner
)
764 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome(do_GetInterface(aTreeOwner
));
765 NS_ENSURE_TRUE(webBrowserChrome
, NS_ERROR_INVALID_ARG
);
766 NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome
), NS_ERROR_INVALID_ARG
);
767 mTreeOwner
= aTreeOwner
;
770 mTreeOwner
= nullptr;
771 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
772 if (!webBrowserChrome
)
773 NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE
);
780 nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome
* aWebBrowserChrome
)
782 if(!aWebBrowserChrome
) {
783 mWebBrowserChrome
= nullptr;
785 mOwnerRequestor
= nullptr;
786 mWebBrowserChromeWeak
= 0;
788 nsCOMPtr
<nsISupportsWeakReference
> supportsweak
=
789 do_QueryInterface(aWebBrowserChrome
);
791 supportsweak
->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak
));
793 nsCOMPtr
<nsIEmbeddingSiteWindow
> ownerWin(do_QueryInterface(aWebBrowserChrome
));
794 nsCOMPtr
<nsIInterfaceRequestor
> requestor(do_QueryInterface(aWebBrowserChrome
));
796 // it's ok for ownerWin or requestor to be null.
797 mWebBrowserChrome
= aWebBrowserChrome
;
798 mOwnerWin
= ownerWin
;
799 mOwnerRequestor
= requestor
;
807 // AddChromeListeners
809 // Hook up things to the chrome like context menus and tooltips, if the chrome
810 // has implemented the right interfaces.
813 nsDocShellTreeOwner::AddChromeListeners()
817 nsCOMPtr
<nsIWebBrowserChrome
> webBrowserChrome
= GetWebBrowserChrome();
818 if (!webBrowserChrome
)
819 return NS_ERROR_FAILURE
;
822 if ( !mChromeTooltipListener
) {
823 nsCOMPtr
<nsITooltipListener
>
824 tooltipListener(do_QueryInterface(webBrowserChrome
));
825 if ( tooltipListener
) {
826 mChromeTooltipListener
= new ChromeTooltipListener(mWebBrowser
,
828 if ( mChromeTooltipListener
) {
829 NS_ADDREF(mChromeTooltipListener
);
830 rv
= mChromeTooltipListener
->AddChromeListeners();
833 rv
= NS_ERROR_OUT_OF_MEMORY
;
837 // install context menus
838 if ( !mChromeContextMenuListener
) {
839 nsCOMPtr
<nsIContextMenuListener2
>
840 contextListener2(do_QueryInterface(webBrowserChrome
));
841 nsCOMPtr
<nsIContextMenuListener
>
842 contextListener(do_QueryInterface(webBrowserChrome
));
843 if ( contextListener2
|| contextListener
) {
844 mChromeContextMenuListener
=
845 new ChromeContextMenuListener(mWebBrowser
, webBrowserChrome
);
846 if ( mChromeContextMenuListener
) {
847 NS_ADDREF(mChromeContextMenuListener
);
848 rv
= mChromeContextMenuListener
->AddChromeListeners();
851 rv
= NS_ERROR_OUT_OF_MEMORY
;
855 // register dragover and drop event listeners with the listener manager
856 nsCOMPtr
<EventTarget
> target
;
857 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(target
));
859 EventListenerManager
* elmP
= target
->GetOrCreateListenerManager();
861 elmP
->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"),
862 TrustedEventsAtSystemGroupBubble());
863 elmP
->AddEventListenerByType(this, NS_LITERAL_STRING("drop"),
864 TrustedEventsAtSystemGroupBubble());
869 } // AddChromeListeners
873 nsDocShellTreeOwner::RemoveChromeListeners()
875 if ( mChromeTooltipListener
) {
876 mChromeTooltipListener
->RemoveChromeListeners();
877 NS_RELEASE(mChromeTooltipListener
);
879 if ( mChromeContextMenuListener
) {
880 mChromeContextMenuListener
->RemoveChromeListeners();
881 NS_RELEASE(mChromeContextMenuListener
);
884 nsCOMPtr
<EventTarget
> piTarget
;
885 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(piTarget
));
889 EventListenerManager
* elmP
= piTarget
->GetOrCreateListenerManager();
892 elmP
->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"),
893 TrustedEventsAtSystemGroupBubble());
894 elmP
->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"),
895 TrustedEventsAtSystemGroupBubble());
902 nsDocShellTreeOwner::HandleEvent(nsIDOMEvent
* aEvent
)
904 nsCOMPtr
<nsIDOMDragEvent
> dragEvent
= do_QueryInterface(aEvent
);
905 NS_ENSURE_TRUE(dragEvent
, NS_ERROR_INVALID_ARG
);
907 bool defaultPrevented
;
908 aEvent
->GetDefaultPrevented(&defaultPrevented
);
909 if (defaultPrevented
) {
913 nsCOMPtr
<nsIDroppedLinkHandler
> handler
= do_GetService("@mozilla.org/content/dropped-link-handler;1");
915 nsAutoString eventType
;
916 aEvent
->GetType(eventType
);
917 if (eventType
.EqualsLiteral("dragover")) {
919 handler
->CanDropLink(dragEvent
, false, &canDropLink
);
921 aEvent
->PreventDefault();
923 else if (eventType
.EqualsLiteral("drop")) {
924 nsIWebNavigation
* webnav
= static_cast<nsIWebNavigation
*>(mWebBrowser
);
926 nsAutoString link
, name
;
927 if (webnav
&& NS_SUCCEEDED(handler
->DropLink(dragEvent
, link
, false, name
))) {
928 if (!link
.IsEmpty()) {
929 webnav
->LoadURI(link
.get(), 0, nullptr, nullptr, nullptr);
933 aEvent
->StopPropagation();
934 aEvent
->PreventDefault();
942 already_AddRefed
<nsIWebBrowserChrome
>
943 nsDocShellTreeOwner::GetWebBrowserChrome()
945 nsCOMPtr
<nsIWebBrowserChrome
> chrome
;
946 if (mWebBrowserChromeWeak
) {
947 chrome
= do_QueryReferent(mWebBrowserChromeWeak
);
948 } else if (mWebBrowserChrome
) {
949 chrome
= mWebBrowserChrome
;
951 return chrome
.forget();
954 already_AddRefed
<nsIEmbeddingSiteWindow
>
955 nsDocShellTreeOwner::GetOwnerWin()
957 nsCOMPtr
<nsIEmbeddingSiteWindow
> win
;
958 if (mWebBrowserChromeWeak
) {
959 win
= do_QueryReferent(mWebBrowserChromeWeak
);
960 } else if (mOwnerWin
) {
966 already_AddRefed
<nsIInterfaceRequestor
>
967 nsDocShellTreeOwner::GetOwnerRequestor()
969 nsCOMPtr
<nsIInterfaceRequestor
> req
;
970 if (mWebBrowserChromeWeak
) {
971 req
= do_QueryReferent(mWebBrowserChromeWeak
);
972 } else if (mOwnerRequestor
) {
973 req
= mOwnerRequestor
;
979 ///////////////////////////////////////////////////////////////////////////////
980 // DefaultTooltipTextProvider
982 class DefaultTooltipTextProvider MOZ_FINAL
: public nsITooltipTextProvider
985 DefaultTooltipTextProvider();
987 NS_DECL_THREADSAFE_ISUPPORTS
988 NS_DECL_NSITOOLTIPTEXTPROVIDER
991 ~DefaultTooltipTextProvider() {}
993 nsCOMPtr
<nsIAtom
> mTag_dialog
;
994 nsCOMPtr
<nsIAtom
> mTag_dialogheader
;
995 nsCOMPtr
<nsIAtom
> mTag_window
;
998 NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider
, nsITooltipTextProvider
)
1000 DefaultTooltipTextProvider::DefaultTooltipTextProvider()
1002 // There are certain element types which we don't want to use
1003 // as tool tip text.
1004 mTag_dialog
= do_GetAtom("dialog");
1005 mTag_dialogheader
= do_GetAtom("dialogheader");
1006 mTag_window
= do_GetAtom("window");
1012 // A helper routine that determines whether we're still interested
1013 // in SVG titles. We need to stop at the SVG root element that
1014 // has a document node parent
1017 UseSVGTitle(nsIDOMElement
*currElement
)
1019 nsCOMPtr
<dom::Element
> element(do_QueryInterface(currElement
));
1020 if (!element
|| !element
->IsSVG() || !element
->GetParentNode())
1023 return element
->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE
;
1026 /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
1028 DefaultTooltipTextProvider::GetNodeText(nsIDOMNode
*aNode
, char16_t
**aText
,
1031 NS_ENSURE_ARG_POINTER(aNode
);
1032 NS_ENSURE_ARG_POINTER(aText
);
1036 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
1038 bool lookingForSVGTitle
= true;
1040 nsCOMPtr
<nsIDOMNode
> current ( aNode
);
1042 // If the element implement the constraint validation API and has no title,
1043 // show the validation message, if any.
1044 nsCOMPtr
<nsIConstraintValidation
> cvElement
= do_QueryInterface(current
);
1046 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(cvElement
);
1047 nsCOMPtr
<nsIAtom
> titleAtom
= do_GetAtom("title");
1049 nsCOMPtr
<nsIFormControl
> formControl
= do_QueryInterface(content
);
1050 bool formHasNoValidate
= false;
1051 mozilla::dom::Element
* form
= formControl
->GetFormElement();
1053 nsCOMPtr
<nsIAtom
> noValidateAtom
= do_GetAtom("novalidate");
1054 formHasNoValidate
= form
->HasAttr(kNameSpaceID_None
, noValidateAtom
);
1057 if (!content
->HasAttr(kNameSpaceID_None
, titleAtom
) &&
1058 !formHasNoValidate
) {
1059 cvElement
->GetValidationMessage(outText
);
1060 found
= !outText
.IsEmpty();
1064 while ( !found
&& current
) {
1065 nsCOMPtr
<nsIDOMElement
> currElement ( do_QueryInterface(current
) );
1066 if ( currElement
) {
1067 nsCOMPtr
<nsIContent
> content(do_QueryInterface(currElement
));
1069 nsIAtom
*tagAtom
= content
->Tag();
1070 if (tagAtom
!= mTag_dialog
&&
1071 tagAtom
!= mTag_dialogheader
&&
1072 tagAtom
!= mTag_window
) {
1073 // first try the normal title attribute...
1074 currElement
->GetAttribute(NS_LITERAL_STRING("title"), outText
);
1075 if ( outText
.Length() )
1078 // ...ok, that didn't work, try it in the XLink namespace
1079 NS_NAMED_LITERAL_STRING(xlinkNS
, "http://www.w3.org/1999/xlink");
1080 nsCOMPtr
<mozilla::dom::Link
> linkContent(do_QueryInterface(currElement
));
1082 nsCOMPtr
<nsIURI
> uri(linkContent
->GetURIExternal());
1084 currElement
->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText
);
1085 if ( outText
.Length() )
1090 if (lookingForSVGTitle
) {
1091 lookingForSVGTitle
= UseSVGTitle(currElement
);
1093 if (lookingForSVGTitle
) {
1094 nsINodeList
* childNodes
= node
->ChildNodes();
1095 uint32_t childNodeCount
= childNodes
->Length();
1096 for (uint32_t i
= 0; i
< childNodeCount
; i
++) {
1097 nsIContent
* child
= childNodes
->Item(i
);
1098 if (child
->IsSVG(nsGkAtoms::title
)) {
1099 static_cast<dom::SVGTitleElement
*>(child
)->GetTextContent(outText
);
1100 if ( outText
.Length() )
1112 // not found here, walk up to the parent and keep trying
1114 nsCOMPtr
<nsIDOMNode
> temp ( current
);
1115 temp
->GetParentNode(getter_AddRefs(current
));
1117 } // while not found
1120 *aText
= (found
) ? ToNewUnicode(outText
) : nullptr;
1125 ///////////////////////////////////////////////////////////////////////////////
1127 NS_IMPL_ISUPPORTS(ChromeTooltipListener
, nsIDOMEventListener
)
1130 // ChromeTooltipListener ctor
1133 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser
* inBrowser
,
1134 nsIWebBrowserChrome
* inChrome
)
1135 : mWebBrowser(inBrowser
), mWebBrowserChrome(inChrome
),
1136 mTooltipListenerInstalled(false),
1137 mMouseClientX(0), mMouseClientY(0),
1138 mShowingTooltip(false)
1140 mTooltipTextProvider
= do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID
);
1141 if (!mTooltipTextProvider
) {
1142 nsISupports
*pProvider
= (nsISupports
*) new DefaultTooltipTextProvider
;
1143 mTooltipTextProvider
= do_QueryInterface(pProvider
);
1149 // ChromeTooltipListener dtor
1151 ChromeTooltipListener::~ChromeTooltipListener()
1158 // AddChromeListeners
1160 // Hook up things to the chrome like context menus and tooltips, if the chrome
1161 // has implemented the right interfaces.
1164 ChromeTooltipListener::AddChromeListeners()
1167 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(mEventTarget
));
1169 // Register the appropriate events for tooltips, but only if
1170 // the embedding chrome cares.
1171 nsresult rv
= NS_OK
;
1172 nsCOMPtr
<nsITooltipListener
> tooltipListener ( do_QueryInterface(mWebBrowserChrome
) );
1173 if ( tooltipListener
&& !mTooltipListenerInstalled
) {
1174 rv
= AddTooltipListener();
1175 if ( NS_FAILED(rv
) )
1181 } // AddChromeListeners
1185 // AddTooltipListener
1187 // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
1188 // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
1189 // of how many succeed so we can clean up correctly in Release().
1192 ChromeTooltipListener::AddTooltipListener()
1195 nsresult rv
= mEventTarget
->AddEventListener(NS_LITERAL_STRING("keydown"),
1196 this, false, false);
1197 NS_ENSURE_SUCCESS(rv
, rv
);
1198 rv
= mEventTarget
->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
1200 NS_ENSURE_SUCCESS(rv
, rv
);
1201 rv
= mEventTarget
->AddEventListener(NS_LITERAL_STRING("mouseout"), this,
1203 NS_ENSURE_SUCCESS(rv
, rv
);
1204 rv
= mEventTarget
->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
1206 NS_ENSURE_SUCCESS(rv
, rv
);
1208 mTooltipListenerInstalled
= true;
1216 // RemoveChromeListeners
1218 // Unsubscribe from the various things we've hooked up to the window root.
1221 ChromeTooltipListener::RemoveChromeListeners ( )
1225 if ( mTooltipListenerInstalled
)
1226 RemoveTooltipListener();
1228 mEventTarget
= nullptr;
1230 // it really doesn't matter if these fail...
1233 } // RemoveChromeTooltipListeners
1238 // RemoveTooltipListener
1240 // Unsubscribe from all the various tooltip events that we were listening to
1243 ChromeTooltipListener::RemoveTooltipListener()
1247 mEventTarget
->RemoveEventListener(NS_LITERAL_STRING("keydown"), this,
1249 NS_ENSURE_SUCCESS(rv
, rv
);
1250 rv
= mEventTarget
->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
1252 NS_ENSURE_SUCCESS(rv
, rv
);
1253 rv
= mEventTarget
->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this,
1255 NS_ENSURE_SUCCESS(rv
, rv
);
1256 rv
= mEventTarget
->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
1258 NS_ENSURE_SUCCESS(rv
, rv
);
1260 mTooltipListenerInstalled
= false;
1267 ChromeTooltipListener::HandleEvent(nsIDOMEvent
* aEvent
)
1269 nsAutoString eventType
;
1270 aEvent
->GetType(eventType
);
1272 if (eventType
.EqualsLiteral("keydown") ||
1273 eventType
.EqualsLiteral("mousedown") ||
1274 eventType
.EqualsLiteral("mouseout"))
1275 return HideTooltip();
1276 if (eventType
.EqualsLiteral("mousemove"))
1277 return MouseMove(aEvent
);
1279 NS_ERROR("Unexpected event type");
1286 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
1287 // timer fires, we cache the node in |mPossibleTooltipNode|.
1290 ChromeTooltipListener::MouseMove(nsIDOMEvent
* aMouseEvent
)
1292 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent ( do_QueryInterface(aMouseEvent
) );
1296 // stash the coordinates of the event so that we can still get back to it from within the
1297 // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
1298 // even when the mouse doesn't change position! To get around this, we make sure the
1299 // mouse has really moved before proceeding.
1300 int32_t newMouseX
, newMouseY
;
1301 mouseEvent
->GetClientX(&newMouseX
);
1302 mouseEvent
->GetClientY(&newMouseY
);
1303 if ( mMouseClientX
== newMouseX
&& mMouseClientY
== newMouseY
)
1305 mMouseClientX
= newMouseX
; mMouseClientY
= newMouseY
;
1306 mouseEvent
->GetScreenX(&mMouseScreenX
);
1307 mouseEvent
->GetScreenY(&mMouseScreenY
);
1309 // We want to close the tip if it is being displayed and the mouse moves. Recall
1310 // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
1311 // moves, we want to make sure we reset the timer to show it, so that the delay
1312 // is from when the mouse stops moving, not when it enters the element.
1313 if ( mShowingTooltip
)
1314 return HideTooltip();
1315 if ( mTooltipTimer
)
1316 mTooltipTimer
->Cancel();
1318 mTooltipTimer
= do_CreateInstance("@mozilla.org/timer;1");
1319 if ( mTooltipTimer
) {
1320 nsCOMPtr
<EventTarget
> eventTarget
= aMouseEvent
->InternalDOMEvent()->GetTarget();
1322 mPossibleTooltipNode
= do_QueryInterface(eventTarget
);
1323 if ( mPossibleTooltipNode
) {
1325 mTooltipTimer
->InitWithFuncCallback(sTooltipCallback
, this,
1326 LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay
, 500),
1327 nsITimer::TYPE_ONE_SHOT
);
1329 mPossibleTooltipNode
= nullptr;
1333 NS_WARNING ( "Could not create a timer for tooltip tracking" );
1343 // Tell the registered chrome that they should show the tooltip
1346 ChromeTooltipListener::ShowTooltip(int32_t inXCoords
, int32_t inYCoords
,
1347 const nsAString
& inTipText
)
1349 nsresult rv
= NS_OK
;
1351 // do the work to call the client
1352 nsCOMPtr
<nsITooltipListener
> tooltipListener ( do_QueryInterface(mWebBrowserChrome
) );
1353 if ( tooltipListener
) {
1354 rv
= tooltipListener
->OnShowTooltip ( inXCoords
, inYCoords
, PromiseFlatString(inTipText
).get() );
1355 if ( NS_SUCCEEDED(rv
) )
1356 mShowingTooltip
= true;
1367 // Tell the registered chrome that they should rollup the tooltip
1368 // NOTE: This routine is safe to call even if the popup is already closed.
1371 ChromeTooltipListener::HideTooltip()
1373 nsresult rv
= NS_OK
;
1375 // shut down the relevant timers
1376 if ( mTooltipTimer
) {
1377 mTooltipTimer
->Cancel();
1378 mTooltipTimer
= nullptr;
1379 // release tooltip target
1380 mPossibleTooltipNode
= nullptr;
1382 if ( mAutoHideTimer
) {
1383 mAutoHideTimer
->Cancel();
1384 mAutoHideTimer
= nullptr;
1387 // if we're showing the tip, tell the chrome to hide it
1388 if ( mShowingTooltip
) {
1389 nsCOMPtr
<nsITooltipListener
> tooltipListener ( do_QueryInterface(mWebBrowserChrome
) );
1390 if ( tooltipListener
) {
1391 rv
= tooltipListener
->OnHideTooltip ( );
1392 if ( NS_SUCCEEDED(rv
) )
1393 mShowingTooltip
= false;
1405 // A timer callback, fired when the mouse has hovered inside of a frame for the
1406 // appropriate amount of time. Getting to this point means that we should show the
1407 // tooltip, but only after we determine there is an appropriate TITLE element.
1409 // This relies on certain things being cached into the |aChromeTooltipListener| object passed to
1411 // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1412 // -- the dom node the user hovered over (mPossibleTooltipNode)
1415 ChromeTooltipListener::sTooltipCallback(nsITimer
*aTimer
,
1416 void *aChromeTooltipListener
)
1418 ChromeTooltipListener
* self
= static_cast<ChromeTooltipListener
*>
1419 (aChromeTooltipListener
);
1420 if ( self
&& self
->mPossibleTooltipNode
){
1421 // The actual coordinates we want to put the tooltip at are relative to the
1422 // toplevel docshell of our mWebBrowser. We know what the screen
1423 // coordinates of the mouse event were, which means we just need the screen
1424 // coordinates of the docshell. Unfortunately, there is no good way to
1425 // find those short of groveling for the presentation in that docshell and
1426 // finding the screen coords of its toplevel widget...
1427 nsCOMPtr
<nsIDocShell
> docShell
=
1428 do_GetInterface(static_cast<nsIWebBrowser
*>(self
->mWebBrowser
));
1429 nsCOMPtr
<nsIPresShell
> shell
;
1431 shell
= docShell
->GetPresShell();
1434 nsIWidget
* widget
= nullptr;
1436 nsViewManager
* vm
= shell
->GetViewManager();
1438 nsView
* view
= vm
->GetRootView();
1441 widget
= view
->GetNearestWidget(&offset
);
1447 // release tooltip target if there is one, NO MATTER WHAT
1448 self
->mPossibleTooltipNode
= nullptr;
1452 // if there is text associated with the node, show the tip and fire
1453 // off a timer to auto-hide it.
1455 nsXPIDLString tooltipText
;
1456 if (self
->mTooltipTextProvider
) {
1457 bool textFound
= false;
1459 self
->mTooltipTextProvider
->GetNodeText(
1460 self
->mPossibleTooltipNode
, getter_Copies(tooltipText
), &textFound
);
1463 nsString
tipText(tooltipText
);
1464 self
->CreateAutoHideTimer();
1465 nsIntPoint screenDot
= widget
->WidgetToScreenOffset();
1466 self
->ShowTooltip (self
->mMouseScreenX
- screenDot
.x
,
1467 self
->mMouseScreenY
- screenDot
.y
,
1472 // release tooltip target if there is one, NO MATTER WHAT
1473 self
->mPossibleTooltipNode
= nullptr;
1474 } // if "self" data valid
1476 } // sTooltipCallback
1480 // CreateAutoHideTimer
1482 // Create a new timer to see if we should auto-hide. It's ok if this fails.
1485 ChromeTooltipListener::CreateAutoHideTimer()
1487 // just to be anal (er, safe)
1488 if ( mAutoHideTimer
) {
1489 mAutoHideTimer
->Cancel();
1490 mAutoHideTimer
= nullptr;
1493 mAutoHideTimer
= do_CreateInstance("@mozilla.org/timer;1");
1494 if ( mAutoHideTimer
)
1495 mAutoHideTimer
->InitWithFuncCallback(sAutoHideCallback
, this, kTooltipAutoHideTime
,
1496 nsITimer::TYPE_ONE_SHOT
);
1498 } // CreateAutoHideTimer
1502 // sAutoHideCallback
1504 // This fires after a tooltip has been open for a certain length of time. Just tell
1505 // the listener to close the popup. We don't have to worry, because HideTooltip() can
1506 // be called multiple times, even if the tip has already been closed.
1509 ChromeTooltipListener::sAutoHideCallback(nsITimer
*aTimer
, void* aListener
)
1511 ChromeTooltipListener
* self
= static_cast<ChromeTooltipListener
*>(aListener
);
1513 self
->HideTooltip();
1515 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
1517 } // sAutoHideCallback
1520 NS_IMPL_ISUPPORTS(ChromeContextMenuListener
, nsIDOMEventListener
)
1524 // ChromeTooltipListener ctor
1526 ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser
* inBrowser
, nsIWebBrowserChrome
* inChrome
)
1527 : mContextMenuListenerInstalled(false),
1528 mWebBrowser(inBrowser
),
1529 mWebBrowserChrome(inChrome
)
1535 // ChromeTooltipListener dtor
1537 ChromeContextMenuListener::~ChromeContextMenuListener()
1543 // AddContextMenuListener
1545 // Subscribe to the events that will allow us to track context menus. Bascially, this
1546 // is just the context-menu DOM event.
1549 ChromeContextMenuListener::AddContextMenuListener()
1553 mEventTarget
->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
1555 NS_ENSURE_SUCCESS(rv
, rv
);
1557 mContextMenuListenerInstalled
= true;
1565 // RemoveContextMenuListener
1567 // Unsubscribe from all the various context menu events that we were listening to.
1570 ChromeContextMenuListener::RemoveContextMenuListener()
1574 mEventTarget
->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
1576 NS_ENSURE_SUCCESS(rv
, rv
);
1578 mContextMenuListenerInstalled
= false;
1586 // AddChromeListeners
1588 // Hook up things to the chrome like context menus and tooltips, if the chrome
1589 // has implemented the right interfaces.
1592 ChromeContextMenuListener::AddChromeListeners()
1595 GetDOMEventTarget(mWebBrowser
, getter_AddRefs(mEventTarget
));
1597 // Register the appropriate events for context menus, but only if
1598 // the embedding chrome cares.
1599 nsresult rv
= NS_OK
;
1601 nsCOMPtr
<nsIContextMenuListener2
> contextListener2 ( do_QueryInterface(mWebBrowserChrome
) );
1602 nsCOMPtr
<nsIContextMenuListener
> contextListener ( do_QueryInterface(mWebBrowserChrome
) );
1603 if ( (contextListener
|| contextListener2
) && !mContextMenuListenerInstalled
)
1604 rv
= AddContextMenuListener();
1608 } // AddChromeListeners
1612 // RemoveChromeListeners
1614 // Unsubscribe from the various things we've hooked up to the window root.
1617 ChromeContextMenuListener::RemoveChromeListeners()
1619 if ( mContextMenuListenerInstalled
)
1620 RemoveContextMenuListener();
1622 mEventTarget
= nullptr;
1624 // it really doesn't matter if these fail...
1627 } // RemoveChromeTooltipListeners
1634 // We're on call to show the context menu. Dig around in the DOM to
1635 // find the type of object we're dealing with and notify the front
1639 ChromeContextMenuListener::HandleEvent(nsIDOMEvent
* aMouseEvent
)
1641 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
= do_QueryInterface(aMouseEvent
);
1642 NS_ENSURE_TRUE(mouseEvent
, NS_ERROR_UNEXPECTED
);
1644 bool isDefaultPrevented
= false;
1645 aMouseEvent
->GetDefaultPrevented(&isDefaultPrevented
);
1646 if (isDefaultPrevented
) {
1650 nsCOMPtr
<EventTarget
> targetNode
= aMouseEvent
->InternalDOMEvent()->GetTarget();
1652 return NS_ERROR_NULL_POINTER
;
1654 nsCOMPtr
<nsIDOMNode
> targetDOMnode
;
1655 nsCOMPtr
<nsIDOMNode
> node
= do_QueryInterface(targetNode
);
1659 // Stop the context menu event going to other windows (bug 78396)
1660 aMouseEvent
->PreventDefault();
1662 // If the listener is a nsIContextMenuListener2, create the info object
1663 nsCOMPtr
<nsIContextMenuListener2
> menuListener2(do_QueryInterface(mWebBrowserChrome
));
1664 nsContextMenuInfo
*menuInfoImpl
= nullptr;
1665 nsCOMPtr
<nsIContextMenuInfo
> menuInfo
;
1666 if (menuListener2
) {
1667 menuInfoImpl
= new nsContextMenuInfo
;
1668 menuInfo
= menuInfoImpl
;
1671 uint32_t flags
= nsIContextMenuListener::CONTEXT_NONE
;
1672 uint32_t flags2
= nsIContextMenuListener2::CONTEXT_NONE
;
1674 // XXX test for selected text
1677 nsresult res
= node
->GetNodeType(&nodeType
);
1678 NS_ENSURE_SUCCESS(res
, res
);
1680 // First, checks for nodes that never have children.
1681 if (nodeType
== nsIDOMNode::ELEMENT_NODE
) {
1682 nsCOMPtr
<nsIImageLoadingContent
> content(do_QueryInterface(node
));
1684 nsCOMPtr
<nsIURI
> imgUri
;
1685 content
->GetCurrentURI(getter_AddRefs(imgUri
));
1687 flags
|= nsIContextMenuListener::CONTEXT_IMAGE
;
1688 flags2
|= nsIContextMenuListener2::CONTEXT_IMAGE
;
1689 targetDOMnode
= node
;
1693 nsCOMPtr
<nsIFormControl
> formControl(do_QueryInterface(node
));
1695 if (formControl
->GetType() == NS_FORM_TEXTAREA
) {
1696 flags
|= nsIContextMenuListener::CONTEXT_TEXT
;
1697 flags2
|= nsIContextMenuListener2::CONTEXT_TEXT
;
1698 targetDOMnode
= node
;
1700 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement(do_QueryInterface(formControl
));
1702 flags
|= nsIContextMenuListener::CONTEXT_INPUT
;
1703 flags2
|= nsIContextMenuListener2::CONTEXT_INPUT
;
1705 if (menuListener2
) {
1706 if (formControl
->IsSingleLineTextControl(false)) {
1707 flags2
|= nsIContextMenuListener2::CONTEXT_TEXT
;
1711 targetDOMnode
= node
;
1716 // always consume events for plugins and Java who may throw their
1717 // own context menus but not for image objects. Document objects
1718 // will never be targets or ancestors of targets, so that's OK.
1719 nsCOMPtr
<nsIDOMHTMLObjectElement
> objectElement
;
1720 if (!(flags
& nsIContextMenuListener::CONTEXT_IMAGE
))
1721 objectElement
= do_QueryInterface(node
);
1722 nsCOMPtr
<nsIDOMHTMLEmbedElement
> embedElement(do_QueryInterface(node
));
1723 nsCOMPtr
<nsIDOMHTMLAppletElement
> appletElement(do_QueryInterface(node
));
1725 if (objectElement
|| embedElement
|| appletElement
)
1729 // Bubble out, looking for items of interest
1732 res
= node
->GetNodeType(&nodeType
);
1733 NS_ENSURE_SUCCESS(res
, res
);
1735 if (nodeType
== nsIDOMNode::ELEMENT_NODE
) {
1737 // Test if the element has an associated link
1738 nsCOMPtr
<nsIDOMElement
> element(do_QueryInterface(node
));
1740 bool hasAttr
= false;
1741 res
= element
->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr
);
1743 if (NS_SUCCEEDED(res
) && hasAttr
)
1745 flags
|= nsIContextMenuListener::CONTEXT_LINK
;
1746 flags2
|= nsIContextMenuListener2::CONTEXT_LINK
;
1748 targetDOMnode
= node
;
1750 menuInfoImpl
->SetAssociatedLink(node
);
1751 break; // exit do-while
1756 nsCOMPtr
<nsIDOMNode
> parentNode
;
1757 node
->GetParentNode(getter_AddRefs(parentNode
));
1761 if (!flags
&& !flags2
) {
1762 // We found nothing of interest so far, check if we
1763 // have at least an html document.
1764 nsCOMPtr
<nsIDOMDocument
> document
;
1765 node
= do_QueryInterface(targetNode
);
1766 node
->GetOwnerDocument(getter_AddRefs(document
));
1767 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDocument(do_QueryInterface(document
));
1769 flags
|= nsIContextMenuListener::CONTEXT_DOCUMENT
;
1770 flags2
|= nsIContextMenuListener2::CONTEXT_DOCUMENT
;
1771 targetDOMnode
= node
;
1772 if (!(flags
& nsIContextMenuListener::CONTEXT_IMAGE
)) {
1773 // check if this is a background image that the user was trying to click on
1774 // and if the listener is ready for that (only nsIContextMenuListener2 and up)
1775 if (menuInfoImpl
&& menuInfoImpl
->HasBackgroundImage(targetDOMnode
)) {
1776 flags2
|= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE
;
1777 // For the embedder to get the correct background image
1778 // targetDOMnode must point to the original node.
1779 targetDOMnode
= do_QueryInterface(targetNode
);
1785 // we need to cache the event target into the focus controller's popupNode
1786 // so we can get at it later from command code, etc.:
1788 // get the dom window
1789 nsCOMPtr
<nsIDOMWindow
> win
;
1790 res
= mWebBrowser
->GetContentDOMWindow(getter_AddRefs(win
));
1791 NS_ENSURE_SUCCESS(res
, res
);
1792 NS_ENSURE_TRUE(win
, NS_ERROR_FAILURE
);
1794 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(win
));
1795 NS_ENSURE_TRUE(window
, NS_ERROR_FAILURE
);
1796 nsCOMPtr
<nsPIWindowRoot
> root
= window
->GetTopWindowRoot();
1797 NS_ENSURE_TRUE(root
, NS_ERROR_FAILURE
);
1799 // set the window root's popup node to the event target
1800 root
->SetPopupNode(targetDOMnode
);
1803 // Tell the listener all about the event
1804 if ( menuListener2
) {
1805 menuInfoImpl
->SetMouseEvent(aMouseEvent
);
1806 menuInfoImpl
->SetDOMNode(targetDOMnode
);
1807 menuListener2
->OnShowContextMenu(flags2
, menuInfo
);
1810 nsCOMPtr
<nsIContextMenuListener
> menuListener(do_QueryInterface(mWebBrowserChrome
));
1812 menuListener
->OnShowContextMenu(flags
, aMouseEvent
, targetDOMnode
);