|
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/. */ |
|
5 |
|
6 // Local Includes |
|
7 #include "nsDocShellTreeOwner.h" |
|
8 #include "nsWebBrowser.h" |
|
9 |
|
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" |
|
22 |
|
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() |
|
69 |
|
70 using namespace mozilla; |
|
71 using namespace mozilla::dom; |
|
72 |
|
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); |
|
83 |
|
84 nsCOMPtr<nsIDOMWindow> domWindow; |
|
85 inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); |
|
86 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE); |
|
87 |
|
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); |
|
96 |
|
97 return NS_OK; |
|
98 } |
|
99 |
|
100 |
|
101 //***************************************************************************** |
|
102 //*** nsDocShellTreeOwner: Object Management |
|
103 //***************************************************************************** |
|
104 |
|
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 } |
|
116 |
|
117 nsDocShellTreeOwner::~nsDocShellTreeOwner() |
|
118 { |
|
119 RemoveChromeListeners(); |
|
120 } |
|
121 |
|
122 //***************************************************************************** |
|
123 // nsDocShellTreeOwner::nsISupports |
|
124 //***************************************************************************** |
|
125 |
|
126 NS_IMPL_ADDREF(nsDocShellTreeOwner) |
|
127 NS_IMPL_RELEASE(nsDocShellTreeOwner) |
|
128 |
|
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 |
|
139 |
|
140 //***************************************************************************** |
|
141 // nsDocShellTreeOwner::nsIInterfaceRequestor |
|
142 //***************************************************************************** |
|
143 |
|
144 NS_IMETHODIMP |
|
145 nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) |
|
146 { |
|
147 NS_ENSURE_ARG_POINTER(aSink); |
|
148 |
|
149 if(NS_SUCCEEDED(QueryInterface(aIID, aSink))) |
|
150 return NS_OK; |
|
151 |
|
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 } |
|
157 |
|
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 } |
|
169 |
|
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 } |
|
181 |
|
182 nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor(); |
|
183 if (req) |
|
184 return req->GetInterface(aIID, aSink); |
|
185 |
|
186 return NS_NOINTERFACE; |
|
187 } |
|
188 |
|
189 //***************************************************************************** |
|
190 // nsDocShellTreeOwner::nsIDocShellTreeOwner |
|
191 //***************************************************************************** |
|
192 |
|
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; |
|
203 |
|
204 nsAutoString name(aName); |
|
205 |
|
206 if (!mWebBrowser) |
|
207 return NS_OK; // stymied |
|
208 |
|
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 } |
|
222 |
|
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 } |
|
232 |
|
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 } |
|
241 |
|
242 // finally, failing everything else, search all windows |
|
243 return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor, |
|
244 aFoundItem); |
|
245 } |
|
246 |
|
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; |
|
257 |
|
258 return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor, |
|
259 aFoundItem); |
|
260 } |
|
261 |
|
262 void |
|
263 nsDocShellTreeOwner::EnsurePrompter() |
|
264 { |
|
265 if (mPrompter) |
|
266 return; |
|
267 |
|
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 } |
|
276 |
|
277 void |
|
278 nsDocShellTreeOwner::EnsureAuthPrompter() |
|
279 { |
|
280 if (mAuthPrompter) |
|
281 return; |
|
282 |
|
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 } |
|
291 |
|
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 } |
|
308 |
|
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 } |
|
322 |
|
323 |
|
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); |
|
332 |
|
333 if (aPrimary) |
|
334 mPrimaryContentShell = aContentShell; |
|
335 return NS_OK; |
|
336 } |
|
337 |
|
338 NS_IMETHODIMP |
|
339 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) |
|
340 { |
|
341 if(mTreeOwner) |
|
342 return mTreeOwner->ContentShellRemoved(aContentShell); |
|
343 |
|
344 if(mPrimaryContentShell == aContentShell) |
|
345 mPrimaryContentShell = nullptr; |
|
346 |
|
347 return NS_OK; |
|
348 } |
|
349 |
|
350 NS_IMETHODIMP |
|
351 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell) |
|
352 { |
|
353 NS_ENSURE_ARG_POINTER(aShell); |
|
354 |
|
355 if (mTreeOwner) |
|
356 return mTreeOwner->GetPrimaryContentShell(aShell); |
|
357 |
|
358 *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell); |
|
359 NS_IF_ADDREF(*aShell); |
|
360 |
|
361 return NS_OK; |
|
362 } |
|
363 |
|
364 NS_IMETHODIMP |
|
365 nsDocShellTreeOwner::GetContentWindow(JSContext* aCx, |
|
366 JS::MutableHandle<JS::Value> aVal) |
|
367 { |
|
368 if (mTreeOwner) |
|
369 return mTreeOwner->GetContentWindow(aCx, aVal); |
|
370 |
|
371 return NS_ERROR_NOT_IMPLEMENTED; |
|
372 } |
|
373 |
|
374 NS_IMETHODIMP |
|
375 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, |
|
376 int32_t aCX, int32_t aCY) |
|
377 { |
|
378 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); |
|
379 |
|
380 NS_ENSURE_STATE(mTreeOwner || webBrowserChrome); |
|
381 |
|
382 if(mTreeOwner) |
|
383 return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY); |
|
384 |
|
385 if(aShellItem == mWebBrowser->mDocShell) |
|
386 return webBrowserChrome->SizeBrowserTo(aCX, aCY); |
|
387 |
|
388 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem)); |
|
389 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); |
|
390 |
|
391 nsCOMPtr<nsIDOMDocument> domDocument; |
|
392 webNav->GetDocument(getter_AddRefs(domDocument)); |
|
393 NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); |
|
394 |
|
395 nsCOMPtr<nsIDOMElement> domElement; |
|
396 domDocument->GetDocumentElement(getter_AddRefs(domElement)); |
|
397 NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); |
|
398 |
|
399 // Set the preferred Size |
|
400 //XXX |
|
401 NS_ERROR("Implement this"); |
|
402 /* |
|
403 Set the preferred size on the aShellItem. |
|
404 */ |
|
405 |
|
406 nsRefPtr<nsPresContext> presContext; |
|
407 mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext)); |
|
408 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); |
|
409 |
|
410 nsIPresShell *presShell = presContext->GetPresShell(); |
|
411 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); |
|
412 |
|
413 NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, |
|
414 NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); |
|
415 |
|
416 nsRect shellArea = presContext->GetVisibleArea(); |
|
417 |
|
418 int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width); |
|
419 int32_t browserCY = presContext->AppUnitsToDevPixels(shellArea.height); |
|
420 |
|
421 return webBrowserChrome->SizeBrowserTo(browserCX, browserCY); |
|
422 } |
|
423 |
|
424 NS_IMETHODIMP |
|
425 nsDocShellTreeOwner::SetPersistence(bool aPersistPosition, |
|
426 bool aPersistSize, |
|
427 bool aPersistSizeMode) |
|
428 { |
|
429 return NS_ERROR_NOT_IMPLEMENTED; |
|
430 } |
|
431 |
|
432 NS_IMETHODIMP |
|
433 nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition, |
|
434 bool* aPersistSize, |
|
435 bool* aPersistSizeMode) |
|
436 { |
|
437 return NS_ERROR_NOT_IMPLEMENTED; |
|
438 } |
|
439 |
|
440 NS_IMETHODIMP |
|
441 nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) |
|
442 { |
|
443 if(mTreeOwner) { |
|
444 mTreeOwner->GetTargetableShellCount(aResult); |
|
445 } else { |
|
446 *aResult = 0; |
|
447 } |
|
448 |
|
449 return NS_OK; |
|
450 } |
|
451 |
|
452 //***************************************************************************** |
|
453 // nsDocShellTreeOwner::nsIBaseWindow |
|
454 //***************************************************************************** |
|
455 |
|
456 |
|
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 } |
|
464 |
|
465 NS_IMETHODIMP |
|
466 nsDocShellTreeOwner::Create() |
|
467 { |
|
468 return NS_ERROR_NULL_POINTER; |
|
469 } |
|
470 |
|
471 NS_IMETHODIMP |
|
472 nsDocShellTreeOwner::Destroy() |
|
473 { |
|
474 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); |
|
475 if (webBrowserChrome) |
|
476 { |
|
477 return webBrowserChrome->DestroyBrowserWindow(); |
|
478 } |
|
479 |
|
480 return NS_ERROR_NULL_POINTER; |
|
481 } |
|
482 |
|
483 NS_IMETHODIMP |
|
484 nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) |
|
485 { |
|
486 if (mWebBrowser) { |
|
487 return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale); |
|
488 } |
|
489 |
|
490 *aScale = 1.0; |
|
491 return NS_OK; |
|
492 } |
|
493 |
|
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 } |
|
505 |
|
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 } |
|
517 |
|
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 } |
|
529 |
|
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 } |
|
541 |
|
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 } |
|
555 |
|
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 } |
|
569 |
|
570 NS_IMETHODIMP |
|
571 nsDocShellTreeOwner::Repaint(bool aForce) |
|
572 { |
|
573 return NS_ERROR_NULL_POINTER; |
|
574 } |
|
575 |
|
576 NS_IMETHODIMP |
|
577 nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget) |
|
578 { |
|
579 return NS_ERROR_NULL_POINTER; |
|
580 } |
|
581 |
|
582 NS_IMETHODIMP |
|
583 nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget) |
|
584 { |
|
585 return NS_ERROR_NULL_POINTER; |
|
586 } |
|
587 |
|
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 } |
|
598 |
|
599 NS_IMETHODIMP |
|
600 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow) |
|
601 { |
|
602 return NS_ERROR_NULL_POINTER; |
|
603 } |
|
604 |
|
605 NS_IMETHODIMP |
|
606 nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle) |
|
607 { |
|
608 // the nativeHandle should be accessed from nsIXULWindow |
|
609 return NS_ERROR_NOT_IMPLEMENTED; |
|
610 } |
|
611 |
|
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 } |
|
622 |
|
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 } |
|
633 |
|
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 } |
|
641 |
|
642 NS_IMETHODIMP |
|
643 nsDocShellTreeOwner::SetEnabled(bool aEnabled) |
|
644 { |
|
645 return NS_ERROR_NOT_IMPLEMENTED; |
|
646 } |
|
647 |
|
648 NS_IMETHODIMP |
|
649 nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget) |
|
650 { |
|
651 return NS_ERROR_NULL_POINTER; |
|
652 } |
|
653 |
|
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 } |
|
664 |
|
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 } |
|
675 |
|
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 } |
|
686 |
|
687 |
|
688 //***************************************************************************** |
|
689 // nsDocShellTreeOwner::nsIWebProgressListener |
|
690 //***************************************************************************** |
|
691 |
|
692 |
|
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 } |
|
706 |
|
707 NS_IMETHODIMP |
|
708 nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress, |
|
709 nsIRequest* aRequest, |
|
710 uint32_t aProgressStateFlags, |
|
711 nsresult aStatus) |
|
712 { |
|
713 return NS_OK; |
|
714 } |
|
715 |
|
716 NS_IMETHODIMP |
|
717 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress, |
|
718 nsIRequest* aRequest, |
|
719 nsIURI* aURI, |
|
720 uint32_t aFlags) |
|
721 { |
|
722 return NS_OK; |
|
723 } |
|
724 |
|
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 } |
|
733 |
|
734 NS_IMETHODIMP |
|
735 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, |
|
736 nsIRequest *aRequest, |
|
737 uint32_t state) |
|
738 { |
|
739 return NS_OK; |
|
740 } |
|
741 |
|
742 |
|
743 //***************************************************************************** |
|
744 // nsDocShellTreeOwner: Helpers |
|
745 //***************************************************************************** |
|
746 |
|
747 //***************************************************************************** |
|
748 // nsDocShellTreeOwner: Accessors |
|
749 //***************************************************************************** |
|
750 |
|
751 void |
|
752 nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) |
|
753 { |
|
754 if ( !aWebBrowser ) |
|
755 RemoveChromeListeners(); |
|
756 if (aWebBrowser != mWebBrowser) { |
|
757 mPrompter = 0; |
|
758 mAuthPrompter = 0; |
|
759 } |
|
760 |
|
761 mWebBrowser = aWebBrowser; |
|
762 } |
|
763 |
|
764 nsWebBrowser * |
|
765 nsDocShellTreeOwner::WebBrowser() |
|
766 { |
|
767 return mWebBrowser; |
|
768 } |
|
769 |
|
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 } |
|
785 |
|
786 return NS_OK; |
|
787 } |
|
788 |
|
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)); |
|
805 |
|
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 } |
|
814 |
|
815 |
|
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; |
|
826 |
|
827 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome(); |
|
828 if (!webBrowserChrome) |
|
829 return NS_ERROR_FAILURE; |
|
830 |
|
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 } |
|
846 |
|
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 } |
|
864 |
|
865 // register dragover and drop event listeners with the listener manager |
|
866 nsCOMPtr<EventTarget> target; |
|
867 GetDOMEventTarget(mWebBrowser, getter_AddRefs(target)); |
|
868 |
|
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 } |
|
876 |
|
877 return rv; |
|
878 |
|
879 } // AddChromeListeners |
|
880 |
|
881 |
|
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 } |
|
893 |
|
894 nsCOMPtr<EventTarget> piTarget; |
|
895 GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget)); |
|
896 if (!piTarget) |
|
897 return NS_OK; |
|
898 |
|
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 } |
|
907 |
|
908 return NS_OK; |
|
909 } |
|
910 |
|
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); |
|
916 |
|
917 bool defaultPrevented; |
|
918 aEvent->GetDefaultPrevented(&defaultPrevented); |
|
919 if (defaultPrevented) { |
|
920 return NS_OK; |
|
921 } |
|
922 |
|
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); |
|
935 |
|
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 } |
|
948 |
|
949 return NS_OK; |
|
950 } |
|
951 |
|
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 } |
|
963 |
|
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 } |
|
975 |
|
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 } |
|
987 |
|
988 |
|
989 /////////////////////////////////////////////////////////////////////////////// |
|
990 // DefaultTooltipTextProvider |
|
991 |
|
992 class DefaultTooltipTextProvider MOZ_FINAL : public nsITooltipTextProvider |
|
993 { |
|
994 public: |
|
995 DefaultTooltipTextProvider(); |
|
996 |
|
997 NS_DECL_THREADSAFE_ISUPPORTS |
|
998 NS_DECL_NSITOOLTIPTEXTPROVIDER |
|
999 |
|
1000 protected: |
|
1001 nsCOMPtr<nsIAtom> mTag_dialog; |
|
1002 nsCOMPtr<nsIAtom> mTag_dialogheader; |
|
1003 nsCOMPtr<nsIAtom> mTag_window; |
|
1004 }; |
|
1005 |
|
1006 NS_IMPL_ISUPPORTS(DefaultTooltipTextProvider, nsITooltipTextProvider) |
|
1007 |
|
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 } |
|
1016 |
|
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; |
|
1030 |
|
1031 return element->GetParentNode()->NodeType() != nsIDOMNode::DOCUMENT_NODE; |
|
1032 } |
|
1033 |
|
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); |
|
1041 |
|
1042 nsString outText; |
|
1043 |
|
1044 nsCOMPtr<nsINode> node = do_QueryInterface(aNode); |
|
1045 |
|
1046 bool lookingForSVGTitle = true; |
|
1047 bool found = false; |
|
1048 nsCOMPtr<nsIDOMNode> current ( aNode ); |
|
1049 |
|
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"); |
|
1056 |
|
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 } |
|
1064 |
|
1065 if (!content->HasAttr(kNameSpaceID_None, titleAtom) && |
|
1066 !formHasNoValidate) { |
|
1067 cvElement->GetValidationMessage(outText); |
|
1068 found = !outText.IsEmpty(); |
|
1069 } |
|
1070 } |
|
1071 |
|
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 } |
|
1119 |
|
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 |
|
1126 |
|
1127 *_retval = found; |
|
1128 *aText = (found) ? ToNewUnicode(outText) : nullptr; |
|
1129 |
|
1130 return NS_OK; |
|
1131 } |
|
1132 |
|
1133 /////////////////////////////////////////////////////////////////////////////// |
|
1134 |
|
1135 NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener) |
|
1136 |
|
1137 // |
|
1138 // ChromeTooltipListener ctor |
|
1139 // |
|
1140 |
|
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 |
|
1154 |
|
1155 |
|
1156 // |
|
1157 // ChromeTooltipListener dtor |
|
1158 // |
|
1159 ChromeTooltipListener::~ChromeTooltipListener() |
|
1160 { |
|
1161 |
|
1162 } // dtor |
|
1163 |
|
1164 |
|
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)); |
|
1176 |
|
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 } |
|
1186 |
|
1187 return rv; |
|
1188 |
|
1189 } // AddChromeListeners |
|
1190 |
|
1191 |
|
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); |
|
1215 |
|
1216 mTooltipListenerInstalled = true; |
|
1217 } |
|
1218 |
|
1219 return NS_OK; |
|
1220 } |
|
1221 |
|
1222 |
|
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(); |
|
1232 |
|
1233 if ( mTooltipListenerInstalled ) |
|
1234 RemoveTooltipListener(); |
|
1235 |
|
1236 mEventTarget = nullptr; |
|
1237 |
|
1238 // it really doesn't matter if these fail... |
|
1239 return NS_OK; |
|
1240 |
|
1241 } // RemoveChromeTooltipListeners |
|
1242 |
|
1243 |
|
1244 |
|
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); |
|
1267 |
|
1268 mTooltipListenerInstalled = false; |
|
1269 } |
|
1270 |
|
1271 return NS_OK; |
|
1272 } |
|
1273 |
|
1274 NS_IMETHODIMP |
|
1275 ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) |
|
1276 { |
|
1277 nsAutoString eventType; |
|
1278 aEvent->GetType(eventType); |
|
1279 |
|
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); |
|
1286 |
|
1287 NS_ERROR("Unexpected event type"); |
|
1288 return NS_OK; |
|
1289 } |
|
1290 |
|
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; |
|
1303 |
|
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); |
|
1316 |
|
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(); |
|
1325 |
|
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" ); |
|
1342 |
|
1343 return NS_OK; |
|
1344 |
|
1345 } // MouseMove |
|
1346 |
|
1347 |
|
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; |
|
1358 |
|
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 } |
|
1366 |
|
1367 return rv; |
|
1368 |
|
1369 } // ShowTooltip |
|
1370 |
|
1371 |
|
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; |
|
1382 |
|
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 } |
|
1394 |
|
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 } |
|
1404 |
|
1405 return rv; |
|
1406 |
|
1407 } // HideTooltip |
|
1408 |
|
1409 |
|
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 } |
|
1441 |
|
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 } |
|
1453 |
|
1454 if (!widget) { |
|
1455 // release tooltip target if there is one, NO MATTER WHAT |
|
1456 self->mPossibleTooltipNode = nullptr; |
|
1457 return; |
|
1458 } |
|
1459 |
|
1460 // if there is text associated with the node, show the tip and fire |
|
1461 // off a timer to auto-hide it. |
|
1462 |
|
1463 nsXPIDLString tooltipText; |
|
1464 if (self->mTooltipTextProvider) { |
|
1465 bool textFound = false; |
|
1466 |
|
1467 self->mTooltipTextProvider->GetNodeText( |
|
1468 self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound); |
|
1469 |
|
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 } |
|
1479 |
|
1480 // release tooltip target if there is one, NO MATTER WHAT |
|
1481 self->mPossibleTooltipNode = nullptr; |
|
1482 } // if "self" data valid |
|
1483 |
|
1484 } // sTooltipCallback |
|
1485 |
|
1486 |
|
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 } |
|
1500 |
|
1501 mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1"); |
|
1502 if ( mAutoHideTimer ) |
|
1503 mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, |
|
1504 nsITimer::TYPE_ONE_SHOT); |
|
1505 |
|
1506 } // CreateAutoHideTimer |
|
1507 |
|
1508 |
|
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(); |
|
1522 |
|
1523 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup(); |
|
1524 |
|
1525 } // sAutoHideCallback |
|
1526 |
|
1527 |
|
1528 NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) |
|
1529 |
|
1530 |
|
1531 // |
|
1532 // ChromeTooltipListener ctor |
|
1533 // |
|
1534 ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) |
|
1535 : mContextMenuListenerInstalled(false), |
|
1536 mWebBrowser(inBrowser), |
|
1537 mWebBrowserChrome(inChrome) |
|
1538 { |
|
1539 } // ctor |
|
1540 |
|
1541 |
|
1542 // |
|
1543 // ChromeTooltipListener dtor |
|
1544 // |
|
1545 ChromeContextMenuListener::~ChromeContextMenuListener() |
|
1546 { |
|
1547 } // dtor |
|
1548 |
|
1549 |
|
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); |
|
1564 |
|
1565 mContextMenuListenerInstalled = true; |
|
1566 } |
|
1567 |
|
1568 return NS_OK; |
|
1569 } |
|
1570 |
|
1571 |
|
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); |
|
1585 |
|
1586 mContextMenuListenerInstalled = false; |
|
1587 } |
|
1588 |
|
1589 return NS_OK; |
|
1590 } |
|
1591 |
|
1592 |
|
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)); |
|
1604 |
|
1605 // Register the appropriate events for context menus, but only if |
|
1606 // the embedding chrome cares. |
|
1607 nsresult rv = NS_OK; |
|
1608 |
|
1609 nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) ); |
|
1610 nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) ); |
|
1611 if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled ) |
|
1612 rv = AddContextMenuListener(); |
|
1613 |
|
1614 return rv; |
|
1615 |
|
1616 } // AddChromeListeners |
|
1617 |
|
1618 |
|
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(); |
|
1629 |
|
1630 mEventTarget = nullptr; |
|
1631 |
|
1632 // it really doesn't matter if these fail... |
|
1633 return NS_OK; |
|
1634 |
|
1635 } // RemoveChromeTooltipListeners |
|
1636 |
|
1637 |
|
1638 |
|
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); |
|
1651 |
|
1652 bool isDefaultPrevented = false; |
|
1653 aMouseEvent->GetDefaultPrevented(&isDefaultPrevented); |
|
1654 if (isDefaultPrevented) { |
|
1655 return NS_OK; |
|
1656 } |
|
1657 |
|
1658 nsCOMPtr<EventTarget> targetNode = aMouseEvent->InternalDOMEvent()->GetTarget(); |
|
1659 if (!targetNode) |
|
1660 return NS_ERROR_NULL_POINTER; |
|
1661 |
|
1662 nsCOMPtr<nsIDOMNode> targetDOMnode; |
|
1663 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode); |
|
1664 if (!node) |
|
1665 return NS_OK; |
|
1666 |
|
1667 // Stop the context menu event going to other windows (bug 78396) |
|
1668 aMouseEvent->PreventDefault(); |
|
1669 |
|
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 } |
|
1678 |
|
1679 uint32_t flags = nsIContextMenuListener::CONTEXT_NONE; |
|
1680 uint32_t flags2 = nsIContextMenuListener2::CONTEXT_NONE; |
|
1681 |
|
1682 // XXX test for selected text |
|
1683 |
|
1684 uint16_t nodeType; |
|
1685 nsresult res = node->GetNodeType(&nodeType); |
|
1686 NS_ENSURE_SUCCESS(res, res); |
|
1687 |
|
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 } |
|
1700 |
|
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; |
|
1712 |
|
1713 if (menuListener2) { |
|
1714 if (formControl->IsSingleLineTextControl(false)) { |
|
1715 flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; |
|
1716 } |
|
1717 } |
|
1718 |
|
1719 targetDOMnode = node; |
|
1720 } |
|
1721 } |
|
1722 } |
|
1723 |
|
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)); |
|
1732 |
|
1733 if (objectElement || embedElement || appletElement) |
|
1734 return NS_OK; |
|
1735 } |
|
1736 |
|
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); |
|
1742 |
|
1743 if (nodeType == nsIDOMNode::ELEMENT_NODE) { |
|
1744 |
|
1745 // Test if the element has an associated link |
|
1746 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node)); |
|
1747 |
|
1748 bool hasAttr = false; |
|
1749 res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); |
|
1750 |
|
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 } |
|
1762 |
|
1763 // walk-up-the-tree |
|
1764 nsCOMPtr<nsIDOMNode> parentNode; |
|
1765 node->GetParentNode(getter_AddRefs(parentNode)); |
|
1766 node = parentNode; |
|
1767 } while (node); |
|
1768 |
|
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 } |
|
1792 |
|
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.: |
|
1795 |
|
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); |
|
1801 |
|
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 } |
|
1810 |
|
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 } |
|
1822 |
|
1823 return NS_OK; |
|
1824 |
|
1825 } // MouseDown |