1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla browser.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications, Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Travis Bogard <travis@netscape.com>
24 : * Adam Lock <adamlock@netscape.com>
25 : * Mike Pinkerton <pinkerton@netscape.com>
26 : * Dan Rosen <dr@netscape.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : // Local Includes
43 : #include "nsDocShellTreeOwner.h"
44 : #include "nsWebBrowser.h"
45 :
46 : // Helper Classes
47 : #include "nsStyleCoord.h"
48 : #include "nsSize.h"
49 : #include "nsHTMLReflowState.h"
50 : #include "nsIServiceManager.h"
51 : #include "nsComponentManagerUtils.h"
52 : #include "nsXPIDLString.h"
53 : #include "nsIAtom.h"
54 : #include "nsReadableUtils.h"
55 : #include "nsUnicharUtils.h"
56 : #include "nsISimpleEnumerator.h"
57 : #include "nsGUIEvent.h"
58 : #include "mozilla/LookAndFeel.h"
59 :
60 : // Interfaces needed to be included
61 : #include "nsPresContext.h"
62 : #include "nsIContextMenuListener.h"
63 : #include "nsIContextMenuListener2.h"
64 : #include "nsITooltipListener.h"
65 : #include "nsIPrivateDOMEvent.h"
66 : #include "nsIDOMNode.h"
67 : #include "nsIDOMNodeList.h"
68 : #include "nsIDOMDocument.h"
69 : #include "nsIDOMDocumentType.h"
70 : #include "nsIDOMElement.h"
71 : #include "Link.h"
72 : #include "nsIDOMSVGElement.h"
73 : #include "nsIDOMSVGTitleElement.h"
74 : #include "nsIDOMEvent.h"
75 : #include "nsIDOMMouseEvent.h"
76 : #include "nsIDOMNSEvent.h"
77 : #include "nsIDOMNamedNodeMap.h"
78 : #include "nsIFormControl.h"
79 : #include "nsIDOMHTMLInputElement.h"
80 : #include "nsIDOMHTMLTextAreaElement.h"
81 : #include "nsIDOMHTMLHtmlElement.h"
82 : #include "nsIDOMHTMLAppletElement.h"
83 : #include "nsIDOMHTMLObjectElement.h"
84 : #include "nsIDOMHTMLEmbedElement.h"
85 : #include "nsIDOMHTMLDocument.h"
86 : #include "nsIImageLoadingContent.h"
87 : #include "nsIWebNavigation.h"
88 : #include "nsIDOMHTMLElement.h"
89 : #include "nsIPresShell.h"
90 : #include "nsPIDOMWindow.h"
91 : #include "nsPIWindowRoot.h"
92 : #include "nsIDOMWindowCollection.h"
93 : #include "nsIWindowWatcher.h"
94 : #include "nsPIWindowWatcher.h"
95 : #include "nsIPrompt.h"
96 : #include "nsRect.h"
97 : #include "nsIWebBrowserChromeFocus.h"
98 : #include "nsIContent.h"
99 : #include "imgIContainer.h"
100 : #include "nsContextMenuInfo.h"
101 : #include "nsPresContext.h"
102 : #include "nsIViewManager.h"
103 : #include "nsIView.h"
104 : #include "nsEventListenerManager.h"
105 : #include "nsIDOMDragEvent.h"
106 : #include "nsIConstraintValidation.h"
107 :
108 : using namespace mozilla;
109 :
110 : //
111 : // GetEventReceiver
112 : //
113 : // A helper routine that navigates the tricky path from a |nsWebBrowser| to
114 : // a |nsIDOMEventTarget| via the window root and chrome event handler.
115 : //
116 : static nsresult
117 0 : GetDOMEventTarget( nsWebBrowser* inBrowser, nsIDOMEventTarget** aTarget)
118 : {
119 0 : NS_ENSURE_ARG_POINTER(inBrowser);
120 :
121 0 : nsCOMPtr<nsIDOMWindow> domWindow;
122 0 : inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
123 0 : NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
124 :
125 0 : nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
126 0 : NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
127 0 : nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot();
128 0 : NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
129 : nsCOMPtr<nsIDOMEventTarget> target =
130 0 : rootWindow->GetChromeEventHandler();
131 0 : NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
132 0 : target.forget(aTarget);
133 :
134 0 : return NS_OK;
135 : }
136 :
137 :
138 : //*****************************************************************************
139 : //*** nsDocShellTreeOwner: Object Management
140 : //*****************************************************************************
141 :
142 0 : nsDocShellTreeOwner::nsDocShellTreeOwner() :
143 : mWebBrowser(nsnull),
144 : mTreeOwner(nsnull),
145 : mPrimaryContentShell(nsnull),
146 : mWebBrowserChrome(nsnull),
147 : mOwnerWin(nsnull),
148 : mOwnerRequestor(nsnull),
149 : mChromeTooltipListener(nsnull),
150 0 : mChromeContextMenuListener(nsnull)
151 : {
152 0 : }
153 :
154 0 : nsDocShellTreeOwner::~nsDocShellTreeOwner()
155 : {
156 0 : RemoveChromeListeners();
157 0 : }
158 :
159 : //*****************************************************************************
160 : // nsDocShellTreeOwner::nsISupports
161 : //*****************************************************************************
162 :
163 0 : NS_IMPL_ADDREF(nsDocShellTreeOwner)
164 0 : NS_IMPL_RELEASE(nsDocShellTreeOwner)
165 :
166 0 : NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
167 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
168 0 : NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
169 0 : NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
170 0 : NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
171 0 : NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
172 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
173 0 : NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
174 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
175 0 : NS_INTERFACE_MAP_END
176 :
177 : //*****************************************************************************
178 : // nsDocShellTreeOwner::nsIInterfaceRequestor
179 : //*****************************************************************************
180 :
181 : NS_IMETHODIMP
182 0 : nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
183 : {
184 0 : NS_ENSURE_ARG_POINTER(aSink);
185 :
186 0 : if(NS_SUCCEEDED(QueryInterface(aIID, aSink)))
187 0 : return NS_OK;
188 :
189 0 : if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
190 0 : if (mWebBrowserChromeWeak != nsnull)
191 0 : return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
192 0 : return mOwnerWin->QueryInterface(aIID, aSink);
193 : }
194 :
195 0 : if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
196 : nsIPrompt *prompt;
197 0 : EnsurePrompter();
198 0 : prompt = mPrompter;
199 0 : if (prompt) {
200 0 : NS_ADDREF(prompt);
201 0 : *aSink = prompt;
202 0 : return NS_OK;
203 : }
204 0 : return NS_NOINTERFACE;
205 : }
206 :
207 0 : if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
208 : nsIAuthPrompt *prompt;
209 0 : EnsureAuthPrompter();
210 0 : prompt = mAuthPrompter;
211 0 : if (prompt) {
212 0 : NS_ADDREF(prompt);
213 0 : *aSink = prompt;
214 0 : return NS_OK;
215 : }
216 0 : return NS_NOINTERFACE;
217 : }
218 :
219 0 : nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor();
220 0 : if (req)
221 0 : return req->GetInterface(aIID, aSink);
222 :
223 0 : return NS_NOINTERFACE;
224 : }
225 :
226 : //*****************************************************************************
227 : // nsDocShellTreeOwner::nsIDocShellTreeOwner
228 : //*****************************************************************************
229 :
230 : NS_IMETHODIMP
231 0 : nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
232 : nsIDocShellTreeItem* aRequestor,
233 : nsIDocShellTreeItem* aOriginalRequestor,
234 : nsIDocShellTreeItem** aFoundItem)
235 : {
236 0 : NS_ENSURE_ARG(aName);
237 0 : NS_ENSURE_ARG_POINTER(aFoundItem);
238 0 : *aFoundItem = nsnull; // if we don't find one, we return NS_OK and a null result
239 : nsresult rv;
240 :
241 0 : nsAutoString name(aName);
242 :
243 0 : if (!mWebBrowser)
244 0 : return NS_OK; // stymied
245 :
246 : /* special cases */
247 0 : if(name.IsEmpty())
248 0 : return NS_OK;
249 0 : if(name.LowerCaseEqualsLiteral("_blank"))
250 0 : return NS_OK;
251 : // _main is an IE target which should be case-insensitive but isn't
252 : // see bug 217886 for details
253 : // XXXbz what if our browser isn't targetable? We need to handle that somehow.
254 0 : if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) {
255 0 : *aFoundItem = mWebBrowser->mDocShellAsItem;
256 0 : NS_IF_ADDREF(*aFoundItem);
257 0 : return NS_OK;
258 : }
259 :
260 0 : if (!SameCOMIdentity(aRequestor, mWebBrowser->mDocShellAsItem)) {
261 : // This isn't a request coming up from our kid, so check with said kid
262 0 : nsISupports* thisSupports = static_cast<nsIDocShellTreeOwner*>(this);
263 : rv =
264 0 : mWebBrowser->mDocShellAsItem->FindItemWithName(aName, thisSupports,
265 0 : aOriginalRequestor, aFoundItem);
266 0 : if (NS_FAILED(rv) || *aFoundItem) {
267 0 : return rv;
268 : }
269 : }
270 :
271 : // next, if we have a parent and it isn't the requestor, ask it
272 0 : if(mTreeOwner) {
273 0 : nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
274 0 : if (mTreeOwner != reqAsTreeOwner)
275 : return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
276 0 : aOriginalRequestor, aFoundItem);
277 0 : return NS_OK;
278 : }
279 :
280 : // finally, failing everything else, search all windows
281 : return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor,
282 0 : aFoundItem);
283 : }
284 :
285 : nsresult
286 0 : nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
287 : nsIDocShellTreeItem* aRequestor,
288 : nsIDocShellTreeItem* aOriginalRequestor,
289 : nsIDocShellTreeItem** aFoundItem)
290 : {
291 : // search for the item across the list of top-level windows
292 0 : nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
293 0 : if (!wwatch)
294 0 : return NS_OK;
295 :
296 0 : return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor,
297 0 : aFoundItem);
298 : }
299 :
300 : void
301 0 : nsDocShellTreeOwner::EnsurePrompter()
302 : {
303 0 : if (mPrompter)
304 0 : return;
305 :
306 0 : nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
307 0 : if (wwatch && mWebBrowser) {
308 0 : nsCOMPtr<nsIDOMWindow> domWindow;
309 0 : mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
310 0 : if (domWindow)
311 0 : wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter));
312 : }
313 : }
314 :
315 : void
316 0 : nsDocShellTreeOwner::EnsureAuthPrompter()
317 : {
318 0 : if (mAuthPrompter)
319 0 : return;
320 :
321 0 : nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
322 0 : if (wwatch && mWebBrowser) {
323 0 : nsCOMPtr<nsIDOMWindow> domWindow;
324 0 : mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
325 0 : if (domWindow)
326 0 : wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter));
327 : }
328 : }
329 :
330 : void
331 0 : nsDocShellTreeOwner::AddToWatcher()
332 : {
333 0 : if (mWebBrowser) {
334 0 : nsCOMPtr<nsIDOMWindow> domWindow;
335 0 : mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
336 0 : if (domWindow) {
337 0 : nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
338 0 : if (wwatch) {
339 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
340 0 : if (webBrowserChrome)
341 0 : wwatch->AddWindow(domWindow, webBrowserChrome);
342 : }
343 : }
344 : }
345 0 : }
346 :
347 : void
348 0 : nsDocShellTreeOwner::RemoveFromWatcher()
349 : {
350 0 : if (mWebBrowser) {
351 0 : nsCOMPtr<nsIDOMWindow> domWindow;
352 0 : mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
353 0 : if (domWindow) {
354 0 : nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
355 0 : if (wwatch)
356 0 : wwatch->RemoveWindow(domWindow);
357 : }
358 : }
359 0 : }
360 :
361 :
362 : NS_IMETHODIMP
363 0 : nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
364 : bool aPrimary, bool aTargetable,
365 : const nsAString& aID)
366 : {
367 0 : if(mTreeOwner)
368 : return mTreeOwner->ContentShellAdded(aContentShell, aPrimary,
369 0 : aTargetable, aID);
370 :
371 0 : if (aPrimary)
372 0 : mPrimaryContentShell = aContentShell;
373 0 : return NS_OK;
374 : }
375 :
376 : NS_IMETHODIMP
377 0 : nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
378 : {
379 0 : if(mTreeOwner)
380 0 : return mTreeOwner->ContentShellRemoved(aContentShell);
381 :
382 0 : if(mPrimaryContentShell == aContentShell)
383 0 : mPrimaryContentShell = nsnull;
384 :
385 0 : return NS_OK;
386 : }
387 :
388 : NS_IMETHODIMP
389 0 : nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell)
390 : {
391 0 : NS_ENSURE_ARG_POINTER(aShell);
392 :
393 0 : if(mTreeOwner)
394 0 : return mTreeOwner->GetPrimaryContentShell(aShell);
395 :
396 0 : *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShellAsItem.get());
397 0 : NS_IF_ADDREF(*aShell);
398 :
399 0 : return NS_OK;
400 : }
401 :
402 : NS_IMETHODIMP
403 0 : nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
404 : PRInt32 aCX, PRInt32 aCY)
405 : {
406 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
407 :
408 0 : NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
409 :
410 0 : if(mTreeOwner)
411 0 : return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
412 :
413 0 : if(aShellItem == mWebBrowser->mDocShellAsItem)
414 0 : return webBrowserChrome->SizeBrowserTo(aCX, aCY);
415 :
416 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
417 0 : NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
418 :
419 0 : nsCOMPtr<nsIDOMDocument> domDocument;
420 0 : webNav->GetDocument(getter_AddRefs(domDocument));
421 0 : NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE);
422 :
423 0 : nsCOMPtr<nsIDOMElement> domElement;
424 0 : domDocument->GetDocumentElement(getter_AddRefs(domElement));
425 0 : NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE);
426 :
427 : // Set the preferred Size
428 : //XXX
429 0 : NS_ERROR("Implement this");
430 : /*
431 : Set the preferred size on the aShellItem.
432 : */
433 :
434 0 : nsRefPtr<nsPresContext> presContext;
435 0 : mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
436 0 : NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
437 :
438 0 : nsIPresShell *presShell = presContext->GetPresShell();
439 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
440 :
441 0 : NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE,
442 : NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE);
443 :
444 0 : nsRect shellArea = presContext->GetVisibleArea();
445 :
446 0 : PRInt32 browserCX = presContext->AppUnitsToDevPixels(shellArea.width);
447 0 : PRInt32 browserCY = presContext->AppUnitsToDevPixels(shellArea.height);
448 :
449 0 : return webBrowserChrome->SizeBrowserTo(browserCX, browserCY);
450 : }
451 :
452 : NS_IMETHODIMP
453 0 : nsDocShellTreeOwner::SetPersistence(bool aPersistPosition,
454 : bool aPersistSize,
455 : bool aPersistSizeMode)
456 : {
457 0 : return NS_ERROR_NOT_IMPLEMENTED;
458 : }
459 :
460 : NS_IMETHODIMP
461 0 : nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition,
462 : bool* aPersistSize,
463 : bool* aPersistSizeMode)
464 : {
465 0 : return NS_ERROR_NOT_IMPLEMENTED;
466 : }
467 :
468 : NS_IMETHODIMP
469 0 : nsDocShellTreeOwner::GetTargetableShellCount(PRUint32* aResult)
470 : {
471 0 : if(mTreeOwner) {
472 0 : mTreeOwner->GetTargetableShellCount(aResult);
473 : } else {
474 0 : *aResult = 0;
475 : }
476 :
477 0 : return NS_OK;
478 : }
479 :
480 : //*****************************************************************************
481 : // nsDocShellTreeOwner::nsIBaseWindow
482 : //*****************************************************************************
483 :
484 :
485 : NS_IMETHODIMP
486 0 : nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
487 : nsIWidget* aParentWidget, PRInt32 aX,
488 : PRInt32 aY, PRInt32 aCX, PRInt32 aCY)
489 : {
490 0 : return NS_ERROR_NULL_POINTER;
491 : }
492 :
493 : NS_IMETHODIMP
494 0 : nsDocShellTreeOwner::Create()
495 : {
496 0 : return NS_ERROR_NULL_POINTER;
497 : }
498 :
499 : NS_IMETHODIMP
500 0 : nsDocShellTreeOwner::Destroy()
501 : {
502 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
503 0 : if (webBrowserChrome)
504 : {
505 0 : return webBrowserChrome->DestroyBrowserWindow();
506 : }
507 :
508 0 : return NS_ERROR_NULL_POINTER;
509 : }
510 :
511 : NS_IMETHODIMP
512 0 : nsDocShellTreeOwner::SetPosition(PRInt32 aX, PRInt32 aY)
513 : {
514 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
515 0 : if (ownerWin)
516 : {
517 0 : return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
518 0 : aX, aY, 0, 0);
519 : }
520 0 : return NS_ERROR_NULL_POINTER;
521 : }
522 :
523 : NS_IMETHODIMP
524 0 : nsDocShellTreeOwner::GetPosition(PRInt32* aX, PRInt32* aY)
525 : {
526 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
527 0 : if (ownerWin)
528 : {
529 0 : return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
530 0 : aX, aY, nsnull, nsnull);
531 : }
532 0 : return NS_ERROR_NULL_POINTER;
533 : }
534 :
535 : NS_IMETHODIMP
536 0 : nsDocShellTreeOwner::SetSize(PRInt32 aCX, PRInt32 aCY, bool aRepaint)
537 : {
538 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
539 0 : if (ownerWin)
540 : {
541 0 : return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
542 0 : 0, 0, aCX, aCY);
543 : }
544 0 : return NS_ERROR_NULL_POINTER;
545 : }
546 :
547 : NS_IMETHODIMP
548 0 : nsDocShellTreeOwner::GetSize(PRInt32* aCX, PRInt32* aCY)
549 : {
550 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
551 0 : if (ownerWin)
552 : {
553 0 : return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
554 0 : nsnull, nsnull, aCX, aCY);
555 : }
556 0 : return NS_ERROR_NULL_POINTER;
557 : }
558 :
559 : NS_IMETHODIMP
560 0 : nsDocShellTreeOwner::SetPositionAndSize(PRInt32 aX, PRInt32 aY, PRInt32 aCX,
561 : PRInt32 aCY, bool aRepaint)
562 : {
563 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
564 0 : if (ownerWin)
565 : {
566 0 : return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
567 : nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
568 0 : aX, aY, aCX, aCY);
569 : }
570 0 : return NS_ERROR_NULL_POINTER;
571 : }
572 :
573 : NS_IMETHODIMP
574 0 : nsDocShellTreeOwner::GetPositionAndSize(PRInt32* aX, PRInt32* aY, PRInt32* aCX,
575 : PRInt32* aCY)
576 : {
577 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
578 0 : if (ownerWin)
579 : {
580 0 : return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
581 : nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
582 0 : aX, aY, aCX, aCY);
583 : }
584 0 : return NS_ERROR_NULL_POINTER;
585 : }
586 :
587 : NS_IMETHODIMP
588 0 : nsDocShellTreeOwner::Repaint(bool aForce)
589 : {
590 0 : return NS_ERROR_NULL_POINTER;
591 : }
592 :
593 : NS_IMETHODIMP
594 0 : nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget)
595 : {
596 0 : return NS_ERROR_NULL_POINTER;
597 : }
598 :
599 : NS_IMETHODIMP
600 0 : nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget)
601 : {
602 0 : return NS_ERROR_NULL_POINTER;
603 : }
604 :
605 : NS_IMETHODIMP
606 0 : nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
607 : {
608 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
609 0 : if (ownerWin)
610 : {
611 0 : return ownerWin->GetSiteWindow(aParentNativeWindow);
612 : }
613 0 : return NS_ERROR_NULL_POINTER;
614 : }
615 :
616 : NS_IMETHODIMP
617 0 : nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
618 : {
619 0 : return NS_ERROR_NULL_POINTER;
620 : }
621 :
622 : NS_IMETHODIMP
623 0 : nsDocShellTreeOwner::GetVisibility(bool* aVisibility)
624 : {
625 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
626 0 : if (ownerWin)
627 : {
628 0 : return ownerWin->GetVisibility(aVisibility);
629 : }
630 0 : return NS_ERROR_NULL_POINTER;
631 : }
632 :
633 : NS_IMETHODIMP
634 0 : nsDocShellTreeOwner::SetVisibility(bool aVisibility)
635 : {
636 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
637 0 : if (ownerWin)
638 : {
639 0 : return ownerWin->SetVisibility(aVisibility);
640 : }
641 0 : return NS_ERROR_NULL_POINTER;
642 : }
643 :
644 : NS_IMETHODIMP
645 0 : nsDocShellTreeOwner::GetEnabled(bool *aEnabled)
646 : {
647 0 : NS_ENSURE_ARG_POINTER(aEnabled);
648 0 : *aEnabled = true;
649 0 : return NS_ERROR_NOT_IMPLEMENTED;
650 : }
651 :
652 : NS_IMETHODIMP
653 0 : nsDocShellTreeOwner::SetEnabled(bool aEnabled)
654 : {
655 0 : return NS_ERROR_NOT_IMPLEMENTED;
656 : }
657 :
658 : NS_IMETHODIMP
659 0 : nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget)
660 : {
661 0 : return NS_ERROR_NULL_POINTER;
662 : }
663 :
664 : NS_IMETHODIMP
665 0 : nsDocShellTreeOwner::SetFocus()
666 : {
667 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
668 0 : if (ownerWin)
669 : {
670 0 : return ownerWin->SetFocus();
671 : }
672 0 : return NS_ERROR_NULL_POINTER;
673 : }
674 :
675 : NS_IMETHODIMP
676 0 : nsDocShellTreeOwner::GetTitle(PRUnichar** aTitle)
677 : {
678 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
679 0 : if (ownerWin)
680 : {
681 0 : return ownerWin->GetTitle(aTitle);
682 : }
683 0 : return NS_ERROR_NULL_POINTER;
684 : }
685 :
686 : NS_IMETHODIMP
687 0 : nsDocShellTreeOwner::SetTitle(const PRUnichar* aTitle)
688 : {
689 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
690 0 : if (ownerWin)
691 : {
692 0 : return ownerWin->SetTitle(aTitle);
693 : }
694 0 : return NS_ERROR_NULL_POINTER;
695 : }
696 :
697 :
698 : //*****************************************************************************
699 : // nsDocShellTreeOwner::nsIWebProgressListener
700 : //*****************************************************************************
701 :
702 :
703 : NS_IMETHODIMP
704 0 : nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress,
705 : nsIRequest* aRequest,
706 : PRInt32 aCurSelfProgress,
707 : PRInt32 aMaxSelfProgress,
708 : PRInt32 aCurTotalProgress,
709 : PRInt32 aMaxTotalProgress)
710 : {
711 : // In the absence of DOM document creation event, this method is the
712 : // most convenient place to install the mouse listener on the
713 : // DOM document.
714 0 : return AddChromeListeners();
715 : }
716 :
717 : NS_IMETHODIMP
718 0 : nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress,
719 : nsIRequest* aRequest,
720 : PRUint32 aProgressStateFlags,
721 : nsresult aStatus)
722 : {
723 0 : return NS_OK;
724 : }
725 :
726 : NS_IMETHODIMP
727 0 : nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
728 : nsIRequest* aRequest,
729 : nsIURI* aURI,
730 : PRUint32 aFlags)
731 : {
732 0 : return NS_OK;
733 : }
734 :
735 : NS_IMETHODIMP
736 0 : nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
737 : nsIRequest* aRequest,
738 : nsresult aStatus,
739 : const PRUnichar* aMessage)
740 : {
741 0 : return NS_OK;
742 : }
743 :
744 : NS_IMETHODIMP
745 0 : nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress,
746 : nsIRequest *aRequest,
747 : PRUint32 state)
748 : {
749 0 : return NS_OK;
750 : }
751 :
752 :
753 : //*****************************************************************************
754 : // nsDocShellTreeOwner: Helpers
755 : //*****************************************************************************
756 :
757 : //*****************************************************************************
758 : // nsDocShellTreeOwner: Accessors
759 : //*****************************************************************************
760 :
761 : void
762 0 : nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
763 : {
764 0 : if ( !aWebBrowser )
765 0 : RemoveChromeListeners();
766 0 : if (aWebBrowser != mWebBrowser) {
767 0 : mPrompter = 0;
768 0 : mAuthPrompter = 0;
769 : }
770 :
771 0 : mWebBrowser = aWebBrowser;
772 0 : }
773 :
774 : nsWebBrowser *
775 0 : nsDocShellTreeOwner::WebBrowser()
776 : {
777 0 : return mWebBrowser;
778 : }
779 :
780 : NS_IMETHODIMP
781 0 : nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
782 : {
783 0 : if(aTreeOwner) {
784 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner));
785 0 : NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG);
786 0 : NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG);
787 0 : mTreeOwner = aTreeOwner;
788 : }
789 : else {
790 0 : mTreeOwner = nsnull;
791 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
792 0 : if (!webBrowserChrome)
793 0 : NS_ENSURE_SUCCESS(SetWebBrowserChrome(nsnull), NS_ERROR_FAILURE);
794 : }
795 :
796 0 : return NS_OK;
797 : }
798 :
799 : NS_IMETHODIMP
800 0 : nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome)
801 : {
802 0 : if(!aWebBrowserChrome) {
803 0 : mWebBrowserChrome = nsnull;
804 0 : mOwnerWin = nsnull;
805 0 : mOwnerRequestor = nsnull;
806 0 : mWebBrowserChromeWeak = 0;
807 : } else {
808 : nsCOMPtr<nsISupportsWeakReference> supportsweak =
809 0 : do_QueryInterface(aWebBrowserChrome);
810 0 : if (supportsweak) {
811 0 : supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak));
812 : } else {
813 0 : nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome));
814 0 : nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome));
815 :
816 : // it's ok for ownerWin or requestor to be null.
817 0 : mWebBrowserChrome = aWebBrowserChrome;
818 0 : mOwnerWin = ownerWin;
819 0 : mOwnerRequestor = requestor;
820 : }
821 : }
822 0 : return NS_OK;
823 : }
824 :
825 :
826 : //
827 : // AddChromeListeners
828 : //
829 : // Hook up things to the chrome like context menus and tooltips, if the chrome
830 : // has implemented the right interfaces.
831 : //
832 : NS_IMETHODIMP
833 0 : nsDocShellTreeOwner::AddChromeListeners()
834 : {
835 0 : nsresult rv = NS_OK;
836 :
837 0 : nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
838 0 : if (!webBrowserChrome)
839 0 : return NS_ERROR_FAILURE;
840 :
841 : // install tooltips
842 0 : if ( !mChromeTooltipListener ) {
843 : nsCOMPtr<nsITooltipListener>
844 0 : tooltipListener(do_QueryInterface(webBrowserChrome));
845 0 : if ( tooltipListener ) {
846 : mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser,
847 0 : webBrowserChrome);
848 0 : if ( mChromeTooltipListener ) {
849 0 : NS_ADDREF(mChromeTooltipListener);
850 0 : rv = mChromeTooltipListener->AddChromeListeners();
851 : }
852 : else
853 0 : rv = NS_ERROR_OUT_OF_MEMORY;
854 : }
855 : }
856 :
857 : // install context menus
858 0 : if ( !mChromeContextMenuListener ) {
859 : nsCOMPtr<nsIContextMenuListener2>
860 0 : contextListener2(do_QueryInterface(webBrowserChrome));
861 : nsCOMPtr<nsIContextMenuListener>
862 0 : contextListener(do_QueryInterface(webBrowserChrome));
863 0 : if ( contextListener2 || contextListener ) {
864 : mChromeContextMenuListener =
865 0 : new ChromeContextMenuListener(mWebBrowser, webBrowserChrome);
866 0 : if ( mChromeContextMenuListener ) {
867 0 : NS_ADDREF(mChromeContextMenuListener);
868 0 : rv = mChromeContextMenuListener->AddChromeListeners();
869 : }
870 : else
871 0 : rv = NS_ERROR_OUT_OF_MEMORY;
872 : }
873 : }
874 :
875 : // register dragover and drop event listeners with the listener manager
876 0 : nsCOMPtr<nsIDOMEventTarget> target;
877 0 : GetDOMEventTarget(mWebBrowser, getter_AddRefs(target));
878 :
879 0 : nsEventListenerManager* elmP = target->GetListenerManager(true);
880 0 : if (elmP) {
881 0 : elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"),
882 : NS_EVENT_FLAG_BUBBLE |
883 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
884 0 : elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"),
885 : NS_EVENT_FLAG_BUBBLE |
886 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
887 : }
888 :
889 0 : return rv;
890 :
891 : } // AddChromeListeners
892 :
893 :
894 : NS_IMETHODIMP
895 0 : nsDocShellTreeOwner::RemoveChromeListeners()
896 : {
897 0 : if ( mChromeTooltipListener ) {
898 0 : mChromeTooltipListener->RemoveChromeListeners();
899 0 : NS_RELEASE(mChromeTooltipListener);
900 : }
901 0 : if ( mChromeContextMenuListener ) {
902 0 : mChromeContextMenuListener->RemoveChromeListeners();
903 0 : NS_RELEASE(mChromeContextMenuListener);
904 : }
905 :
906 0 : nsCOMPtr<nsIDOMEventTarget> piTarget;
907 0 : GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget));
908 0 : if (!piTarget)
909 0 : return NS_OK;
910 :
911 0 : nsEventListenerManager* elmP = piTarget->GetListenerManager(true);
912 0 : if (elmP)
913 : {
914 0 : elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"),
915 : NS_EVENT_FLAG_BUBBLE |
916 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
917 0 : elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"),
918 : NS_EVENT_FLAG_BUBBLE |
919 0 : NS_EVENT_FLAG_SYSTEM_EVENT);
920 : }
921 :
922 0 : return NS_OK;
923 : }
924 :
925 : NS_IMETHODIMP
926 0 : nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent)
927 : {
928 0 : nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
929 0 : NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG);
930 :
931 0 : nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
932 0 : if (domNSEvent) {
933 : bool defaultPrevented;
934 0 : domNSEvent->GetPreventDefault(&defaultPrevented);
935 0 : if (defaultPrevented)
936 0 : return NS_OK;
937 : }
938 :
939 0 : nsCOMPtr<nsIDroppedLinkHandler> handler = do_GetService("@mozilla.org/content/dropped-link-handler;1");
940 0 : if (handler) {
941 0 : nsAutoString eventType;
942 0 : aEvent->GetType(eventType);
943 0 : if (eventType.EqualsLiteral("dragover")) {
944 : bool canDropLink;
945 0 : handler->CanDropLink(dragEvent, false, &canDropLink);
946 0 : if (canDropLink)
947 0 : aEvent->PreventDefault();
948 : }
949 0 : else if (eventType.EqualsLiteral("drop")) {
950 0 : nsIWebNavigation* webnav = static_cast<nsIWebNavigation *>(mWebBrowser);
951 :
952 0 : nsAutoString link, name;
953 0 : if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) {
954 0 : if (!link.IsEmpty()) {
955 0 : webnav->LoadURI(link.get(), 0, nsnull, nsnull, nsnull);
956 : }
957 : }
958 : else {
959 0 : aEvent->StopPropagation();
960 0 : aEvent->PreventDefault();
961 : }
962 : }
963 : }
964 :
965 0 : return NS_OK;
966 : }
967 :
968 : already_AddRefed<nsIWebBrowserChrome>
969 0 : nsDocShellTreeOwner::GetWebBrowserChrome()
970 : {
971 0 : nsCOMPtr<nsIWebBrowserChrome> chrome;
972 0 : if (mWebBrowserChromeWeak) {
973 0 : chrome = do_QueryReferent(mWebBrowserChromeWeak);
974 0 : } else if (mWebBrowserChrome) {
975 0 : chrome = mWebBrowserChrome;
976 : }
977 0 : return chrome.forget();
978 : }
979 :
980 : already_AddRefed<nsIEmbeddingSiteWindow>
981 0 : nsDocShellTreeOwner::GetOwnerWin()
982 : {
983 0 : nsCOMPtr<nsIEmbeddingSiteWindow> win;
984 0 : if (mWebBrowserChromeWeak) {
985 0 : win = do_QueryReferent(mWebBrowserChromeWeak);
986 0 : } else if (mOwnerWin) {
987 0 : win = mOwnerWin;
988 : }
989 0 : return win.forget();
990 : }
991 :
992 : already_AddRefed<nsIInterfaceRequestor>
993 0 : nsDocShellTreeOwner::GetOwnerRequestor()
994 : {
995 0 : nsCOMPtr<nsIInterfaceRequestor> req;
996 0 : if (mWebBrowserChromeWeak) {
997 0 : req = do_QueryReferent(mWebBrowserChromeWeak);
998 0 : } else if (mOwnerRequestor) {
999 0 : req = mOwnerRequestor;
1000 : }
1001 0 : return req.forget();
1002 : }
1003 :
1004 :
1005 : ///////////////////////////////////////////////////////////////////////////////
1006 : // DefaultTooltipTextProvider
1007 :
1008 : class DefaultTooltipTextProvider : public nsITooltipTextProvider
1009 0 : {
1010 : public:
1011 : DefaultTooltipTextProvider();
1012 :
1013 : NS_DECL_ISUPPORTS
1014 : NS_DECL_NSITOOLTIPTEXTPROVIDER
1015 :
1016 : protected:
1017 : nsCOMPtr<nsIAtom> mTag_dialog;
1018 : nsCOMPtr<nsIAtom> mTag_dialogheader;
1019 : nsCOMPtr<nsIAtom> mTag_window;
1020 : };
1021 :
1022 0 : NS_IMPL_THREADSAFE_ISUPPORTS1(DefaultTooltipTextProvider, nsITooltipTextProvider)
1023 :
1024 0 : DefaultTooltipTextProvider::DefaultTooltipTextProvider()
1025 : {
1026 : // There are certain element types which we don't want to use
1027 : // as tool tip text.
1028 0 : mTag_dialog = do_GetAtom("dialog");
1029 0 : mTag_dialogheader = do_GetAtom("dialogheader");
1030 0 : mTag_window = do_GetAtom("window");
1031 0 : }
1032 :
1033 : //
1034 : // UseSVGTitle
1035 : //
1036 : // A helper routine that determines whether we're still interested
1037 : // in SVG titles. We need to stop at the SVG root element that
1038 : // has a document node parent
1039 : //
1040 : static bool
1041 0 : UseSVGTitle(nsIDOMElement *currElement)
1042 : {
1043 0 : nsCOMPtr<nsIDOMSVGElement> svgContent(do_QueryInterface(currElement));
1044 0 : if (!svgContent)
1045 0 : return false;
1046 :
1047 0 : nsCOMPtr<nsIDOMNode> parent;
1048 0 : currElement->GetParentNode(getter_AddRefs(parent));
1049 0 : if (!parent)
1050 0 : return false;
1051 :
1052 : PRUint16 nodeType;
1053 0 : nsresult rv = parent->GetNodeType(&nodeType);
1054 :
1055 0 : return NS_SUCCEEDED(rv) && nodeType != nsIDOMNode::DOCUMENT_NODE;
1056 : }
1057 :
1058 : /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
1059 : NS_IMETHODIMP
1060 0 : DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, PRUnichar **aText,
1061 : bool *_retval)
1062 : {
1063 0 : NS_ENSURE_ARG_POINTER(aNode);
1064 0 : NS_ENSURE_ARG_POINTER(aText);
1065 :
1066 0 : nsString outText;
1067 :
1068 0 : bool lookingForSVGTitle = true;
1069 0 : bool found = false;
1070 0 : nsCOMPtr<nsIDOMNode> current ( aNode );
1071 :
1072 : // If the element implement the constraint validation API and has no title,
1073 : // show the validation message, if any.
1074 0 : nsCOMPtr<nsIConstraintValidation> cvElement = do_QueryInterface(current);
1075 0 : if (cvElement) {
1076 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(cvElement);
1077 0 : nsCOMPtr<nsIAtom> titleAtom = do_GetAtom("title");
1078 :
1079 0 : nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(content);
1080 0 : bool formHasNoValidate = false;
1081 0 : mozilla::dom::Element* form = formControl->GetFormElement();
1082 0 : if (form) {
1083 0 : nsCOMPtr<nsIAtom> noValidateAtom = do_GetAtom("novalidate");
1084 0 : formHasNoValidate = form->HasAttr(kNameSpaceID_None, noValidateAtom);
1085 : }
1086 :
1087 0 : if (!content->HasAttr(kNameSpaceID_None, titleAtom) &&
1088 0 : !formHasNoValidate) {
1089 0 : cvElement->GetValidationMessage(outText);
1090 0 : found = !outText.IsEmpty();
1091 : }
1092 : }
1093 :
1094 0 : while ( !found && current ) {
1095 0 : nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) );
1096 0 : if ( currElement ) {
1097 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
1098 0 : if (content) {
1099 0 : nsIAtom *tagAtom = content->Tag();
1100 0 : if (tagAtom != mTag_dialog &&
1101 0 : tagAtom != mTag_dialogheader &&
1102 0 : tagAtom != mTag_window) {
1103 : // first try the normal title attribute...
1104 0 : currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
1105 0 : if ( outText.Length() )
1106 0 : found = true;
1107 : else {
1108 : // ...ok, that didn't work, try it in the XLink namespace
1109 0 : NS_NAMED_LITERAL_STRING(xlinkNS, "http://www.w3.org/1999/xlink");
1110 0 : nsCOMPtr<mozilla::dom::Link> linkContent(do_QueryInterface(currElement));
1111 0 : if (linkContent) {
1112 0 : nsCOMPtr<nsIURI> uri(linkContent->GetURIExternal());
1113 0 : if (uri) {
1114 0 : currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText);
1115 0 : if ( outText.Length() )
1116 0 : found = true;
1117 : }
1118 : }
1119 : else {
1120 0 : if (lookingForSVGTitle) {
1121 0 : lookingForSVGTitle = UseSVGTitle(currElement);
1122 : }
1123 0 : if (lookingForSVGTitle) {
1124 0 : nsCOMPtr<nsIDOMNodeList>childNodes;
1125 0 : aNode->GetChildNodes(getter_AddRefs(childNodes));
1126 : PRUint32 childNodeCount;
1127 0 : childNodes->GetLength(&childNodeCount);
1128 0 : for (PRUint32 i = 0; i < childNodeCount; i++) {
1129 0 : nsCOMPtr<nsIDOMNode>childNode;
1130 0 : childNodes->Item(i, getter_AddRefs(childNode));
1131 0 : nsCOMPtr<nsIDOMSVGTitleElement> titleElement(do_QueryInterface(childNode));
1132 0 : if (titleElement) {
1133 0 : titleElement->GetTextContent(outText);
1134 0 : if ( outText.Length() )
1135 0 : found = true;
1136 : break;
1137 : }
1138 : }
1139 : }
1140 : }
1141 : }
1142 : }
1143 : }
1144 : }
1145 :
1146 : // not found here, walk up to the parent and keep trying
1147 0 : if ( !found ) {
1148 0 : nsCOMPtr<nsIDOMNode> temp ( current );
1149 0 : temp->GetParentNode(getter_AddRefs(current));
1150 : }
1151 : } // while not found
1152 :
1153 0 : *_retval = found;
1154 0 : *aText = (found) ? ToNewUnicode(outText) : nsnull;
1155 :
1156 0 : return NS_OK;
1157 : }
1158 :
1159 : ///////////////////////////////////////////////////////////////////////////////
1160 :
1161 0 : NS_IMPL_ISUPPORTS1(ChromeTooltipListener, nsIDOMEventListener)
1162 :
1163 : //
1164 : // ChromeTooltipListener ctor
1165 : //
1166 :
1167 0 : ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
1168 : nsIWebBrowserChrome* inChrome)
1169 : : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
1170 : mTooltipListenerInstalled(false),
1171 : mMouseClientX(0), mMouseClientY(0),
1172 0 : mShowingTooltip(false)
1173 : {
1174 0 : mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
1175 0 : if (!mTooltipTextProvider) {
1176 0 : nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
1177 0 : mTooltipTextProvider = do_QueryInterface(pProvider);
1178 : }
1179 0 : } // ctor
1180 :
1181 :
1182 : //
1183 : // ChromeTooltipListener dtor
1184 : //
1185 0 : ChromeTooltipListener::~ChromeTooltipListener()
1186 : {
1187 :
1188 0 : } // dtor
1189 :
1190 :
1191 : //
1192 : // AddChromeListeners
1193 : //
1194 : // Hook up things to the chrome like context menus and tooltips, if the chrome
1195 : // has implemented the right interfaces.
1196 : //
1197 : NS_IMETHODIMP
1198 0 : ChromeTooltipListener::AddChromeListeners()
1199 : {
1200 0 : if (!mEventTarget)
1201 0 : GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1202 :
1203 : // Register the appropriate events for tooltips, but only if
1204 : // the embedding chrome cares.
1205 0 : nsresult rv = NS_OK;
1206 0 : nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1207 0 : if ( tooltipListener && !mTooltipListenerInstalled ) {
1208 0 : rv = AddTooltipListener();
1209 0 : if ( NS_FAILED(rv) )
1210 0 : return rv;
1211 : }
1212 :
1213 0 : return rv;
1214 :
1215 : } // AddChromeListeners
1216 :
1217 :
1218 : //
1219 : // AddTooltipListener
1220 : //
1221 : // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
1222 : // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
1223 : // of how many succeed so we can clean up correctly in Release().
1224 : //
1225 : NS_IMETHODIMP
1226 0 : ChromeTooltipListener::AddTooltipListener()
1227 : {
1228 0 : if (mEventTarget) {
1229 0 : nsresult rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"),
1230 0 : this, false, false);
1231 0 : NS_ENSURE_SUCCESS(rv, rv);
1232 0 : rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
1233 0 : false, false);
1234 0 : NS_ENSURE_SUCCESS(rv, rv);
1235 0 : rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this,
1236 0 : false, false);
1237 0 : NS_ENSURE_SUCCESS(rv, rv);
1238 0 : rv = mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
1239 0 : false, false);
1240 0 : NS_ENSURE_SUCCESS(rv, rv);
1241 :
1242 0 : mTooltipListenerInstalled = true;
1243 : }
1244 :
1245 0 : return NS_OK;
1246 : }
1247 :
1248 :
1249 : //
1250 : // RemoveChromeListeners
1251 : //
1252 : // Unsubscribe from the various things we've hooked up to the window root.
1253 : //
1254 : NS_IMETHODIMP
1255 0 : ChromeTooltipListener::RemoveChromeListeners ( )
1256 : {
1257 0 : HideTooltip();
1258 :
1259 0 : if ( mTooltipListenerInstalled )
1260 0 : RemoveTooltipListener();
1261 :
1262 0 : mEventTarget = nsnull;
1263 :
1264 : // it really doesn't matter if these fail...
1265 0 : return NS_OK;
1266 :
1267 : } // RemoveChromeTooltipListeners
1268 :
1269 :
1270 :
1271 : //
1272 : // RemoveTooltipListener
1273 : //
1274 : // Unsubscribe from all the various tooltip events that we were listening to
1275 : //
1276 : NS_IMETHODIMP
1277 0 : ChromeTooltipListener::RemoveTooltipListener()
1278 : {
1279 0 : if (mEventTarget) {
1280 : nsresult rv =
1281 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this,
1282 0 : false);
1283 0 : NS_ENSURE_SUCCESS(rv, rv);
1284 0 : rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"),
1285 0 : this, false);
1286 0 : NS_ENSURE_SUCCESS(rv, rv);
1287 0 : rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this,
1288 0 : false);
1289 0 : NS_ENSURE_SUCCESS(rv, rv);
1290 0 : rv = mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
1291 0 : this, false);
1292 0 : NS_ENSURE_SUCCESS(rv, rv);
1293 :
1294 0 : mTooltipListenerInstalled = false;
1295 : }
1296 :
1297 0 : return NS_OK;
1298 : }
1299 :
1300 : NS_IMETHODIMP
1301 0 : ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
1302 : {
1303 0 : nsAutoString eventType;
1304 0 : aEvent->GetType(eventType);
1305 :
1306 0 : if (eventType.EqualsLiteral("keydown") ||
1307 0 : eventType.EqualsLiteral("mousedown") ||
1308 0 : eventType.EqualsLiteral("mouseout"))
1309 0 : return HideTooltip();
1310 0 : if (eventType.EqualsLiteral("mousemove"))
1311 0 : return MouseMove(aEvent);
1312 :
1313 0 : NS_ERROR("Unexpected event type");
1314 0 : return NS_OK;
1315 : }
1316 :
1317 : //
1318 : // MouseMove
1319 : //
1320 : // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
1321 : // timer fires, we cache the node in |mPossibleTooltipNode|.
1322 : //
1323 : nsresult
1324 0 : ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
1325 : {
1326 0 : nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
1327 0 : if (!mouseEvent)
1328 0 : return NS_OK;
1329 :
1330 : // stash the coordinates of the event so that we can still get back to it from within the
1331 : // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
1332 : // even when the mouse doesn't change position! To get around this, we make sure the
1333 : // mouse has really moved before proceeding.
1334 : PRInt32 newMouseX, newMouseY;
1335 0 : mouseEvent->GetClientX(&newMouseX);
1336 0 : mouseEvent->GetClientY(&newMouseY);
1337 0 : if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
1338 0 : return NS_OK;
1339 0 : mMouseClientX = newMouseX; mMouseClientY = newMouseY;
1340 0 : mouseEvent->GetScreenX(&mMouseScreenX);
1341 0 : mouseEvent->GetScreenY(&mMouseScreenY);
1342 :
1343 : // We want to close the tip if it is being displayed and the mouse moves. Recall
1344 : // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
1345 : // moves, we want to make sure we reset the timer to show it, so that the delay
1346 : // is from when the mouse stops moving, not when it enters the element.
1347 0 : if ( mShowingTooltip )
1348 0 : return HideTooltip();
1349 0 : if ( mTooltipTimer )
1350 0 : mTooltipTimer->Cancel();
1351 :
1352 0 : mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
1353 0 : if ( mTooltipTimer ) {
1354 0 : nsCOMPtr<nsIDOMEventTarget> eventTarget;
1355 0 : aMouseEvent->GetTarget(getter_AddRefs(eventTarget));
1356 0 : if ( eventTarget )
1357 0 : mPossibleTooltipNode = do_QueryInterface(eventTarget);
1358 0 : if ( mPossibleTooltipNode ) {
1359 : nsresult rv =
1360 0 : mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
1361 0 : LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
1362 0 : nsITimer::TYPE_ONE_SHOT);
1363 0 : if (NS_FAILED(rv))
1364 0 : mPossibleTooltipNode = nsnull;
1365 : }
1366 : }
1367 : else
1368 0 : NS_WARNING ( "Could not create a timer for tooltip tracking" );
1369 :
1370 0 : return NS_OK;
1371 :
1372 : } // MouseMove
1373 :
1374 :
1375 : //
1376 : // ShowTooltip
1377 : //
1378 : // Tell the registered chrome that they should show the tooltip
1379 : //
1380 : NS_IMETHODIMP
1381 0 : ChromeTooltipListener::ShowTooltip(PRInt32 inXCoords, PRInt32 inYCoords,
1382 : const nsAString & inTipText)
1383 : {
1384 0 : nsresult rv = NS_OK;
1385 :
1386 : // do the work to call the client
1387 0 : nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1388 0 : if ( tooltipListener ) {
1389 0 : rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() );
1390 0 : if ( NS_SUCCEEDED(rv) )
1391 0 : mShowingTooltip = true;
1392 : }
1393 :
1394 0 : return rv;
1395 :
1396 : } // ShowTooltip
1397 :
1398 :
1399 : //
1400 : // HideTooltip
1401 : //
1402 : // Tell the registered chrome that they should rollup the tooltip
1403 : // NOTE: This routine is safe to call even if the popup is already closed.
1404 : //
1405 : NS_IMETHODIMP
1406 0 : ChromeTooltipListener::HideTooltip()
1407 : {
1408 0 : nsresult rv = NS_OK;
1409 :
1410 : // shut down the relevant timers
1411 0 : if ( mTooltipTimer ) {
1412 0 : mTooltipTimer->Cancel();
1413 0 : mTooltipTimer = nsnull;
1414 : // release tooltip target
1415 0 : mPossibleTooltipNode = nsnull;
1416 : }
1417 0 : if ( mAutoHideTimer ) {
1418 0 : mAutoHideTimer->Cancel();
1419 0 : mAutoHideTimer = nsnull;
1420 : }
1421 :
1422 : // if we're showing the tip, tell the chrome to hide it
1423 0 : if ( mShowingTooltip ) {
1424 0 : nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1425 0 : if ( tooltipListener ) {
1426 0 : rv = tooltipListener->OnHideTooltip ( );
1427 0 : if ( NS_SUCCEEDED(rv) )
1428 0 : mShowingTooltip = false;
1429 : }
1430 : }
1431 :
1432 0 : return rv;
1433 :
1434 : } // HideTooltip
1435 :
1436 :
1437 : //
1438 : // sTooltipCallback
1439 : //
1440 : // A timer callback, fired when the mouse has hovered inside of a frame for the
1441 : // appropriate amount of time. Getting to this point means that we should show the
1442 : // tooltip, but only after we determine there is an appropriate TITLE element.
1443 : //
1444 : // This relies on certain things being cached into the |aChromeTooltipListener| object passed to
1445 : // us by the timer:
1446 : // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1447 : // -- the dom node the user hovered over (mPossibleTooltipNode)
1448 : //
1449 : void
1450 0 : ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
1451 : void *aChromeTooltipListener)
1452 : {
1453 : ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>
1454 0 : (aChromeTooltipListener);
1455 0 : if ( self && self->mPossibleTooltipNode ){
1456 : // The actual coordinates we want to put the tooltip at are relative to the
1457 : // toplevel docshell of our mWebBrowser. We know what the screen
1458 : // coordinates of the mouse event were, which means we just need the screen
1459 : // coordinates of the docshell. Unfortunately, there is no good way to
1460 : // find those short of groveling for the presentation in that docshell and
1461 : // finding the screen coords of its toplevel widget...
1462 : nsCOMPtr<nsIDocShell> docShell =
1463 0 : do_GetInterface(static_cast<nsIWebBrowser*>(self->mWebBrowser));
1464 0 : nsCOMPtr<nsIPresShell> shell;
1465 0 : if (docShell) {
1466 0 : docShell->GetPresShell(getter_AddRefs(shell));
1467 : }
1468 :
1469 0 : nsIWidget* widget = nsnull;
1470 0 : if (shell) {
1471 0 : nsIViewManager* vm = shell->GetViewManager();
1472 0 : if (vm) {
1473 0 : nsIView* view = vm->GetRootView();
1474 0 : if (view) {
1475 0 : nsPoint offset;
1476 0 : widget = view->GetNearestWidget(&offset);
1477 : }
1478 : }
1479 : }
1480 :
1481 0 : if (!widget) {
1482 : // release tooltip target if there is one, NO MATTER WHAT
1483 0 : self->mPossibleTooltipNode = nsnull;
1484 : return;
1485 : }
1486 :
1487 : // if there is text associated with the node, show the tip and fire
1488 : // off a timer to auto-hide it.
1489 :
1490 0 : nsXPIDLString tooltipText;
1491 0 : if (self->mTooltipTextProvider) {
1492 0 : bool textFound = false;
1493 :
1494 0 : self->mTooltipTextProvider->GetNodeText(
1495 0 : self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
1496 :
1497 0 : if (textFound) {
1498 0 : nsString tipText(tooltipText);
1499 0 : self->CreateAutoHideTimer();
1500 0 : nsIntPoint screenDot = widget->WidgetToScreenOffset();
1501 : self->ShowTooltip (self->mMouseScreenX - screenDot.x,
1502 : self->mMouseScreenY - screenDot.y,
1503 0 : tipText);
1504 : }
1505 : }
1506 :
1507 : // release tooltip target if there is one, NO MATTER WHAT
1508 0 : self->mPossibleTooltipNode = nsnull;
1509 : } // if "self" data valid
1510 :
1511 : } // sTooltipCallback
1512 :
1513 :
1514 : //
1515 : // CreateAutoHideTimer
1516 : //
1517 : // Create a new timer to see if we should auto-hide. It's ok if this fails.
1518 : //
1519 : void
1520 0 : ChromeTooltipListener::CreateAutoHideTimer()
1521 : {
1522 : // just to be anal (er, safe)
1523 0 : if ( mAutoHideTimer ) {
1524 0 : mAutoHideTimer->Cancel();
1525 0 : mAutoHideTimer = nsnull;
1526 : }
1527 :
1528 0 : mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
1529 0 : if ( mAutoHideTimer )
1530 0 : mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime,
1531 0 : nsITimer::TYPE_ONE_SHOT);
1532 :
1533 0 : } // CreateAutoHideTimer
1534 :
1535 :
1536 : //
1537 : // sAutoHideCallback
1538 : //
1539 : // This fires after a tooltip has been open for a certain length of time. Just tell
1540 : // the listener to close the popup. We don't have to worry, because HideTooltip() can
1541 : // be called multiple times, even if the tip has already been closed.
1542 : //
1543 : void
1544 0 : ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
1545 : {
1546 0 : ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener);
1547 0 : if ( self )
1548 0 : self->HideTooltip();
1549 :
1550 : // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
1551 :
1552 0 : } // sAutoHideCallback
1553 :
1554 :
1555 0 : NS_IMPL_ISUPPORTS1(ChromeContextMenuListener, nsIDOMEventListener)
1556 :
1557 :
1558 : //
1559 : // ChromeTooltipListener ctor
1560 : //
1561 0 : ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
1562 : : mContextMenuListenerInstalled(false),
1563 : mWebBrowser(inBrowser),
1564 0 : mWebBrowserChrome(inChrome)
1565 : {
1566 0 : } // ctor
1567 :
1568 :
1569 : //
1570 : // ChromeTooltipListener dtor
1571 : //
1572 0 : ChromeContextMenuListener::~ChromeContextMenuListener()
1573 : {
1574 0 : } // dtor
1575 :
1576 :
1577 : //
1578 : // AddContextMenuListener
1579 : //
1580 : // Subscribe to the events that will allow us to track context menus. Bascially, this
1581 : // is just the context-menu DOM event.
1582 : //
1583 : NS_IMETHODIMP
1584 0 : ChromeContextMenuListener::AddContextMenuListener()
1585 : {
1586 0 : if (mEventTarget) {
1587 : nsresult rv =
1588 0 : mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
1589 0 : false, false);
1590 0 : NS_ENSURE_SUCCESS(rv, rv);
1591 :
1592 0 : mContextMenuListenerInstalled = true;
1593 : }
1594 :
1595 0 : return NS_OK;
1596 : }
1597 :
1598 :
1599 : //
1600 : // RemoveContextMenuListener
1601 : //
1602 : // Unsubscribe from all the various context menu events that we were listening to.
1603 : //
1604 : NS_IMETHODIMP
1605 0 : ChromeContextMenuListener::RemoveContextMenuListener()
1606 : {
1607 0 : if (mEventTarget) {
1608 : nsresult rv =
1609 0 : mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
1610 0 : false);
1611 0 : NS_ENSURE_SUCCESS(rv, rv);
1612 :
1613 0 : mContextMenuListenerInstalled = false;
1614 : }
1615 :
1616 0 : return NS_OK;
1617 : }
1618 :
1619 :
1620 : //
1621 : // AddChromeListeners
1622 : //
1623 : // Hook up things to the chrome like context menus and tooltips, if the chrome
1624 : // has implemented the right interfaces.
1625 : //
1626 : NS_IMETHODIMP
1627 0 : ChromeContextMenuListener::AddChromeListeners()
1628 : {
1629 0 : if (!mEventTarget)
1630 0 : GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1631 :
1632 : // Register the appropriate events for context menus, but only if
1633 : // the embedding chrome cares.
1634 0 : nsresult rv = NS_OK;
1635 :
1636 0 : nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) );
1637 0 : nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
1638 0 : if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled )
1639 0 : rv = AddContextMenuListener();
1640 :
1641 0 : return rv;
1642 :
1643 : } // AddChromeListeners
1644 :
1645 :
1646 : //
1647 : // RemoveChromeListeners
1648 : //
1649 : // Unsubscribe from the various things we've hooked up to the window root.
1650 : //
1651 : NS_IMETHODIMP
1652 0 : ChromeContextMenuListener::RemoveChromeListeners()
1653 : {
1654 0 : if ( mContextMenuListenerInstalled )
1655 0 : RemoveContextMenuListener();
1656 :
1657 0 : mEventTarget = nsnull;
1658 :
1659 : // it really doesn't matter if these fail...
1660 0 : return NS_OK;
1661 :
1662 : } // RemoveChromeTooltipListeners
1663 :
1664 :
1665 :
1666 : //
1667 : // ContextMenu
1668 : //
1669 : // We're on call to show the context menu. Dig around in the DOM to
1670 : // find the type of object we're dealing with and notify the front
1671 : // end chrome.
1672 : //
1673 : NS_IMETHODIMP
1674 0 : ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent)
1675 : {
1676 0 : nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
1677 0 : NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED);
1678 :
1679 0 : nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aMouseEvent);
1680 :
1681 0 : if (domNSEvent) {
1682 0 : bool isDefaultPrevented = false;
1683 0 : domNSEvent->GetPreventDefault(&isDefaultPrevented);
1684 :
1685 0 : if (isDefaultPrevented) {
1686 0 : return NS_OK;
1687 : }
1688 : }
1689 :
1690 0 : nsCOMPtr<nsIDOMEventTarget> targetNode;
1691 0 : nsresult res = aMouseEvent->GetTarget(getter_AddRefs(targetNode));
1692 0 : if (NS_FAILED(res))
1693 0 : return res;
1694 0 : if (!targetNode)
1695 0 : return NS_ERROR_NULL_POINTER;
1696 :
1697 0 : nsCOMPtr<nsIDOMNode> targetDOMnode;
1698 0 : nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
1699 0 : if (!node)
1700 0 : return NS_OK;
1701 :
1702 : // Stop the context menu event going to other windows (bug 78396)
1703 0 : aMouseEvent->PreventDefault();
1704 :
1705 : // If the listener is a nsIContextMenuListener2, create the info object
1706 0 : nsCOMPtr<nsIContextMenuListener2> menuListener2(do_QueryInterface(mWebBrowserChrome));
1707 0 : nsContextMenuInfo *menuInfoImpl = nsnull;
1708 0 : nsCOMPtr<nsIContextMenuInfo> menuInfo;
1709 0 : if (menuListener2) {
1710 0 : menuInfoImpl = new nsContextMenuInfo;
1711 0 : if (!menuInfoImpl)
1712 0 : return NS_ERROR_OUT_OF_MEMORY;
1713 0 : menuInfo = menuInfoImpl;
1714 : }
1715 :
1716 0 : PRUint32 flags = nsIContextMenuListener::CONTEXT_NONE;
1717 0 : PRUint32 flags2 = nsIContextMenuListener2::CONTEXT_NONE;
1718 :
1719 : // XXX test for selected text
1720 :
1721 : PRUint16 nodeType;
1722 0 : res = node->GetNodeType(&nodeType);
1723 0 : NS_ENSURE_SUCCESS(res, res);
1724 :
1725 : // First, checks for nodes that never have children.
1726 0 : if (nodeType == nsIDOMNode::ELEMENT_NODE) {
1727 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(node));
1728 0 : if (content) {
1729 0 : nsCOMPtr<nsIURI> imgUri;
1730 0 : content->GetCurrentURI(getter_AddRefs(imgUri));
1731 0 : if (imgUri) {
1732 0 : flags |= nsIContextMenuListener::CONTEXT_IMAGE;
1733 0 : flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE;
1734 0 : targetDOMnode = node;
1735 : }
1736 : }
1737 :
1738 0 : nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(node));
1739 0 : if (formControl) {
1740 0 : if (formControl->GetType() == NS_FORM_TEXTAREA) {
1741 0 : flags |= nsIContextMenuListener::CONTEXT_TEXT;
1742 0 : flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
1743 0 : targetDOMnode = node;
1744 : } else {
1745 0 : nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(formControl));
1746 0 : if (inputElement) {
1747 0 : flags |= nsIContextMenuListener::CONTEXT_INPUT;
1748 0 : flags2 |= nsIContextMenuListener2::CONTEXT_INPUT;
1749 :
1750 0 : if (menuListener2) {
1751 0 : if (formControl->IsSingleLineTextControl(false)) {
1752 0 : flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
1753 : }
1754 : }
1755 :
1756 0 : targetDOMnode = node;
1757 : }
1758 : }
1759 : }
1760 :
1761 : // always consume events for plugins and Java who may throw their
1762 : // own context menus but not for image objects. Document objects
1763 : // will never be targets or ancestors of targets, so that's OK.
1764 0 : nsCOMPtr<nsIDOMHTMLObjectElement> objectElement;
1765 0 : if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE))
1766 0 : objectElement = do_QueryInterface(node);
1767 0 : nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement(do_QueryInterface(node));
1768 0 : nsCOMPtr<nsIDOMHTMLAppletElement> appletElement(do_QueryInterface(node));
1769 :
1770 0 : if (objectElement || embedElement || appletElement)
1771 0 : return NS_OK;
1772 : }
1773 :
1774 : // Bubble out, looking for items of interest
1775 0 : do {
1776 : PRUint16 nodeType;
1777 0 : res = node->GetNodeType(&nodeType);
1778 0 : NS_ENSURE_SUCCESS(res, res);
1779 :
1780 0 : if (nodeType == nsIDOMNode::ELEMENT_NODE) {
1781 :
1782 : // Test if the element has an associated link
1783 0 : nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
1784 :
1785 0 : bool hasAttr = false;
1786 0 : res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
1787 :
1788 0 : if (NS_SUCCEEDED(res) && hasAttr)
1789 : {
1790 0 : flags |= nsIContextMenuListener::CONTEXT_LINK;
1791 0 : flags2 |= nsIContextMenuListener2::CONTEXT_LINK;
1792 0 : if (!targetDOMnode)
1793 0 : targetDOMnode = node;
1794 0 : if (menuInfoImpl)
1795 0 : menuInfoImpl->SetAssociatedLink(node);
1796 : break; // exit do-while
1797 : }
1798 : }
1799 :
1800 : // walk-up-the-tree
1801 0 : nsCOMPtr<nsIDOMNode> parentNode;
1802 0 : node->GetParentNode(getter_AddRefs(parentNode));
1803 0 : node = parentNode;
1804 0 : } while (node);
1805 :
1806 0 : if (!flags && !flags2) {
1807 : // We found nothing of interest so far, check if we
1808 : // have at least an html document.
1809 0 : nsCOMPtr<nsIDOMDocument> document;
1810 0 : node = do_QueryInterface(targetNode);
1811 0 : node->GetOwnerDocument(getter_AddRefs(document));
1812 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document));
1813 0 : if (htmlDocument) {
1814 0 : flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
1815 0 : flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT;
1816 0 : targetDOMnode = node;
1817 0 : if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) {
1818 : // check if this is a background image that the user was trying to click on
1819 : // and if the listener is ready for that (only nsIContextMenuListener2 and up)
1820 0 : if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) {
1821 0 : flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE;
1822 : // For the embedder to get the correct background image
1823 : // targetDOMnode must point to the original node.
1824 0 : targetDOMnode = do_QueryInterface(targetNode);
1825 : }
1826 : }
1827 : }
1828 : }
1829 :
1830 : // we need to cache the event target into the focus controller's popupNode
1831 : // so we can get at it later from command code, etc.:
1832 :
1833 : // get the dom window
1834 0 : nsCOMPtr<nsIDOMWindow> win;
1835 0 : res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win));
1836 0 : NS_ENSURE_SUCCESS(res, res);
1837 0 : NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
1838 :
1839 0 : nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(win));
1840 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
1841 0 : nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
1842 0 : NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
1843 0 : if (root) {
1844 : // set the window root's popup node to the event target
1845 0 : root->SetPopupNode(targetDOMnode);
1846 : }
1847 :
1848 : // Tell the listener all about the event
1849 0 : if ( menuListener2 ) {
1850 0 : menuInfoImpl->SetMouseEvent(aMouseEvent);
1851 0 : menuInfoImpl->SetDOMNode(targetDOMnode);
1852 0 : menuListener2->OnShowContextMenu(flags2, menuInfo);
1853 : }
1854 : else {
1855 0 : nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
1856 0 : if ( menuListener )
1857 0 : menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
1858 : }
1859 :
1860 0 : return NS_OK;
1861 :
1862 : } // MouseDown
|