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