1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 tw=80 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla's Element Optimizeing extension.
18 * The Initial Developer of the Original Code is the Mozilla Foundation.
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
23 * Oleg Romashin <romaxa@gmail.com> (original author)
24 * Brad Lassey <blassey@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsCURILoader.h"
41 #include "nsICategoryManager.h"
42 #include "nsIDOMAbstractView.h"
43 #include "nsIDOMDocument.h"
44 #include "nsIDOMDocumentView.h"
45 #include "nsIDOMHTMLElement.h"
46 #include "nsIDOMHTMLIFrameElement.h"
47 #include "nsIDOMNSDocument.h"
48 #include "nsIDOMNSElement.h"
49 #include "nsIDOMNSHTMLElement.h"
50 #include "nsIDOMNode.h"
51 #include "nsIDOMNodeList.h"
52 #include "nsIDOMWindow.h"
53 #include "nsIDOMWindowCollection.h"
54 #include "nsIDocument.h"
55 #include "nsIGenericFactory.h"
56 #include "nsIObserver.h"
58 #include "nsIPresShell.h"
59 #include "nsIStyleSheetService.h"
60 #include "nsIWebProgress.h"
61 #include "nsIWebProgressListener.h"
62 #include "nsIWindowWatcher.h"
63 #include "nsNetUtil.h"
65 #include "nsStringGlue.h"
66 #include "nsWeakReference.h"
67 #include "nsIWebBrowser.h"
68 #include "nsIObserverService.h"
69 #include "nsIDOMEventTarget.h"
70 #include "nsPIDOMWindow.h"
71 #include "nsIDOMWindow.h"
73 #include "nsIDOM3EventTarget.h"
74 #include "nsIDOMKeyListener.h"
75 #include "nsIDOMCompositionListener.h"
76 #include "nsIDOMTextListener.h"
77 #include "nsIDOMMouseMotionListener.h"
78 #include "nsIDOMMouseListener.h"
79 #include "nsIDOMMouseEvent.h"
80 #include "nsIDOMNSEvent.h"
82 #include "nsGUIEvent.h"
83 #include "nsIViewManager.h"
84 #include "nsIContentPolicy.h"
85 #include "nsIDocShellTreeItem.h"
86 #include "nsIContent.h"
89 const int MIN_INT
=((int) (1 << (sizeof(int) * 8 - 1)));
91 static int g_lastX
=MIN_INT
;
92 static int g_lastY
=MIN_INT
;
93 static PRInt32 g_panning
= 0;
94 static PRBool g_is_scrollable
= PR_FALSE
;
97 #define NS_FRAME_HAS_RELATIVE_SIZE 0x01000000
98 #define NS_FRAME_HAS_OPTIMIZEDVIEW 0x02000000
99 #define BEHAVIOR_ACCEPT nsIPermissionManager::ALLOW_ACTION
100 #define BEHAVIOR_REJECT nsIPermissionManager::DENY_ACTION
101 #define BEHAVIOR_NOFOREIGN 3
102 #define NUMBER_OF_TYPES 13
104 // TODO auto reload nsWidgetUtils in C.
105 class nsWidgetUtils
: public nsIObserver
,
106 public nsIDOMMouseMotionListener
,
107 public nsIDOMMouseListener
,
108 public nsIContentPolicy
,
109 public nsSupportsWeakReference
113 virtual ~nsWidgetUtils();
115 // nsIDOMMouseMotionListener
116 NS_IMETHOD
MouseMove(nsIDOMEvent
* aDOMEvent
);
117 NS_IMETHOD
DragMove(nsIDOMEvent
* aMouseEvent
);
118 NS_IMETHOD
HandleEvent(nsIDOMEvent
* aDOMEvent
);
120 // nsIDOMMouseListener
121 NS_IMETHOD
MouseDown(nsIDOMEvent
* aDOMEvent
);
122 NS_IMETHOD
MouseUp(nsIDOMEvent
* aDOMEvent
);
123 NS_IMETHOD
MouseClick(nsIDOMEvent
* aDOMEvent
);
124 NS_IMETHOD
MouseDblClick(nsIDOMEvent
* aDOMEvent
);
125 NS_IMETHOD
MouseOver(nsIDOMEvent
* aDOMEvent
);
126 NS_IMETHOD
MouseOut(nsIDOMEvent
* aDOMEvent
);
130 NS_DECL_NSICONTENTPOLICY
134 void RemoveWindowListeners(nsIDOMWindow
*aDOMWin
);
135 void GetChromeEventHandler(nsIDOMWindow
*aDOMWin
, nsIDOMEventTarget
**aChromeTarget
);
136 void AttachWindowListeners(nsIDOMWindow
*aDOMWin
);
137 PRBool
IsXULNode(nsIDOMNode
*aNode
, PRUint32
*aType
= 0);
138 nsresult
GetDOMWindowByNode(nsIDOMNode
*aNode
, nsIDOMWindow
* *aDOMWindow
);
139 nsresult
UpdateFromEvent(nsIDOMEvent
*aDOMEvent
, nsIWidget
* *aWidget
= nsnull
, nsIViewManager
* *aViewManager
= nsnull
);
141 static void StopPanningCallback(nsITimer
*timer
, void *closure
);
143 nsCOMPtr
<nsIWidget
> mWidget
;
144 nsCOMPtr
<nsIViewManager
> mViewManager
;
145 nsCOMPtr
<nsITimer
> mTimer
;
148 nsWidgetUtils::nsWidgetUtils()
154 nsWidgetUtils::Init()
157 nsCOMPtr
<nsIObserverService
> obsSvc
=
158 do_GetService("@mozilla.org/observer-service;1");
159 NS_ENSURE_STATE(obsSvc
);
161 rv
= obsSvc
->AddObserver(this, "domwindowopened", PR_FALSE
);
162 NS_ENSURE_SUCCESS(rv
, rv
);
163 rv
= obsSvc
->AddObserver(this, "domwindowclosed", PR_FALSE
);
164 NS_ENSURE_SUCCESS(rv
, rv
);
165 mTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
169 nsWidgetUtils::UpdateFromEvent(nsIDOMEvent
*aDOMEvent
, nsIWidget
* *aWidget
, nsIViewManager
* *aViewManager
)
171 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
;
172 mouseEvent
= do_QueryInterface(aDOMEvent
);
176 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenX(&g_lastX
);
177 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenY(&g_lastY
);
179 nsCOMPtr
<nsIDOMWindow
> mWindow
;
180 nsCOMPtr
<nsIDOMNode
> mNode
;
181 nsCOMPtr
<nsIDOMNode
> mOrigNode
;
184 PRBool isXul
= PR_FALSE
;
186 nsCOMPtr
<nsIDOMNSEvent
> aEvent
= do_QueryInterface(aDOMEvent
);
187 nsCOMPtr
<nsIDOMEventTarget
> eventOrigTarget
;
189 aEvent
->GetOriginalTarget(getter_AddRefs(eventOrigTarget
));
191 mOrigNode
= do_QueryInterface(eventOrigTarget
);
192 isXul
= IsXULNode(mOrigNode
, &type
);
196 return NS_ERROR_FAILURE
;
198 nsCOMPtr
<nsIDOMEventTarget
> eventTarget
;
199 aDOMEvent
->GetTarget(getter_AddRefs(eventTarget
));
201 mNode
= do_QueryInterface(eventTarget
);
206 GetDOMWindowByNode(mNode
, getter_AddRefs(mWindow
));
209 nsCOMPtr
<nsIDocument
> doc
;
210 nsCOMPtr
<nsIDOMDocument
> domDoc
;
211 mWindow
->GetDocument(getter_AddRefs(domDoc
));
212 doc
= do_QueryInterface(domDoc
);
213 if (!doc
) return NS_OK
;
214 // the only case where there could be more shells in printpreview
215 nsIPresShell
*shell
= doc
->GetPrimaryShell();
216 NS_ENSURE_TRUE(shell
, NS_ERROR_FAILURE
);
217 mViewManager
= shell
->GetViewManager();
218 NS_ENSURE_TRUE(mViewManager
, NS_ERROR_FAILURE
);
219 mViewManager
->GetWidget(getter_AddRefs(mWidget
));
220 NS_ENSURE_TRUE(mWidget
, NS_ERROR_FAILURE
);
222 NS_ADDREF(*aWidget
= mWidget
);
224 NS_ADDREF(*aViewManager
= mViewManager
);
229 nsWidgetUtils::MouseDown(nsIDOMEvent
* aDOMEvent
)
231 g_is_scrollable
= PR_FALSE
;
232 // Return TRUE from your signal handler to mark the event as consumed.
233 if (NS_FAILED(UpdateFromEvent(aDOMEvent
)))
235 g_is_scrollable
= PR_TRUE
;
236 if (g_is_scrollable
) {
237 aDOMEvent
->StopPropagation();
238 aDOMEvent
->PreventDefault();
244 nsWidgetUtils::StopPanningCallback(nsITimer
*timer
, void *closure
)
246 g_panning
= PR_FALSE
;
250 nsWidgetUtils::MouseUp(nsIDOMEvent
* aDOMEvent
)
252 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
;
253 mouseEvent
= do_QueryInterface(aDOMEvent
);
256 // Return TRUE from your signal handler to mark the event as consumed.
259 g_is_scrollable
= PR_FALSE
;
261 aDOMEvent
->StopPropagation();
262 aDOMEvent
->PreventDefault();
265 rv
= mTimer
->InitWithFuncCallback(nsWidgetUtils::StopPanningCallback
,
266 nsnull
, 500, nsITimer::TYPE_ONE_SHOT
);
267 if (NS_SUCCEEDED(rv
))
270 g_panning
= PR_FALSE
;
276 nsWidgetUtils::MouseMove(nsIDOMEvent
* aDOMEvent
)
278 if (!g_is_scrollable
) return NS_OK
;
280 nsCOMPtr
<nsIDOMMouseEvent
> mouseEvent
= do_QueryInterface(aDOMEvent
);
284 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenX(&x
);
285 ((nsIDOMMouseEvent
*)mouseEvent
)->GetScreenY(&y
);
287 int dx
= g_lastX
- x
;
288 int dy
= g_lastY
- y
;
289 if(g_lastX
== MIN_INT
|| g_lastY
== MIN_INT
)
292 nsIView
*aView
= nsnull
;
293 mViewManager
->GetRootView(aView
);
295 if (NS_FAILED(UpdateFromEvent(aDOMEvent
)))
298 nsEventStatus statusX
;
299 nsMouseScrollEvent
scrollEventX(PR_TRUE
, NS_MOUSE_SCROLL
, mWidget
);
300 scrollEventX
.delta
= dx
;
301 scrollEventX
.scrollFlags
= nsMouseScrollEvent::kIsHorizontal
| nsMouseScrollEvent::kIsPixels
;
302 mViewManager
->DispatchEvent(&scrollEventX
, &statusX
);
303 if(statusX
!= nsEventStatus_eIgnore
){
309 nsEventStatus statusY
;
310 nsMouseScrollEvent
scrollEventY(PR_TRUE
, NS_MOUSE_SCROLL
, mWidget
);
311 scrollEventY
.delta
= dy
;
312 scrollEventY
.scrollFlags
= nsMouseScrollEvent::kIsVertical
| nsMouseScrollEvent::kIsPixels
;
313 mViewManager
->DispatchEvent(&scrollEventY
, &statusY
);
314 if(statusY
!= nsEventStatus_eIgnore
){
320 aDOMEvent
->StopPropagation();
321 aDOMEvent
->PreventDefault();
327 // nsIContentPolicy Implementation
329 nsWidgetUtils::ShouldLoad(PRUint32 aContentType
,
330 nsIURI
*aContentLocation
,
331 nsIURI
*aRequestingLocation
,
332 nsISupports
*aRequestingContext
,
333 const nsACString
&aMimeGuess
,
337 *aDecision
= nsIContentPolicy::ACCEPT
;
340 if (aContentType
!= nsIContentPolicy::TYPE_DOCUMENT
)
343 // we can't do anything without this
344 if (!aContentLocation
)
347 nsCAutoString scheme
;
348 rv
= aContentLocation
->GetScheme(scheme
);
349 nsCAutoString lscheme
;
350 ToLowerCase(scheme
, lscheme
);
351 if (!lscheme
.EqualsLiteral("ftp") &&
352 !lscheme
.EqualsLiteral("http") &&
353 !lscheme
.EqualsLiteral("https"))
356 *aDecision
= nsIContentPolicy::REJECT_REQUEST
;
361 nsWidgetUtils::MouseClick(nsIDOMEvent
* aDOMEvent
)
367 nsWidgetUtils::MouseDblClick(nsIDOMEvent
* aDOMEvent
)
373 nsWidgetUtils::HandleEvent(nsIDOMEvent
* aDOMEvent
)
379 nsWidgetUtils::MouseOver(nsIDOMEvent
* aDOMEvent
)
385 nsWidgetUtils::MouseOut(nsIDOMEvent
* aDOMEvent
)
392 nsWidgetUtils::DragMove(nsIDOMEvent
* aDOMEvent
)
398 nsWidgetUtils::ShouldProcess(PRUint32 aContentType
,
399 nsIURI
*aContentLocation
,
400 nsIURI
*aRequestingLocation
,
401 nsISupports
*aRequestingContext
,
402 const nsACString
&aMimeGuess
,
406 *aDecision
= nsIContentPolicy::ACCEPT
;
411 nsWidgetUtils::IsXULNode(nsIDOMNode
*aNode
, PRUint32
*aType
)
413 PRBool retval
= PR_FALSE
;
414 if (!aNode
) return retval
;
417 aNode
->GetNodeName(sorigNode
);
418 if (sorigNode
.EqualsLiteral("#document"))
420 retval
= StringBeginsWith(sorigNode
, NS_LITERAL_STRING("xul:"));
422 if (!aType
) return retval
;
424 if (sorigNode
.EqualsLiteral("xul:thumb")
425 || sorigNode
.EqualsLiteral("xul:vbox")
426 || sorigNode
.EqualsLiteral("xul:spacer"))
427 *aType
= PR_FALSE
; // Magic
428 else if (sorigNode
.EqualsLiteral("xul:slider"))
430 else if (sorigNode
.EqualsLiteral("xul:scrollbarbutton"))
437 nsWidgetUtils::GetDOMWindowByNode(nsIDOMNode
*aNode
, nsIDOMWindow
* *aDOMWindow
)
440 nsCOMPtr
<nsIDOMDocument
> nodeDoc
;
441 rv
= aNode
->GetOwnerDocument(getter_AddRefs(nodeDoc
));
442 NS_ENSURE_SUCCESS(rv
, rv
);
443 nsCOMPtr
<nsIDOMDocumentView
> docView
= do_QueryInterface(nodeDoc
, &rv
);
444 NS_ENSURE_SUCCESS(rv
, rv
);
445 nsCOMPtr
<nsIDOMAbstractView
> absView
;
446 NS_ENSURE_SUCCESS(rv
, rv
);
447 rv
= docView
->GetDefaultView(getter_AddRefs(absView
));
448 NS_ENSURE_SUCCESS(rv
, rv
);
449 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryInterface(absView
, &rv
);
450 NS_ENSURE_SUCCESS(rv
, rv
);
451 *aDOMWindow
= window
;
452 NS_IF_ADDREF(*aDOMWindow
);
457 nsWidgetUtils::GetChromeEventHandler(nsIDOMWindow
*aDOMWin
,
458 nsIDOMEventTarget
**aChromeTarget
)
460 nsCOMPtr
<nsPIDOMWindow
> privateDOMWindow(do_QueryInterface(aDOMWin
));
461 nsPIDOMEventTarget
* chromeEventHandler
= nsnull
;
462 if (privateDOMWindow
) {
463 chromeEventHandler
= privateDOMWindow
->GetChromeEventHandler();
466 nsCOMPtr
<nsIDOMEventTarget
> target(do_QueryInterface(chromeEventHandler
));
468 *aChromeTarget
= target
;
469 NS_IF_ADDREF(*aChromeTarget
);
473 nsWidgetUtils::RemoveWindowListeners(nsIDOMWindow
*aDOMWin
)
476 nsCOMPtr
<nsIDOMEventTarget
> chromeEventHandler
;
477 GetChromeEventHandler(aDOMWin
, getter_AddRefs(chromeEventHandler
));
478 if (!chromeEventHandler
) {
482 // Use capturing, otherwise the normal find next will get activated when ours should
483 nsCOMPtr
<nsPIDOMEventTarget
> piTarget(do_QueryInterface(chromeEventHandler
));
485 // Remove DOM Text listener for IME text events
486 rv
= piTarget
->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener
*>(this),
487 NS_GET_IID(nsIDOMMouseListener
));
489 NS_WARNING("Failed to add Mouse Motion listener\n");
492 rv
= piTarget
->RemoveEventListenerByIID(static_cast<nsIDOMMouseMotionListener
*>(this),
493 NS_GET_IID(nsIDOMMouseMotionListener
));
495 NS_WARNING("Failed to add Mouse Motion listener\n");
501 nsWidgetUtils::AttachWindowListeners(nsIDOMWindow
*aDOMWin
)
504 nsCOMPtr
<nsIDOMEventTarget
> chromeEventHandler
;
505 GetChromeEventHandler(aDOMWin
, getter_AddRefs(chromeEventHandler
));
506 if (!chromeEventHandler
) {
510 // Use capturing, otherwise the normal find next will get activated when ours should
511 nsCOMPtr
<nsPIDOMEventTarget
> piTarget(do_QueryInterface(chromeEventHandler
));
513 // Attach menu listeners, this will help us ignore keystrokes meant for menus
514 rv
= piTarget
->AddEventListenerByIID(static_cast<nsIDOMMouseListener
*>(this),
515 NS_GET_IID(nsIDOMMouseListener
));
517 NS_WARNING("Failed to add Mouse Motion listener\n");
520 rv
= piTarget
->AddEventListenerByIID(static_cast<nsIDOMMouseMotionListener
*>(this),
521 NS_GET_IID(nsIDOMMouseMotionListener
));
523 NS_WARNING("Failed to add Mouse Motion listener\n");
528 nsWidgetUtils::~nsWidgetUtils()
532 NS_IMPL_ISUPPORTS5(nsWidgetUtils
, nsIObserver
, nsIDOMMouseMotionListener
, nsIDOMMouseListener
, nsIContentPolicy
, nsISupportsWeakReference
)
535 nsWidgetUtils::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*aData
)
538 if (!strcmp(aTopic
,"domwindowopened"))
540 nsCOMPtr
<nsIDOMWindow
> chromeWindow
= do_QueryInterface(aSubject
);
542 AttachWindowListeners(chromeWindow
);
546 if (!strcmp(aTopic
,"domwindowclosed"))
548 nsCOMPtr
<nsIDOMWindow
> chromeWindow
= do_QueryInterface(aSubject
);
549 RemoveWindowListeners(chromeWindow
);
556 //------------------------------------------------------------------------------
557 // XPCOM REGISTRATION BELOW
558 //------------------------------------------------------------------------------
560 #define WidgetUtils_CID \
561 { 0x0ced17b6, 0x96ed, 0x4030, \
562 {0xa1, 0x34, 0x77, 0xcb, 0x66, 0x10, 0xa8, 0xf6} }
564 #define WidgetUtils_ContractID "@mozilla.org/extensions/widgetutils;1"
566 static NS_METHOD
WidgetUtilsRegistration(nsIComponentManager
*aCompMgr
,
568 const char *registryLocation
,
569 const char *componentType
,
570 const nsModuleComponentInfo
*info
)
574 nsCOMPtr
<nsIServiceManager
> servman
= do_QueryInterface((nsISupports
*)aCompMgr
, &rv
);
578 nsCOMPtr
<nsICategoryManager
> catman
;
579 servman
->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID
,
580 NS_GET_IID(nsICategoryManager
),
581 getter_AddRefs(catman
));
586 char* previous
= nsnull
;
587 rv
= catman
->AddCategoryEntry("app-startup",
589 WidgetUtils_ContractID
,
594 nsMemory::Free(previous
);
595 rv
= catman
->AddCategoryEntry("content-policy",
597 WidgetUtils_ContractID
,
602 nsMemory::Free(previous
);
607 static NS_METHOD
WidgetUtilsUnregistration(nsIComponentManager
*aCompMgr
,
609 const char *registryLocation
,
610 const nsModuleComponentInfo
*info
)
614 nsCOMPtr
<nsIServiceManager
> servman
= do_QueryInterface((nsISupports
*)aCompMgr
, &rv
);
618 nsCOMPtr
<nsICategoryManager
> catman
;
619 servman
->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID
,
620 NS_GET_IID(nsICategoryManager
),
621 getter_AddRefs(catman
));
626 rv
= catman
->DeleteCategoryEntry("app-startup",
629 rv
= catman
->DeleteCategoryEntry("content-policy",
636 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWidgetUtils
)
638 static const nsModuleComponentInfo components
[] =
640 { "nsWidgetUtilsService",
642 WidgetUtils_ContractID
,
643 nsWidgetUtilsConstructor
,
644 WidgetUtilsRegistration
,
645 WidgetUtilsUnregistration
649 NS_IMPL_NSGETMODULE(nsWidgetUtilsModule
, components
)