Back to index

lightning-sunbird  0.9+nobinonly
nsEventListenerManager.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsISupports.h"
00039 #include "nsGUIEvent.h"
00040 #include "nsDOMEvent.h"
00041 #include "nsEventListenerManager.h"
00042 #include "nsICaret.h"
00043 #include "nsIFrameSelection.h"
00044 #include "nsIDOMNSEvent.h"
00045 #include "nsIDOMEventListener.h"
00046 #include "nsIDOMMouseListener.h"
00047 #include "nsIDOMMouseMotionListener.h"
00048 #include "nsIDOMContextMenuListener.h"
00049 #include "nsIDOMKeyListener.h"
00050 #include "nsIDOMFocusListener.h"
00051 #include "nsIDOMFormListener.h"
00052 #include "nsIDOMLoadListener.h"
00053 #include "nsIDOMDragListener.h"
00054 #include "nsIDOMPaintListener.h"
00055 #include "nsIDOMTextListener.h"
00056 #include "nsIDOMCompositionListener.h"
00057 #include "nsIDOMXULListener.h"
00058 #include "nsIDOMScrollListener.h"
00059 #include "nsIDOMMutationListener.h"
00060 #include "nsIDOMUIListener.h"
00061 #include "nsIDOMPageTransitionListener.h"
00062 #include "nsITextControlFrame.h"
00063 #ifdef MOZ_SVG
00064 #include "nsIDOMSVGListener.h"
00065 #include "nsIDOMSVGZoomListener.h"
00066 #include "nsSVGAtoms.h"
00067 #endif // MOZ_SVG
00068 #include "nsIEventStateManager.h"
00069 #include "nsPIDOMWindow.h"
00070 #include "nsIPrivateDOMEvent.h"
00071 #include "nsIJSEventListener.h"
00072 #include "prmem.h"
00073 #include "nsIScriptGlobalObject.h"
00074 #include "nsLayoutAtoms.h"
00075 #include "nsLayoutUtils.h"
00076 #ifdef MOZ_XUL
00077 // XXXbz the fact that this is ifdef MOZ_XUL is good indication that
00078 // it doesn't belong here...
00079 #include "nsITreeBoxObject.h"
00080 #include "nsITreeColumns.h"
00081 #include "nsIDOMXULMultSelectCntrlEl.h"
00082 #endif
00083 #include "nsINameSpaceManager.h"
00084 #include "nsIContent.h"
00085 #include "nsINodeInfo.h"
00086 #include "nsIFrame.h"
00087 #include "nsIView.h"
00088 #include "nsIViewManager.h"
00089 #include "nsIScrollableView.h"
00090 #include "nsCOMPtr.h"
00091 #include "nsIServiceManager.h"
00092 #include "nsIScriptSecurityManager.h"
00093 #include "nsDOMError.h"
00094 #include "nsIJSContextStack.h"
00095 #include "nsIDocument.h"
00096 #include "nsIPresShell.h"
00097 #include "nsMutationEvent.h"
00098 #include "nsIXPConnect.h"
00099 #include "nsDOMCID.h"
00100 #include "nsIScriptObjectOwner.h" // for nsIScriptEventHandlerOwner
00101 #include "nsIClassInfo.h"
00102 #include "nsIFocusController.h"
00103 #include "nsIDOMElement.h"
00104 #include "nsIBoxObject.h"
00105 #include "nsIDOMNSDocument.h"
00106 #include "nsIWidget.h"
00107 #include "nsContentUtils.h"
00108 #include "nsJSUtils.h"
00109 #include "nsIDOMEventGroup.h"
00110 #include "nsContentCID.h"
00111 
00112 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
00113                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
00114 static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
00115 
00116 typedef
00117 NS_STDCALL_FUNCPROTO(nsresult,
00118                      GenericHandler,
00119                      nsIDOMEventListener, HandleEvent, 
00120                      (nsIDOMEvent*));
00121 
00122 /*
00123  * Things here are not as they appear.  Namely, |ifaceListener| below is
00124  * not really a pointer to the nsIDOMEventListener interface, and aMethod is
00125  * not really a pointer-to-member for nsIDOMEventListener.  They both
00126  * actually refer to the event-type-specific listener interface.  The casting
00127  * magic allows us to use a single dispatch method.  This relies on the
00128  * assumption that nsIDOMEventListener and the event type listener interfaces
00129  * have the same object layout and will therefore have compatible
00130  * pointer-to-member implementations.
00131  */
00132 
00133 static nsresult DispatchToInterface(nsIDOMEvent* aEvent,
00134                                     nsIDOMEventListener* aListener,
00135                                     GenericHandler aMethod,
00136                                     const nsIID& aIID,
00137                                     PRBool* aHasInterface)
00138 {
00139   nsIDOMEventListener* ifaceListener = nsnull;
00140   nsresult rv = NS_OK;
00141   aListener->QueryInterface(aIID, (void**) &ifaceListener);
00142   if (ifaceListener) {
00143     *aHasInterface = PR_TRUE;
00144     rv = (ifaceListener->*aMethod)(aEvent);
00145     NS_RELEASE(ifaceListener);
00146   }
00147   return rv;
00148 }
00149 
00150 struct EventDispatchData
00151 {
00152   PRUint32 message;
00153   GenericHandler method;
00154   PRUint8 bits;
00155 };
00156 
00157 struct EventTypeData
00158 {
00159   const EventDispatchData* events;
00160   int                      numEvents;
00161   const nsIID*             iid;
00162 };
00163 
00164 #define HANDLER(x) NS_REINTERPRET_CAST(GenericHandler, x)
00165 
00166 static const EventDispatchData sMouseEvents[] = {
00167   { NS_MOUSE_LEFT_BUTTON_DOWN,   HANDLER(&nsIDOMMouseListener::MouseDown),
00168     NS_EVENT_BITS_MOUSE_MOUSEDOWN },
00169   { NS_MOUSE_MIDDLE_BUTTON_DOWN, HANDLER(&nsIDOMMouseListener::MouseDown),
00170     NS_EVENT_BITS_MOUSE_MOUSEDOWN },
00171   { NS_MOUSE_RIGHT_BUTTON_DOWN,  HANDLER(&nsIDOMMouseListener::MouseDown),
00172     NS_EVENT_BITS_MOUSE_MOUSEDOWN },
00173   { NS_MOUSE_LEFT_BUTTON_UP,     HANDLER(&nsIDOMMouseListener::MouseUp),
00174     NS_EVENT_BITS_MOUSE_MOUSEUP },
00175   { NS_MOUSE_MIDDLE_BUTTON_UP,   HANDLER(&nsIDOMMouseListener::MouseUp),
00176     NS_EVENT_BITS_MOUSE_MOUSEUP },
00177   { NS_MOUSE_RIGHT_BUTTON_UP,    HANDLER(&nsIDOMMouseListener::MouseUp),
00178     NS_EVENT_BITS_MOUSE_MOUSEUP },
00179   { NS_MOUSE_LEFT_CLICK,         HANDLER(&nsIDOMMouseListener::MouseClick),
00180     NS_EVENT_BITS_MOUSE_CLICK },
00181   { NS_MOUSE_MIDDLE_CLICK,       HANDLER(&nsIDOMMouseListener::MouseClick),
00182     NS_EVENT_BITS_MOUSE_CLICK },
00183   { NS_MOUSE_RIGHT_CLICK,        HANDLER(&nsIDOMMouseListener::MouseClick),
00184     NS_EVENT_BITS_MOUSE_CLICK },
00185   { NS_MOUSE_LEFT_DOUBLECLICK,   HANDLER(&nsIDOMMouseListener::MouseDblClick),
00186     NS_EVENT_BITS_MOUSE_DBLCLICK },
00187   { NS_MOUSE_MIDDLE_DOUBLECLICK, HANDLER(&nsIDOMMouseListener::MouseDblClick),
00188     NS_EVENT_BITS_MOUSE_DBLCLICK },
00189   { NS_MOUSE_RIGHT_DOUBLECLICK,  HANDLER(&nsIDOMMouseListener::MouseDblClick),
00190     NS_EVENT_BITS_MOUSE_DBLCLICK },
00191   { NS_MOUSE_ENTER_SYNTH,        HANDLER(&nsIDOMMouseListener::MouseOver),
00192     NS_EVENT_BITS_MOUSE_MOUSEOVER },
00193   { NS_MOUSE_EXIT_SYNTH,         HANDLER(&nsIDOMMouseListener::MouseOut),
00194     NS_EVENT_BITS_MOUSE_MOUSEOUT }
00195 };
00196 
00197 static const EventDispatchData sMouseMotionEvents[] = {
00198   { NS_MOUSE_MOVE, HANDLER(&nsIDOMMouseMotionListener::MouseMove),
00199     NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE }
00200 };
00201 
00202 static const EventDispatchData sContextMenuEvents[] = {
00203   { NS_CONTEXTMENU,     HANDLER(&nsIDOMContextMenuListener::ContextMenu),
00204     NS_EVENT_BITS_CONTEXT_MENU },
00205   { NS_CONTEXTMENU_KEY, HANDLER(&nsIDOMContextMenuListener::ContextMenu),
00206     NS_EVENT_BITS_CONTEXT_MENU }
00207 };
00208 
00209 static const EventDispatchData sCompositionEvents[] = {
00210   { NS_COMPOSITION_START,  HANDLER(&nsIDOMCompositionListener::HandleStartComposition),
00211     NS_EVENT_BITS_COMPOSITION_START },
00212   { NS_COMPOSITION_END,    HANDLER(&nsIDOMCompositionListener::HandleEndComposition),
00213     NS_EVENT_BITS_COMPOSITION_END },
00214   { NS_COMPOSITION_QUERY,  HANDLER(&nsIDOMCompositionListener::HandleQueryComposition),
00215     NS_EVENT_BITS_COMPOSITION_QUERY },
00216   { NS_RECONVERSION_QUERY, HANDLER(&nsIDOMCompositionListener::HandleQueryReconversion),
00217     NS_EVENT_BITS_COMPOSITION_RECONVERSION },
00218   { NS_QUERYCARETRECT,  HANDLER(&nsIDOMCompositionListener::HandleQueryCaretRect),
00219     NS_EVENT_BITS_COMPOSITION_QUERYCARETRECT }
00220 };
00221 
00222 static const EventDispatchData sTextEvents[] = {
00223   {NS_TEXT_TEXT,HANDLER(&nsIDOMTextListener::HandleText),NS_EVENT_BITS_TEXT_TEXT},
00224 };
00225 
00226 static const EventDispatchData sKeyEvents[] = {
00227   {NS_KEY_UP,   HANDLER(&nsIDOMKeyListener::KeyUp),   NS_EVENT_BITS_KEY_KEYUP},
00228   {NS_KEY_DOWN, HANDLER(&nsIDOMKeyListener::KeyDown), NS_EVENT_BITS_KEY_KEYDOWN},
00229   {NS_KEY_PRESS,HANDLER(&nsIDOMKeyListener::KeyPress),NS_EVENT_BITS_KEY_KEYPRESS},
00230 };
00231 
00232 static const EventDispatchData sFocusEvents[] = {
00233   {NS_FOCUS_CONTENT,HANDLER(&nsIDOMFocusListener::Focus),NS_EVENT_BITS_FOCUS_FOCUS},
00234   {NS_BLUR_CONTENT, HANDLER(&nsIDOMFocusListener::Blur), NS_EVENT_BITS_FOCUS_BLUR }
00235 };
00236 
00237 static const EventDispatchData sFormEvents[] = {
00238   {NS_FORM_SUBMIT,  HANDLER(&nsIDOMFormListener::Submit),NS_EVENT_BITS_FORM_SUBMIT},
00239   {NS_FORM_RESET,   HANDLER(&nsIDOMFormListener::Reset), NS_EVENT_BITS_FORM_RESET},
00240   {NS_FORM_CHANGE,  HANDLER(&nsIDOMFormListener::Change),NS_EVENT_BITS_FORM_CHANGE},
00241   {NS_FORM_SELECTED,HANDLER(&nsIDOMFormListener::Select),NS_EVENT_BITS_FORM_SELECT},
00242   {NS_FORM_INPUT,   HANDLER(&nsIDOMFormListener::Input), NS_EVENT_BITS_FORM_INPUT}
00243 };
00244 
00245 static const EventDispatchData sLoadEvents[] = {
00246   {NS_PAGE_LOAD,   HANDLER(&nsIDOMLoadListener::Load),  NS_EVENT_BITS_LOAD_LOAD},
00247   {NS_IMAGE_LOAD,  HANDLER(&nsIDOMLoadListener::Load),  NS_EVENT_BITS_LOAD_LOAD},
00248   {NS_SCRIPT_LOAD, HANDLER(&nsIDOMLoadListener::Load),  NS_EVENT_BITS_LOAD_LOAD},
00249   {NS_PAGE_UNLOAD, HANDLER(&nsIDOMLoadListener::Unload),NS_EVENT_BITS_LOAD_UNLOAD},
00250   {NS_IMAGE_ERROR, HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR},
00251   {NS_SCRIPT_ERROR,HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR},
00252   {NS_BEFORE_PAGE_UNLOAD,HANDLER(&nsIDOMLoadListener::BeforeUnload), NS_EVENT_BITS_LOAD_BEFORE_UNLOAD},
00253 };
00254 
00255 static const EventDispatchData sPaintEvents[] = {
00256   {NS_PAINT,       HANDLER(&nsIDOMPaintListener::Paint), NS_EVENT_BITS_PAINT_PAINT},
00257   {NS_RESIZE_EVENT,HANDLER(&nsIDOMPaintListener::Resize),NS_EVENT_BITS_PAINT_RESIZE},
00258   {NS_SCROLL_EVENT,HANDLER(&nsIDOMPaintListener::Scroll),NS_EVENT_BITS_PAINT_SCROLL}
00259 };
00260 
00261 static const EventDispatchData sDragEvents[] = {
00262   {NS_DRAGDROP_ENTER,     HANDLER(&nsIDOMDragListener::DragEnter),  NS_EVENT_BITS_DRAG_ENTER},
00263   {NS_DRAGDROP_OVER_SYNTH,HANDLER(&nsIDOMDragListener::DragOver),   NS_EVENT_BITS_DRAG_OVER},
00264   {NS_DRAGDROP_EXIT_SYNTH,HANDLER(&nsIDOMDragListener::DragExit),   NS_EVENT_BITS_DRAG_EXIT},
00265   {NS_DRAGDROP_DROP,      HANDLER(&nsIDOMDragListener::DragDrop),   NS_EVENT_BITS_DRAG_DROP},
00266   {NS_DRAGDROP_GESTURE,   HANDLER(&nsIDOMDragListener::DragGesture),NS_EVENT_BITS_DRAG_GESTURE}
00267 };
00268 
00269 static const EventDispatchData sScrollEvents[] = {
00270   { NS_SCROLLPORT_OVERFLOW,        HANDLER(&nsIDOMScrollListener::Overflow),
00271     NS_EVENT_BITS_SCROLLPORT_OVERFLOW },
00272   { NS_SCROLLPORT_UNDERFLOW,       HANDLER(&nsIDOMScrollListener::Underflow),
00273     NS_EVENT_BITS_SCROLLPORT_UNDERFLOW },
00274   { NS_SCROLLPORT_OVERFLOWCHANGED, HANDLER(&nsIDOMScrollListener::OverflowChanged),
00275     NS_EVENT_BITS_SCROLLPORT_OVERFLOWCHANGED }
00276 };
00277 
00278 static const EventDispatchData sXULEvents[] = {
00279   { NS_XUL_POPUP_SHOWING,  HANDLER(&nsIDOMXULListener::PopupShowing),
00280     NS_EVENT_BITS_XUL_POPUP_SHOWING },
00281   { NS_XUL_POPUP_SHOWN,    HANDLER(&nsIDOMXULListener::PopupShown),
00282     NS_EVENT_BITS_XUL_POPUP_SHOWN },
00283   { NS_XUL_POPUP_HIDING,   HANDLER(&nsIDOMXULListener::PopupHiding),
00284     NS_EVENT_BITS_XUL_POPUP_HIDING },
00285   { NS_XUL_POPUP_HIDDEN,   HANDLER(&nsIDOMXULListener::PopupHidden),
00286     NS_EVENT_BITS_XUL_POPUP_HIDDEN },
00287   { NS_XUL_CLOSE,          HANDLER(&nsIDOMXULListener::Close),
00288     NS_EVENT_BITS_XUL_CLOSE },
00289   { NS_XUL_COMMAND,        HANDLER(&nsIDOMXULListener::Command),
00290     NS_EVENT_BITS_XUL_COMMAND },
00291   { NS_XUL_BROADCAST,      HANDLER(&nsIDOMXULListener::Broadcast),
00292     NS_EVENT_BITS_XUL_BROADCAST },
00293   { NS_XUL_COMMAND_UPDATE, HANDLER(&nsIDOMXULListener::CommandUpdate),
00294     NS_EVENT_BITS_XUL_COMMAND_UPDATE }
00295 };
00296 
00297 static const EventDispatchData sMutationEvents[] = {
00298   { NS_MUTATION_SUBTREEMODIFIED,
00299     HANDLER(&nsIDOMMutationListener::SubtreeModified),
00300     NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED },
00301   { NS_MUTATION_NODEINSERTED,
00302     HANDLER(&nsIDOMMutationListener::NodeInserted),
00303     NS_EVENT_BITS_MUTATION_NODEINSERTED },
00304   { NS_MUTATION_NODEREMOVED,
00305     HANDLER(&nsIDOMMutationListener::NodeRemoved),
00306     NS_EVENT_BITS_MUTATION_NODEREMOVED },
00307   { NS_MUTATION_NODEINSERTEDINTODOCUMENT,
00308     HANDLER(&nsIDOMMutationListener::NodeInsertedIntoDocument),
00309     NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT },
00310   { NS_MUTATION_NODEREMOVEDFROMDOCUMENT,
00311     HANDLER(&nsIDOMMutationListener::NodeRemovedFromDocument),
00312     NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT },
00313   { NS_MUTATION_ATTRMODIFIED,
00314     HANDLER(&nsIDOMMutationListener::AttrModified),
00315     NS_EVENT_BITS_MUTATION_ATTRMODIFIED },
00316   { NS_MUTATION_CHARACTERDATAMODIFIED,
00317     HANDLER(&nsIDOMMutationListener::CharacterDataModified),
00318     NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED }
00319 };
00320 
00321 static const EventDispatchData sUIEvents[] = {
00322   { NS_UI_ACTIVATE, HANDLER(&nsIDOMUIListener::Activate),
00323     NS_EVENT_BITS_UI_ACTIVATE },
00324   { NS_UI_FOCUSIN, HANDLER(&nsIDOMUIListener::FocusIn),
00325     NS_EVENT_BITS_UI_FOCUSIN },
00326   { NS_UI_FOCUSOUT, HANDLER(&nsIDOMUIListener::FocusOut),
00327     NS_EVENT_BITS_UI_FOCUSOUT }
00328 };
00329 
00330 static const EventDispatchData sPageTransitionEvents[] = {
00331   { NS_PAGE_SHOW, HANDLER(&nsIDOMPageTransitionListener::PageShow),
00332     NS_EVENT_BITS_PAGETRANSITION_SHOW },
00333   { NS_PAGE_HIDE, HANDLER(&nsIDOMPageTransitionListener::PageHide),
00334     NS_EVENT_BITS_PAGETRANSITION_HIDE }
00335 };
00336 
00337 #ifdef MOZ_SVG
00338 static const EventDispatchData sSVGEvents[] = {
00339   { NS_SVG_LOAD, HANDLER(&nsIDOMSVGListener::Load),
00340     NS_EVENT_BITS_SVG_LOAD },
00341   { NS_SVG_UNLOAD, HANDLER(&nsIDOMSVGListener::Unload),
00342     NS_EVENT_BITS_SVG_UNLOAD },
00343   { NS_SVG_ABORT, HANDLER(&nsIDOMSVGListener::Abort),
00344     NS_EVENT_BITS_SVG_ABORT },
00345   { NS_SVG_ERROR, HANDLER(&nsIDOMSVGListener::Error),
00346     NS_EVENT_BITS_SVG_ERROR },
00347   { NS_SVG_RESIZE, HANDLER(&nsIDOMSVGListener::Resize),
00348     NS_EVENT_BITS_SVG_RESIZE },
00349   { NS_SVG_SCROLL, HANDLER(&nsIDOMSVGListener::Scroll),
00350     NS_EVENT_BITS_SVG_SCROLL }
00351 };
00352 
00353 static const EventDispatchData sSVGZoomEvents[] = {
00354   { NS_SVG_ZOOM, HANDLER(&nsIDOMSVGZoomListener::Zoom),
00355     NS_EVENT_BITS_SVGZOOM_ZOOM }
00356 };
00357 #endif // MOZ_SVG
00358 
00359 #define IMPL_EVENTTYPEDATA(type) \
00360 { \
00361   s##type##Events, \
00362   NS_ARRAY_LENGTH(s##type##Events), \
00363   &NS_GET_IID(nsIDOM##type##Listener) \
00364 }
00365  
00366 // IMPORTANT: indices match up with eEventArrayType_ enum values
00367 
00368 static const EventTypeData sEventTypes[] = {
00369   IMPL_EVENTTYPEDATA(Mouse),
00370   IMPL_EVENTTYPEDATA(MouseMotion),
00371   IMPL_EVENTTYPEDATA(ContextMenu),
00372   IMPL_EVENTTYPEDATA(Key),
00373   IMPL_EVENTTYPEDATA(Load),
00374   IMPL_EVENTTYPEDATA(Focus),
00375   IMPL_EVENTTYPEDATA(Form),
00376   IMPL_EVENTTYPEDATA(Drag),
00377   IMPL_EVENTTYPEDATA(Paint),
00378   IMPL_EVENTTYPEDATA(Text),
00379   IMPL_EVENTTYPEDATA(Composition),
00380   IMPL_EVENTTYPEDATA(XUL),
00381   IMPL_EVENTTYPEDATA(Scroll),
00382   IMPL_EVENTTYPEDATA(Mutation),
00383   IMPL_EVENTTYPEDATA(UI),
00384   IMPL_EVENTTYPEDATA(PageTransition)
00385 #ifdef MOZ_SVG
00386  ,
00387   IMPL_EVENTTYPEDATA(SVG),
00388   IMPL_EVENTTYPEDATA(SVGZoom)
00389 #endif // MOZ_SVG
00390 };
00391 
00392 // Strong references to event groups
00393 nsIDOMEventGroup* gSystemEventGroup;
00394 nsIDOMEventGroup* gDOM2EventGroup;
00395 
00396 PRUint32 nsEventListenerManager::mInstanceCount = 0;
00397 
00398 nsEventListenerManager::nsEventListenerManager() :
00399   mManagerType(NS_ELM_NONE),
00400   mListenersRemoved(PR_FALSE),
00401   mSingleListenerType(eEventArrayType_None),
00402   mSingleListener(nsnull),
00403   mMultiListeners(nsnull),
00404   mGenericListeners(nsnull),
00405   mTarget(nsnull)
00406 {
00407   ++mInstanceCount;
00408 }
00409 
00410 static PRBool PR_CALLBACK
00411 GenericListenersHashEnum(nsHashKey *aKey, void *aData, void* closure)
00412 {
00413   nsVoidArray* listeners = NS_STATIC_CAST(nsVoidArray*, aData);
00414   if (listeners) {
00415     PRInt32 i, count = listeners->Count();
00416     nsListenerStruct *ls;
00417     for (i = count-1; i >= 0; --i) {
00418       ls = (nsListenerStruct*)listeners->ElementAt(i);
00419       if (ls) {
00420         delete ls;
00421       }
00422     }
00423     delete listeners;
00424   }
00425   return PR_TRUE;
00426 }
00427 
00428 nsEventListenerManager::~nsEventListenerManager() 
00429 {
00430   RemoveAllListeners();
00431 
00432   --mInstanceCount;
00433   if(mInstanceCount == 0) {
00434     NS_IF_RELEASE(gSystemEventGroup);
00435     NS_IF_RELEASE(gDOM2EventGroup);
00436   }
00437 }
00438 
00439 nsresult
00440 nsEventListenerManager::RemoveAllListeners()
00441 {
00442   mListenersRemoved = PR_TRUE;
00443 
00444   ReleaseListeners(&mSingleListener);
00445   if (!mSingleListener) {
00446     mSingleListenerType = eEventArrayType_None;
00447     mManagerType &= ~NS_ELM_SINGLE;
00448   }
00449 
00450   if (mMultiListeners) {
00451     // XXX probably should just be i < Count()
00452     for (PRInt32 i=0; i<EVENT_ARRAY_TYPE_LENGTH && i < mMultiListeners->Count(); i++) {
00453       nsVoidArray* listeners;
00454       listeners = NS_STATIC_CAST(nsVoidArray*, mMultiListeners->ElementAt(i));
00455       ReleaseListeners(&listeners);
00456     }
00457     delete mMultiListeners;
00458     mMultiListeners = nsnull;
00459     mManagerType &= ~NS_ELM_MULTI;
00460   }
00461 
00462   if (mGenericListeners) {
00463     mGenericListeners->Enumerate(GenericListenersHashEnum, nsnull);
00464     //hash destructor
00465     delete mGenericListeners;
00466     mGenericListeners = nsnull;
00467     mManagerType &= ~NS_ELM_HASH;
00468   }
00469 
00470   return NS_OK;
00471 }
00472 
00473 void
00474 nsEventListenerManager::Shutdown()
00475 {
00476     sAddListenerID = JSVAL_VOID;
00477 
00478     nsDOMEvent::Shutdown();
00479 }
00480 
00481 NS_IMPL_ADDREF(nsEventListenerManager)
00482 NS_IMPL_RELEASE(nsEventListenerManager)
00483 
00484 
00485 NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
00486    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEventListenerManager)
00487    NS_INTERFACE_MAP_ENTRY(nsIEventListenerManager)
00488    NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
00489    NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
00490    NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
00491 NS_INTERFACE_MAP_END
00492 
00493 
00494 nsVoidArray*
00495 nsEventListenerManager::GetListenersByType(EventArrayType aType, 
00496                                            nsHashKey* aKey, PRBool aCreate)
00497 {
00498   NS_ASSERTION(aType >= 0,"Negative EventListenerType?");
00499   //Look for existing listeners
00500   if (aType == eEventArrayType_Hash && aKey && (mManagerType & NS_ELM_HASH)) {
00501     if (mGenericListeners && mGenericListeners->Exists(aKey)) {
00502       nsVoidArray* listeners = NS_STATIC_CAST(nsVoidArray*, mGenericListeners->Get(aKey));
00503       return listeners;
00504     }
00505   }
00506   else if (mManagerType & NS_ELM_SINGLE) {
00507     if (mSingleListenerType == aType) {
00508       return mSingleListener;
00509     }
00510   }
00511   else if (mManagerType & NS_ELM_MULTI) {
00512     if (mMultiListeners) {
00513       PRInt32 index = aType;
00514       if (index < mMultiListeners->Count()) {
00515         nsVoidArray* listeners;
00516         listeners = NS_STATIC_CAST(nsVoidArray*, mMultiListeners->ElementAt(index));
00517         if (listeners) {
00518           return listeners;
00519         }
00520       }
00521     }
00522   }
00523 
00524   //If we've gotten here we didn't find anything.  See if we should create something.
00525   if (aCreate) {
00526     if (aType == eEventArrayType_Hash && aKey) {
00527       if (!mGenericListeners) {
00528         mGenericListeners = new nsHashtable();
00529         if (!mGenericListeners) {
00530           //out of memory
00531           return nsnull;
00532         }
00533       }
00534       NS_ASSERTION(!(mGenericListeners->Get(aKey)), "Found existing generic listeners, should be none");
00535       nsVoidArray* listeners;
00536       listeners = new nsAutoVoidArray();
00537       if (!listeners) {
00538         //out of memory
00539         return nsnull;
00540       }
00541       mGenericListeners->Put(aKey, listeners);
00542       mManagerType |= NS_ELM_HASH;
00543       return listeners;
00544     }
00545     else {
00546       if (mManagerType & NS_ELM_SINGLE) {
00547         //Change single type into multi, then add new listener with the code for the 
00548         //multi type below
00549         NS_ASSERTION(!mMultiListeners, "Found existing multi listener array, should be none");
00550         mMultiListeners = new nsAutoVoidArray();
00551         if (!mMultiListeners) {
00552           //out of memory
00553           return nsnull;
00554         }
00555 
00556         //Move single listener to multi array
00557         mMultiListeners->ReplaceElementAt((void*)mSingleListener, mSingleListenerType);
00558         mSingleListener = nsnull;
00559 
00560         mManagerType &= ~NS_ELM_SINGLE;
00561         mManagerType |= NS_ELM_MULTI;
00562         // we'll fall through into the multi case
00563       }
00564 
00565       if (mManagerType & NS_ELM_MULTI) {
00566         PRInt32 index = aType;
00567         if (index >= 0) {
00568           nsVoidArray* listeners;
00569           NS_ASSERTION(index >= mMultiListeners->Count() || !mMultiListeners->ElementAt(index), "Found existing listeners, should be none");
00570           listeners = new nsAutoVoidArray();
00571           if (!listeners) {
00572             //out of memory
00573             return nsnull;
00574           }
00575           mMultiListeners->ReplaceElementAt((void*)listeners, index);
00576           return listeners;
00577         }
00578       }
00579       else {
00580         //We had no pre-existing type.  This is our first non-hash listener.
00581         //Create the single listener type
00582         NS_ASSERTION(!mSingleListener, "Found existing single listener array, should be none");
00583         mSingleListener = new nsAutoVoidArray();
00584         if (!mSingleListener) {
00585           //out of memory
00586           return nsnull;
00587         }
00588         mSingleListenerType = aType;
00589         mManagerType |= NS_ELM_SINGLE;
00590         return mSingleListener;
00591       }
00592     }
00593   }
00594 
00595   return nsnull;
00596 }
00597 
00598 EventArrayType
00599 nsEventListenerManager::GetTypeForIID(const nsIID& aIID)
00600 { 
00601   if (aIID.Equals(NS_GET_IID(nsIDOMMouseListener)))
00602       return eEventArrayType_Mouse;
00603 
00604   if (aIID.Equals(NS_GET_IID(nsIDOMMouseMotionListener)))
00605     return eEventArrayType_MouseMotion;
00606 
00607   if (aIID.Equals(NS_GET_IID(nsIDOMContextMenuListener)))
00608     return eEventArrayType_ContextMenu;
00609 
00610   if (aIID.Equals(NS_GET_IID(nsIDOMKeyListener)))
00611     return eEventArrayType_Key;
00612 
00613   if (aIID.Equals(NS_GET_IID(nsIDOMLoadListener)))
00614     return eEventArrayType_Load;
00615 
00616   if (aIID.Equals(NS_GET_IID(nsIDOMFocusListener)))
00617     return eEventArrayType_Focus;
00618 
00619   if (aIID.Equals(NS_GET_IID(nsIDOMFormListener)))
00620     return eEventArrayType_Form;
00621 
00622   if (aIID.Equals(NS_GET_IID(nsIDOMDragListener)))
00623     return eEventArrayType_Drag;
00624 
00625   if (aIID.Equals(NS_GET_IID(nsIDOMPaintListener)))
00626     return eEventArrayType_Paint;
00627 
00628   if (aIID.Equals(NS_GET_IID(nsIDOMTextListener)))
00629     return eEventArrayType_Text;
00630 
00631   if (aIID.Equals(NS_GET_IID(nsIDOMCompositionListener)))
00632     return eEventArrayType_Composition;
00633 
00634   if (aIID.Equals(NS_GET_IID(nsIDOMXULListener)))
00635     return eEventArrayType_XUL;
00636 
00637   if (aIID.Equals(NS_GET_IID(nsIDOMScrollListener)))
00638     return eEventArrayType_Scroll;
00639 
00640   if (aIID.Equals(NS_GET_IID(nsIDOMMutationListener)))
00641     return eEventArrayType_Mutation;
00642 
00643   if (aIID.Equals(NS_GET_IID(nsIDOMUIListener)))
00644     return eEventArrayType_DOMUI;
00645 
00646 #ifdef MOZ_SVG
00647   if (aIID.Equals(NS_GET_IID(nsIDOMSVGListener)))
00648     return eEventArrayType_SVG;
00649 
00650   if (aIID.Equals(NS_GET_IID(nsIDOMSVGZoomListener)))
00651     return eEventArrayType_SVGZoom;
00652 #endif // MOZ_SVG
00653 
00654   return eEventArrayType_None;
00655 }
00656 
00657 void
00658 nsEventListenerManager::ReleaseListeners(nsVoidArray** aListeners)
00659 {
00660   if (nsnull != *aListeners) {
00661     PRInt32 i, count = (*aListeners)->Count();
00662     nsListenerStruct *ls;
00663     for (i = 0; i < count; i++) {
00664       ls = (nsListenerStruct*)(*aListeners)->ElementAt(i);
00665       if (ls) {
00666         delete ls;
00667       }
00668     }
00669     delete *aListeners;
00670     *aListeners = nsnull;
00671   }
00672 }
00673 
00679 nsresult
00680 nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener, 
00681                                          EventArrayType aType, 
00682                                          PRInt32 aSubType,
00683                                          nsHashKey* aKey,
00684                                          PRInt32 aFlags,
00685                                          nsIDOMEventGroup* aEvtGrp)
00686 {
00687   NS_ENSURE_TRUE(aListener, NS_ERROR_FAILURE);
00688 
00689   nsVoidArray* listeners = GetListenersByType(aType, aKey, PR_TRUE);
00690 
00691   //We asked the GetListenersByType to create the array if it had to.  If it didn't
00692   //then we're out of memory (or a bug was added which passed in an unsupported
00693   //event type)
00694   if (!listeners) {
00695     return NS_ERROR_OUT_OF_MEMORY;
00696   }
00697 
00698   // For mutation listeners, we need to update the global bit on the DOM window.
00699   // Otherwise we won't actually fire the mutation event.
00700   if (aType == eEventArrayType_Mutation) {
00701     // Go from our target to the nearest enclosing DOM window.
00702     nsCOMPtr<nsIScriptGlobalObject> global;
00703     nsCOMPtr<nsIDocument> document;
00704     nsCOMPtr<nsIContent> content(do_QueryInterface(mTarget));
00705     if (content)
00706       document = content->GetOwnerDoc();
00707     else document = do_QueryInterface(mTarget);
00708     if (document)
00709       global = document->GetScriptGlobalObject();
00710     else global = do_QueryInterface(mTarget);
00711     if (global) {
00712       nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(global));
00713       window->SetMutationListeners(aSubType);
00714     }
00715   }
00716   
00717   PRBool isSame = PR_FALSE;
00718   PRUint16 group = 0;
00719   nsCOMPtr<nsIDOMEventGroup> sysGroup;
00720   GetSystemEventGroupLM(getter_AddRefs(sysGroup));
00721   if (sysGroup) {
00722     sysGroup->IsSameEventGroup(aEvtGrp, &isSame);
00723     if (isSame) {
00724       group = NS_EVENT_FLAG_SYSTEM_EVENT;
00725     }
00726   }
00727 
00728   PRBool found = PR_FALSE;
00729   nsListenerStruct* ls;
00730 
00731   for (PRInt32 i=0; i<listeners->Count(); i++) {
00732     ls = (nsListenerStruct*)listeners->ElementAt(i);
00733     nsRefPtr<nsIDOMEventListener> iListener = ls->mListener.Get();
00734     if (iListener == aListener && ls->mFlags == aFlags &&
00735         ls->mGroupFlags == group) {
00736       ls->mSubType |= aSubType;
00737       found = PR_TRUE;
00738       break;
00739     }
00740   }
00741 
00742   if (!found) {
00743     ls = new nsListenerStruct;
00744     if (!ls) {
00745       return NS_ERROR_OUT_OF_MEMORY;
00746     }
00747 
00748     nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(mTarget);
00749     NS_ASSERTION(participant, "must implement nsIDOMGCParticipant");
00750     ls->mListener.Set(aListener, participant);
00751     ls->mFlags = aFlags;
00752     ls->mSubType = aSubType;
00753     ls->mSubTypeCapture = NS_EVENT_BITS_NONE;
00754     ls->mHandlerIsString = 0;
00755     ls->mGroupFlags = group;
00756     listeners->AppendElement((void*)ls);
00757   }
00758 
00759   return NS_OK;
00760 }
00761 
00762 nsresult
00763 nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener, 
00764                                             EventArrayType aType, 
00765                                             PRInt32 aSubType,
00766                                             nsHashKey* aKey,
00767                                             PRInt32 aFlags,
00768                                             nsIDOMEventGroup* aEvtGrp)
00769 {
00770   nsVoidArray* listeners = GetListenersByType(aType, aKey, PR_FALSE);
00771 
00772   if (!listeners) {
00773     return NS_OK;
00774   }
00775 
00776   nsListenerStruct* ls;
00777   aFlags &= ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
00778 
00779   for (PRInt32 i=0; i<listeners->Count(); i++) {
00780     ls = (nsListenerStruct*)listeners->ElementAt(i);
00781     nsRefPtr<nsIDOMEventListener> iListener = ls->mListener.Get();
00782     if (iListener == aListener &&
00783         (ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) {
00784       ls->mSubType &= ~aSubType;
00785       if (ls->mSubType == NS_EVENT_BITS_NONE) {
00786         listeners->RemoveElement((void*)ls);
00787         delete ls;
00788       }
00789       break;
00790     }
00791   }
00792 
00793   return NS_OK;
00794 }
00795 
00796 nsresult
00797 nsEventListenerManager::AddEventListenerByIID(nsIDOMEventListener *aListener, 
00798                                               const nsIID& aIID,
00799                                               PRInt32 aFlags)
00800 {
00801   AddEventListener(aListener, GetTypeForIID(aIID), NS_EVENT_BITS_NONE, nsnull,
00802                    aFlags, nsnull);
00803   return NS_OK;
00804 }
00805 
00806 NS_IMETHODIMP
00807 nsEventListenerManager::RemoveEventListenerByIID(nsIDOMEventListener *aListener, 
00808                                                  const nsIID& aIID,
00809                                                  PRInt32 aFlags)
00810 {
00811   RemoveEventListener(aListener, GetTypeForIID(aIID), NS_EVENT_BITS_NONE,
00812                       nsnull, aFlags, nsnull);
00813   return NS_OK;
00814 }
00815 
00816 nsresult
00817 nsEventListenerManager::GetIdentifiersForType(nsIAtom* aType,
00818                                               EventArrayType* aArrayType,
00819                                               PRInt32* aFlags)
00820 {
00821   if (aType == nsLayoutAtoms::onmousedown) {
00822     *aArrayType = eEventArrayType_Mouse;
00823     *aFlags = NS_EVENT_BITS_MOUSE_MOUSEDOWN;
00824   }
00825   else if (aType == nsLayoutAtoms::onmouseup) {
00826     *aArrayType = eEventArrayType_Mouse;
00827     *aFlags = NS_EVENT_BITS_MOUSE_MOUSEUP;
00828   }
00829   else if (aType == nsLayoutAtoms::onclick) {
00830     *aArrayType = eEventArrayType_Mouse;
00831     *aFlags = NS_EVENT_BITS_MOUSE_CLICK;
00832   }
00833   else if (aType == nsLayoutAtoms::ondblclick) {
00834     *aArrayType = eEventArrayType_Mouse;
00835     *aFlags = NS_EVENT_BITS_MOUSE_DBLCLICK;
00836   }
00837   else if (aType == nsLayoutAtoms::onmouseover) {
00838     *aArrayType = eEventArrayType_Mouse;
00839     *aFlags = NS_EVENT_BITS_MOUSE_MOUSEOVER;
00840   }
00841   else if (aType == nsLayoutAtoms::onmouseout) {
00842     *aArrayType = eEventArrayType_Mouse;
00843     *aFlags = NS_EVENT_BITS_MOUSE_MOUSEOUT;
00844   }
00845   else if (aType == nsLayoutAtoms::onkeydown) {
00846     *aArrayType = eEventArrayType_Key;
00847     *aFlags = NS_EVENT_BITS_KEY_KEYDOWN;
00848   }
00849   else if (aType == nsLayoutAtoms::onkeyup) {
00850     *aArrayType = eEventArrayType_Key;
00851     *aFlags = NS_EVENT_BITS_KEY_KEYUP;
00852   }
00853   else if (aType == nsLayoutAtoms::onkeypress) {
00854     *aArrayType = eEventArrayType_Key;
00855     *aFlags = NS_EVENT_BITS_KEY_KEYPRESS;
00856   }
00857   else if (aType == nsLayoutAtoms::onmousemove) {
00858     *aArrayType = eEventArrayType_MouseMotion;
00859     *aFlags = NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE;
00860   }
00861   else if (aType == nsLayoutAtoms::oncontextmenu) {
00862     *aArrayType = eEventArrayType_ContextMenu;
00863     *aFlags = NS_EVENT_BITS_CONTEXTMENU;
00864   }
00865   else if (aType == nsLayoutAtoms::onfocus) {
00866     *aArrayType = eEventArrayType_Focus;
00867     *aFlags = NS_EVENT_BITS_FOCUS_FOCUS;
00868   }
00869   else if (aType == nsLayoutAtoms::onblur) {
00870     *aArrayType = eEventArrayType_Focus;
00871     *aFlags = NS_EVENT_BITS_FOCUS_BLUR;
00872   }
00873   else if (aType == nsLayoutAtoms::onsubmit) {
00874     *aArrayType = eEventArrayType_Form;
00875     *aFlags = NS_EVENT_BITS_FORM_SUBMIT;
00876   }
00877   else if (aType == nsLayoutAtoms::onreset) {
00878     *aArrayType = eEventArrayType_Form;
00879     *aFlags = NS_EVENT_BITS_FORM_RESET;
00880   }
00881   else if (aType == nsLayoutAtoms::onchange) {
00882     *aArrayType = eEventArrayType_Form;
00883     *aFlags = NS_EVENT_BITS_FORM_CHANGE;
00884   }
00885   else if (aType == nsLayoutAtoms::onselect) {
00886     *aArrayType = eEventArrayType_Form;
00887     *aFlags = NS_EVENT_BITS_FORM_SELECT;
00888   }
00889   else if (aType == nsLayoutAtoms::oninput) {
00890     *aArrayType = eEventArrayType_Form;
00891     *aFlags = NS_EVENT_BITS_FORM_INPUT;
00892   }
00893   else if (aType == nsLayoutAtoms::onload) {
00894     *aArrayType = eEventArrayType_Load;
00895     *aFlags = NS_EVENT_BITS_LOAD_LOAD;
00896   }
00897   else if (aType == nsLayoutAtoms::onbeforeunload) {
00898     *aArrayType = eEventArrayType_Load;
00899     *aFlags = NS_EVENT_BITS_LOAD_BEFORE_UNLOAD;
00900   }
00901   else if (aType == nsLayoutAtoms::onunload) {
00902     *aArrayType = eEventArrayType_Load;
00903     *aFlags = NS_EVENT_BITS_LOAD_UNLOAD;
00904   }
00905   else if (aType == nsLayoutAtoms::onabort) {
00906     *aArrayType = eEventArrayType_Load;
00907     *aFlags = NS_EVENT_BITS_LOAD_ABORT;
00908   }
00909   else if (aType == nsLayoutAtoms::onerror) {
00910     *aArrayType = eEventArrayType_Load;
00911     *aFlags = NS_EVENT_BITS_LOAD_ERROR;
00912   }
00913   else if (aType == nsLayoutAtoms::onpaint) {
00914     *aArrayType = eEventArrayType_Paint;
00915     *aFlags = NS_EVENT_BITS_PAINT_PAINT;
00916   }
00917   else if (aType == nsLayoutAtoms::onresize) {
00918     *aArrayType = eEventArrayType_Paint;
00919     *aFlags = NS_EVENT_BITS_PAINT_RESIZE;
00920   }
00921   else if (aType == nsLayoutAtoms::onscroll) {
00922     *aArrayType = eEventArrayType_Paint;
00923     *aFlags = NS_EVENT_BITS_PAINT_SCROLL;
00924   } // extened this to handle IME related events
00925   else if (aType == nsLayoutAtoms::onpopupshowing) {
00926     *aArrayType = eEventArrayType_XUL; 
00927     *aFlags = NS_EVENT_BITS_XUL_POPUP_SHOWING;
00928   }
00929   else if (aType == nsLayoutAtoms::onpopupshown) {
00930     *aArrayType = eEventArrayType_XUL; 
00931     *aFlags = NS_EVENT_BITS_XUL_POPUP_SHOWN;
00932   }
00933   else if (aType == nsLayoutAtoms::onpopuphiding) {
00934     *aArrayType = eEventArrayType_XUL; 
00935     *aFlags = NS_EVENT_BITS_XUL_POPUP_HIDING;
00936   }
00937   else if (aType == nsLayoutAtoms::onpopuphidden) {
00938     *aArrayType = eEventArrayType_XUL; 
00939     *aFlags = NS_EVENT_BITS_XUL_POPUP_HIDDEN;
00940   }
00941   else if (aType == nsLayoutAtoms::onclose) {
00942     *aArrayType = eEventArrayType_XUL; 
00943     *aFlags = NS_EVENT_BITS_XUL_CLOSE;
00944   }
00945   else if (aType == nsLayoutAtoms::oncommand) {
00946     *aArrayType = eEventArrayType_XUL; 
00947     *aFlags = NS_EVENT_BITS_XUL_COMMAND;
00948   }
00949   else if (aType == nsLayoutAtoms::onbroadcast) {
00950     *aArrayType = eEventArrayType_XUL;
00951     *aFlags = NS_EVENT_BITS_XUL_BROADCAST;
00952   }
00953   else if (aType == nsLayoutAtoms::oncommandupdate) {
00954     *aArrayType = eEventArrayType_XUL;
00955     *aFlags = NS_EVENT_BITS_XUL_COMMAND_UPDATE;
00956   }
00957   else if (aType == nsLayoutAtoms::onoverflow) {
00958     *aArrayType = eEventArrayType_Scroll;
00959     *aFlags = NS_EVENT_BITS_SCROLLPORT_OVERFLOW;
00960   }
00961   else if (aType == nsLayoutAtoms::onunderflow) {
00962     *aArrayType = eEventArrayType_Scroll;
00963     *aFlags = NS_EVENT_BITS_SCROLLPORT_UNDERFLOW;
00964   }
00965   else if (aType == nsLayoutAtoms::onoverflowchanged) {
00966     *aArrayType = eEventArrayType_Scroll;
00967     *aFlags = NS_EVENT_BITS_SCROLLPORT_OVERFLOWCHANGED;
00968   }
00969   else if (aType == nsLayoutAtoms::ondragenter) {
00970     *aArrayType = eEventArrayType_Drag;
00971     *aFlags = NS_EVENT_BITS_DRAG_ENTER;
00972   }
00973   else if (aType == nsLayoutAtoms::ondragover) {
00974     *aArrayType = eEventArrayType_Drag; 
00975     *aFlags = NS_EVENT_BITS_DRAG_OVER;
00976   }
00977   else if (aType == nsLayoutAtoms::ondragexit) {
00978     *aArrayType = eEventArrayType_Drag; 
00979     *aFlags = NS_EVENT_BITS_DRAG_EXIT;
00980   }
00981   else if (aType == nsLayoutAtoms::ondragdrop) {
00982     *aArrayType = eEventArrayType_Drag; 
00983     *aFlags = NS_EVENT_BITS_DRAG_DROP;
00984   }
00985   else if (aType == nsLayoutAtoms::ondraggesture) {
00986     *aArrayType = eEventArrayType_Drag; 
00987     *aFlags = NS_EVENT_BITS_DRAG_GESTURE;
00988   }
00989   else if (aType == nsLayoutAtoms::onDOMSubtreeModified) {
00990     *aArrayType = eEventArrayType_Mutation;
00991     *aFlags = NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED;
00992   }
00993   else if (aType == nsLayoutAtoms::onDOMNodeInserted) {
00994     *aArrayType = eEventArrayType_Mutation;
00995     *aFlags = NS_EVENT_BITS_MUTATION_NODEINSERTED;
00996   }
00997   else if (aType == nsLayoutAtoms::onDOMNodeRemoved) {
00998     *aArrayType = eEventArrayType_Mutation;
00999     *aFlags = NS_EVENT_BITS_MUTATION_NODEREMOVED;
01000   }
01001   else if (aType == nsLayoutAtoms::onDOMNodeInsertedIntoDocument) {
01002     *aArrayType = eEventArrayType_Mutation;
01003     *aFlags = NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT;
01004   }
01005   else if (aType == nsLayoutAtoms::onDOMNodeRemovedFromDocument) {
01006     *aArrayType = eEventArrayType_Mutation;
01007     *aFlags = NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT;
01008   }
01009   else if (aType == nsLayoutAtoms::onDOMAttrModified) {
01010     *aArrayType = eEventArrayType_Mutation;
01011     *aFlags = NS_EVENT_BITS_MUTATION_ATTRMODIFIED;
01012   }
01013   else if (aType == nsLayoutAtoms::onDOMCharacterDataModified) {
01014     *aArrayType = eEventArrayType_Mutation;
01015     *aFlags = NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED;
01016   }
01017   else if (aType == nsLayoutAtoms::onDOMActivate) {
01018     *aArrayType = eEventArrayType_DOMUI;
01019     *aFlags = NS_EVENT_BITS_UI_ACTIVATE;
01020   }
01021   else if (aType == nsLayoutAtoms::onDOMFocusIn) {
01022     *aArrayType = eEventArrayType_DOMUI;
01023     *aFlags = NS_EVENT_BITS_UI_FOCUSIN;
01024   }
01025   else if (aType == nsLayoutAtoms::onDOMFocusOut) {
01026     *aArrayType = eEventArrayType_DOMUI;
01027     *aFlags = NS_EVENT_BITS_UI_FOCUSOUT;
01028   }
01029   else if (aType == nsLayoutAtoms::oncompositionstart) {
01030     *aArrayType = eEventArrayType_Composition;
01031     *aFlags = NS_EVENT_BITS_COMPOSITION_START;
01032   }
01033   else if (aType == nsLayoutAtoms::oncompositionend) {
01034     *aArrayType = eEventArrayType_Composition;
01035     *aFlags = NS_EVENT_BITS_COMPOSITION_END;
01036   }
01037   else if (aType == nsLayoutAtoms::ontext) {
01038     *aArrayType = eEventArrayType_Text;
01039     *aFlags = NS_EVENT_BITS_TEXT_TEXT;
01040   }
01041   else if (aType == nsLayoutAtoms::onpageshow) {
01042     *aArrayType = eEventArrayType_PageTransition;
01043     *aFlags = NS_EVENT_BITS_PAGETRANSITION_SHOW;
01044   }
01045   else if (aType == nsLayoutAtoms::onpagehide) {
01046     *aArrayType = eEventArrayType_PageTransition;
01047     *aFlags = NS_EVENT_BITS_PAGETRANSITION_HIDE;
01048   }
01049 #ifdef MOZ_SVG
01050   else if (aType == nsLayoutAtoms::onSVGLoad) {
01051     *aArrayType = eEventArrayType_SVG;
01052     *aFlags = NS_EVENT_BITS_SVG_LOAD;
01053   }
01054   else if (aType == nsLayoutAtoms::onSVGUnload) {
01055     *aArrayType = eEventArrayType_SVG;
01056     *aFlags = NS_EVENT_BITS_SVG_UNLOAD;
01057   }
01058   else if (aType == nsLayoutAtoms::onSVGAbort) {
01059     *aArrayType = eEventArrayType_SVG;
01060     *aFlags = NS_EVENT_BITS_SVG_ABORT;
01061   }
01062   else if (aType == nsLayoutAtoms::onSVGError) {
01063     *aArrayType = eEventArrayType_SVG;
01064     *aFlags = NS_EVENT_BITS_SVG_ERROR;
01065   }
01066   else if (aType == nsLayoutAtoms::onSVGResize) {
01067     *aArrayType = eEventArrayType_SVG;
01068     *aFlags = NS_EVENT_BITS_SVG_RESIZE;
01069   }
01070   else if (aType == nsLayoutAtoms::onSVGScroll) {
01071     *aArrayType = eEventArrayType_SVG;
01072     *aFlags = NS_EVENT_BITS_SVG_SCROLL;
01073   }
01074   else if (aType == nsLayoutAtoms::onSVGZoom) {
01075     *aArrayType = eEventArrayType_SVGZoom;
01076     *aFlags = NS_EVENT_BITS_SVGZOOM_ZOOM;
01077   }
01078 #endif // MOZ_SVG
01079   else {
01080     return NS_ERROR_FAILURE;
01081   }
01082   return NS_OK;
01083 }
01084 
01085 NS_IMETHODIMP
01086 nsEventListenerManager::AddEventListenerByType(nsIDOMEventListener *aListener, 
01087                                                const nsAString& aType,
01088                                                PRInt32 aFlags,
01089                                                nsIDOMEventGroup* aEvtGrp)
01090 {
01091   PRInt32 subType;
01092   EventArrayType arrayType;
01093   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
01094 
01095   if (NS_OK == GetIdentifiersForType(atom, &arrayType, &subType)) {
01096     AddEventListener(aListener, arrayType, subType, nsnull, aFlags, aEvtGrp);
01097   }
01098   else {
01099     const nsPromiseFlatString& flatString = PromiseFlatString(aType); 
01100     nsStringKey key(flatString);
01101     AddEventListener(aListener, eEventArrayType_Hash, NS_EVENT_BITS_NONE, &key, aFlags, aEvtGrp);
01102   }
01103 
01104   return NS_OK;
01105 }
01106 
01107 NS_IMETHODIMP
01108 nsEventListenerManager::RemoveEventListenerByType(nsIDOMEventListener *aListener, 
01109                                                   const nsAString& aType,
01110                                                   PRInt32 aFlags,
01111                                                   nsIDOMEventGroup* aEvtGrp)
01112 {
01113   PRInt32 subType;
01114   EventArrayType arrayType;
01115   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
01116 
01117   if (NS_OK == GetIdentifiersForType(atom, &arrayType, &subType)) {
01118     RemoveEventListener(aListener, arrayType, subType, nsnull, aFlags, aEvtGrp);
01119   }
01120   else {
01121     const nsPromiseFlatString& flatString = PromiseFlatString(aType); 
01122     nsStringKey key(flatString);
01123     RemoveEventListener(aListener, eEventArrayType_Hash, NS_EVENT_BITS_NONE, &key, aFlags, aEvtGrp);
01124   }
01125 
01126   return NS_OK;
01127 }
01128 
01129 nsListenerStruct*
01130 nsEventListenerManager::FindJSEventListener(EventArrayType aType)
01131 {
01132   nsVoidArray *listeners = GetListenersByType(aType, nsnull, PR_FALSE);
01133   if (listeners) {
01134     // Run through the listeners for this type and see if a script
01135     // listener is registered
01136     nsListenerStruct *ls;
01137     for (PRInt32 i=0; i < listeners->Count(); i++) {
01138       ls = (nsListenerStruct*)listeners->ElementAt(i);
01139       if (ls->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) {
01140         return ls;
01141       }
01142     }
01143   }
01144 
01145   return nsnull;
01146 }
01147 
01148 nsresult
01149 nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
01150                                            JSObject *aScopeObject,
01151                                            nsISupports *aObject,
01152                                            nsIAtom* aName,
01153                                            PRBool aIsString,
01154                                            PRBool aPermitUntrustedEvents)
01155 {
01156   nsresult rv = NS_OK;
01157   nsListenerStruct *ls;
01158   PRInt32 flags;
01159   EventArrayType arrayType;
01160 
01161   NS_ENSURE_SUCCESS(GetIdentifiersForType(aName, &arrayType, &flags),
01162                     NS_ERROR_FAILURE);
01163 
01164   ls = FindJSEventListener(arrayType);
01165 
01166   if (nsnull == ls) {
01167     // If we didn't find a script listener or no listeners existed
01168     // create and add a new one.
01169     nsCOMPtr<nsIDOMEventListener> scriptListener;
01170     rv = NS_NewJSEventListener(aContext, aScopeObject, aObject,
01171                                getter_AddRefs(scriptListener));
01172     if (NS_SUCCEEDED(rv)) {
01173       AddEventListener(scriptListener, arrayType, NS_EVENT_BITS_NONE, nsnull,
01174                        NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT, nsnull);
01175 
01176       ls = FindJSEventListener(arrayType);
01177     }
01178   }
01179 
01180   if (NS_SUCCEEDED(rv) && ls) {
01181     // Set flag to indicate possible need for compilation later
01182     if (aIsString) {
01183       ls->mHandlerIsString |= flags;
01184     }
01185     else {
01186       ls->mHandlerIsString &= ~flags;
01187     }
01188 
01189     // Set subtype flags based on event
01190     ls->mSubType |= flags;
01191 
01192     if (aPermitUntrustedEvents) {
01193       ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
01194     }
01195   }
01196 
01197   return rv;
01198 }
01199 
01200 NS_IMETHODIMP
01201 nsEventListenerManager::AddScriptEventListener(nsISupports *aObject,
01202                                                nsIAtom *aName,
01203                                                const nsAString& aBody,
01204                                                PRBool aDeferCompilation,
01205                                                PRBool aPermitUntrustedEvents)
01206 {
01207   nsIScriptContext *context = nsnull;
01208   JSContext* cx = nsnull;
01209 
01210   nsCOMPtr<nsIContent> content(do_QueryInterface(aObject));
01211 
01212   nsCOMPtr<nsIDocument> doc;
01213 
01214   nsISupports *objiSupp = aObject;
01215 
01216   JSObject *scope = nsnull;
01217 
01218   if (content) {
01219     // Try to get context from doc
01220     doc = content->GetOwnerDoc();
01221     nsIScriptGlobalObject *global;
01222 
01223     if (doc && (global = doc->GetScriptGlobalObject())) {
01224       context = global->GetContext();
01225       scope = global->GetGlobalJSObject();
01226     }
01227   } else {
01228     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aObject));
01229     nsCOMPtr<nsIScriptGlobalObject> global;
01230     if (win) {
01231       NS_ASSERTION(win->IsInnerWindow(),
01232                    "Event listener added to outer window!");
01233 
01234       nsCOMPtr<nsIDOMDocument> domdoc;
01235       win->GetDocument(getter_AddRefs(domdoc));
01236       doc = do_QueryInterface(domdoc);
01237       global = do_QueryInterface(win);
01238     } else {
01239       doc = do_QueryInterface(aObject);
01240 
01241       if (doc) {
01242         global = doc->GetScriptGlobalObject();
01243       } else {
01244         global = do_QueryInterface(aObject);
01245       }
01246     }
01247     if (global) {
01248       context = global->GetContext();
01249       scope = global->GetGlobalJSObject();
01250     }
01251   }
01252 
01253   if (!context) {
01254     // Get JSContext from stack, or use the safe context (and hidden
01255     // window global) if no JS is running.
01256     nsCOMPtr<nsIThreadJSContextStack> stack =
01257       do_GetService("@mozilla.org/js/xpc/ContextStack;1");
01258     NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
01259     NS_ENSURE_SUCCESS(stack->Peek(&cx), NS_ERROR_FAILURE);
01260 
01261     if (!cx) {
01262       stack->GetSafeJSContext(&cx);
01263       NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
01264     }
01265 
01266     context = nsJSUtils::GetDynamicScriptContext(cx);
01267     NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
01268 
01269     scope = ::JS_GetGlobalObject(cx);
01270   } else if (!scope) {
01271     NS_ERROR("Context reachable, but no scope reachable in "
01272              "AddScriptEventListener()!");
01273 
01274     return NS_ERROR_NOT_AVAILABLE;
01275   }
01276 
01277   nsresult rv;
01278 
01279   if (!aDeferCompilation) {
01280     JSContext *cx = (JSContext *)context->GetNativeContext();
01281 
01282     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
01283     rv = nsContentUtils::XPConnect()->WrapNative(cx, scope, aObject,
01284                                                  NS_GET_IID(nsISupports),
01285                                                  getter_AddRefs(holder));
01286     NS_ENSURE_SUCCESS(rv, rv);
01287 
01288     // Since JSEventListeners only have a raw nsISupports pointer, it's
01289     // important that it point to the same object that the WrappedNative wraps.
01290     // (In the case of a tearoff, the tearoff will not persist).
01291     nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(holder);
01292     NS_ASSERTION(wrapper, "wrapper must impl nsIXPConnectWrappedNative");
01293 
01294     objiSupp = wrapper->Native();
01295 
01296     JSObject *scriptObject = nsnull;
01297 
01298     rv = holder->GetJSObject(&scriptObject);
01299     NS_ENSURE_SUCCESS(rv, rv);
01300 
01301     nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
01302       do_QueryInterface(aObject);
01303 
01304     void *handler = nsnull;
01305     PRBool done = PR_FALSE;
01306 
01307     if (handlerOwner) {
01308       rv = handlerOwner->GetCompiledEventHandler(aName, &handler);
01309       if (NS_SUCCEEDED(rv) && handler) {
01310         rv = context->BindCompiledEventHandler(scriptObject, aName, handler);
01311         if (NS_FAILED(rv))
01312           return rv;
01313         done = PR_TRUE;
01314       }
01315     }
01316 
01317     if (!done) {
01318       PRUint32 lineNo = 0;
01319       nsCAutoString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
01320       if (doc) {
01321         nsIURI *uri = doc->GetDocumentURI();
01322         if (uri) {
01323           uri->GetSpec(url);
01324           lineNo = 1;
01325         }
01326       }
01327 
01328       if (handlerOwner) {
01329         // Always let the handler owner compile the event handler, as
01330         // it may want to use a special context or scope object.
01331         rv = handlerOwner->CompileEventHandler(context, scriptObject, aName,
01332                                                aBody, url.get(), lineNo, &handler);
01333       }
01334       else {
01335         PRInt32 nameSpace = kNameSpaceID_Unknown;
01336         if (content)
01337           nameSpace = content->GetNameSpaceID();
01338         else if (doc) {
01339           nsCOMPtr<nsIContent> root = doc->GetRootContent();
01340           if (root)
01341             nameSpace = root->GetNameSpaceID();
01342         }
01343         const char *eventName = nsContentUtils::GetEventArgName(nameSpace);
01344 
01345         rv = context->CompileEventHandler(scriptObject, aName, eventName,
01346                                           aBody,
01347                                           url.get(), lineNo,
01348                                           (handlerOwner != nsnull),
01349                                           &handler);
01350       }
01351       if (NS_FAILED(rv)) return rv;
01352     }
01353   }
01354 
01355   return SetJSEventListener(context, scope, objiSupp, aName, aDeferCompilation,
01356                             aPermitUntrustedEvents);
01357 }
01358 
01359 nsresult
01360 nsEventListenerManager::RemoveScriptEventListener(nsIAtom *aName)
01361 {
01362   nsresult result = NS_OK;
01363   nsListenerStruct *ls;
01364   PRInt32 flags;
01365   EventArrayType arrayType;
01366 
01367   NS_ENSURE_SUCCESS(GetIdentifiersForType(aName, &arrayType, &flags),
01368                     NS_ERROR_FAILURE);
01369   ls = FindJSEventListener(arrayType);
01370 
01371   if (ls) {
01372     ls->mSubType &= ~flags;
01373     if (ls->mSubType == NS_EVENT_BITS_NONE) {
01374       //Get the listeners array so we can remove ourselves from it
01375       nsVoidArray* listeners;
01376       listeners = GetListenersByType(arrayType, nsnull, PR_FALSE);
01377       NS_ENSURE_TRUE(listeners, NS_ERROR_FAILURE);
01378       listeners->RemoveElement((void*)ls);
01379       delete ls;
01380     }
01381   }
01382 
01383   return result;
01384 }
01385 
01386 jsval
01387 nsEventListenerManager::sAddListenerID = JSVAL_VOID;
01388 
01389 NS_IMETHODIMP
01390 nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
01391                                                     JSObject *aScopeObject,
01392                                                     nsISupports *aObject, 
01393                                                     nsIAtom *aName)
01394 {
01395   // Check that we have access to set an event listener. Prevents
01396   // snooping attacks across domains by setting onkeypress handlers,
01397   // for instance.
01398   // You'd think it'd work just to get the JSContext from aContext,
01399   // but that's actually the JSContext whose private object parents
01400   // the object in aObject.
01401   nsresult rv;
01402   nsCOMPtr<nsIJSContextStack> stack =
01403     do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
01404   if (NS_FAILED(rv))
01405     return rv;
01406   JSContext *cx;
01407   if (NS_FAILED(rv = stack->Peek(&cx)))
01408     return rv;
01409 
01410   JSContext *current_cx = (JSContext *)aContext->GetNativeContext();
01411 
01412   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
01413   rv = nsContentUtils::XPConnect()->
01414     WrapNative(current_cx, aScopeObject, aObject, NS_GET_IID(nsISupports),
01415                getter_AddRefs(holder));
01416   NS_ENSURE_SUCCESS(rv, rv);
01417 
01418   // Since JSEventListeners only have a raw nsISupports pointer, it's
01419   // important that it point to the same object that the WrappedNative wraps.
01420   // (In the case of a tearoff, the tearoff will not persist).
01421   nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(holder);
01422   NS_ASSERTION(wrapper, "wrapper must impl nsIXPConnectWrappedNative");
01423 
01424   JSObject *jsobj = nsnull;
01425 
01426   rv = holder->GetJSObject(&jsobj);
01427   NS_ENSURE_SUCCESS(rv, rv);
01428 
01429   if (cx) {
01430     if (sAddListenerID == JSVAL_VOID) {
01431       sAddListenerID =
01432         STRING_TO_JSVAL(::JS_InternString(cx, "addEventListener"));
01433     }
01434 
01435     rv = nsContentUtils::GetSecurityManager()->
01436       CheckPropertyAccess(cx, jsobj,
01437                           "EventTarget",
01438                           sAddListenerID,
01439                           nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
01440     if (NS_FAILED(rv)) {
01441       // XXX set pending exception on the native call context?
01442       return rv;
01443     }
01444   }
01445 
01446   // Untrusted events are always permitted for non-chrome script
01447   // handlers.
01448   return SetJSEventListener(aContext, aScopeObject, wrapper->Native(), aName,
01449                             PR_FALSE, !nsContentUtils::IsCallerChrome());
01450 }
01451 
01452 nsresult
01453 nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext, 
01454                                                    JSObject *aScopeObject,
01455                                                    nsISupports *aObject, 
01456                                                    nsIAtom *aName,
01457                                                    PRBool *aDidCompile)
01458 {
01459   nsresult rv = NS_OK;
01460   nsListenerStruct *ls;
01461   PRInt32 subType;
01462   EventArrayType arrayType;
01463 
01464   *aDidCompile = PR_FALSE;
01465 
01466   rv = GetIdentifiersForType(aName, &arrayType, &subType);
01467   NS_ENSURE_SUCCESS(rv, rv);
01468 
01469   ls = FindJSEventListener(arrayType);
01470 
01471   if (!ls) {
01472     //nothing to compile
01473     return NS_OK;
01474   }
01475 
01476   if (ls->mHandlerIsString & subType) {
01477     rv = CompileEventHandlerInternal(aContext, aScopeObject, aObject, aName,
01478                                      ls, /*XXX fixme*/nsnull, subType);
01479   }
01480 
01481   // Set *aDidCompile to true even if we didn't really compile
01482   // anything right now, if we get here it means that this event
01483   // handler has been compiled at some point, that's good enough for
01484   // us.
01485 
01486   *aDidCompile = PR_TRUE;
01487 
01488   return rv;
01489 }
01490 
01491 nsresult
01492 nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
01493                                                     JSObject *aScopeObject,
01494                                                     nsISupports *aObject,
01495                                                     nsIAtom *aName,
01496                                                     nsListenerStruct *aListenerStruct,
01497                                                     nsIDOMEventTarget* aCurrentTarget,
01498                                                     PRUint32 aSubType)
01499 {
01500   nsresult result = NS_OK;
01501 
01502   JSContext *cx = (JSContext *)aContext->GetNativeContext();
01503 
01504   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
01505   result = nsContentUtils::XPConnect()->WrapNative(cx, aScopeObject, aObject,
01506                                                    NS_GET_IID(nsISupports),
01507                                                    getter_AddRefs(holder));
01508   NS_ENSURE_SUCCESS(result, result);
01509 
01510   JSObject *jsobj = nsnull;
01511 
01512   result = holder->GetJSObject(&jsobj);
01513   NS_ENSURE_SUCCESS(result, result);
01514 
01515   nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
01516     do_QueryInterface(aObject);
01517   void* handler = nsnull;
01518 
01519   if (handlerOwner) {
01520     result = handlerOwner->GetCompiledEventHandler(aName, &handler);
01521     if (NS_SUCCEEDED(result) && handler) {
01522       result = aContext->BindCompiledEventHandler(jsobj, aName, handler);
01523       aListenerStruct->mHandlerIsString &= ~aSubType;
01524     }
01525   }
01526 
01527   if (aListenerStruct->mHandlerIsString & aSubType) {
01528     // This should never happen for anything but content
01529     // XXX I don't like that we have to reference content
01530     // from here. The alternative is to store the event handler
01531     // string on the JS object itself.
01532     nsCOMPtr<nsIContent> content = do_QueryInterface(aObject);
01533     NS_ASSERTION(content, "only content should have event handler attributes");
01534     if (content) {
01535       nsAutoString handlerBody;
01536       nsIAtom* attrName = aName;
01537 #ifdef MOZ_SVG
01538       if (aName == nsLayoutAtoms::onSVGLoad)
01539         attrName = nsSVGAtoms::onload;
01540       else if (aName == nsLayoutAtoms::onSVGUnload)
01541         attrName = nsSVGAtoms::onunload;
01542       else if (aName == nsLayoutAtoms::onSVGAbort)
01543         attrName = nsSVGAtoms::onabort;
01544       else if (aName == nsLayoutAtoms::onSVGError)
01545         attrName = nsSVGAtoms::onerror;
01546       else if (aName == nsLayoutAtoms::onSVGResize)
01547         attrName = nsSVGAtoms::onresize;
01548       else if (aName == nsLayoutAtoms::onSVGScroll)
01549         attrName = nsSVGAtoms::onscroll;
01550       else if (aName == nsLayoutAtoms::onSVGZoom)
01551         attrName = nsSVGAtoms::onzoom;
01552 #endif // MOZ_SVG
01553 
01554       result = content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
01555 
01556       if (NS_SUCCEEDED(result)) {
01557         PRUint32 lineNo = 0;
01558         nsCAutoString url (NS_LITERAL_CSTRING("javascript:alert('TODO: FIXME')"));
01559         nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCurrentTarget);
01560         if (!doc) {
01561           nsCOMPtr<nsIContent> content = do_QueryInterface(aCurrentTarget);
01562           if (content)
01563             doc = content->GetOwnerDoc();
01564         }
01565         if (doc) {
01566           nsIURI *uri = doc->GetDocumentURI();
01567           if (uri) {
01568             uri->GetSpec(url);
01569             lineNo = 1;
01570           }
01571         }
01572 
01573         if (handlerOwner) {
01574           // Always let the handler owner compile the event
01575           // handler, as it may want to use a special
01576           // context or scope object.
01577           result = handlerOwner->CompileEventHandler(aContext, jsobj, aName,
01578                                                      handlerBody,
01579                                                      url.get(), lineNo,
01580                                                      &handler);
01581         }
01582         else {
01583           const char *eventName =
01584             nsContentUtils::GetEventArgName(content->GetNameSpaceID());
01585 
01586           result = aContext->CompileEventHandler(jsobj, aName, eventName,
01587                                                  handlerBody,
01588                                                  url.get(), lineNo,
01589                                                  (handlerOwner != nsnull),
01590                                                  &handler);
01591         }
01592 
01593         if (NS_SUCCEEDED(result)) {
01594           aListenerStruct->mHandlerIsString &= ~aSubType;
01595         }
01596       }
01597     }
01598   }
01599 
01600   return result;
01601 }
01602 
01603 nsresult
01604 nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
01605                                            nsIDOMEventListener* aListener,
01606                                            nsIDOMEvent* aDOMEvent,
01607                                            nsIDOMEventTarget* aCurrentTarget,
01608                                            PRUint32 aSubType,
01609                                            PRUint32 aPhaseFlags)
01610 {
01611   nsresult result = NS_OK;
01612 
01613   // If this is a script handler and we haven't yet
01614   // compiled the event handler itself
01615   if (aListenerStruct->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) {
01616     // If we're not in the capture phase we must *NOT* have capture flags
01617     // set.  Compiled script handlers are one or the other, not both.
01618     if (aPhaseFlags & NS_EVENT_FLAG_BUBBLE && !aPhaseFlags & NS_EVENT_FLAG_INIT) {
01619       if (aListenerStruct->mSubTypeCapture & aSubType) {
01620         return result;
01621       }
01622     }
01623     // If we're in the capture phase we must have capture flags set.
01624     else if (aPhaseFlags & NS_EVENT_FLAG_CAPTURE && !aPhaseFlags & NS_EVENT_FLAG_INIT) {
01625       if (!(aListenerStruct->mSubTypeCapture & aSubType)) {
01626         return result;
01627       }
01628     }
01629     if (aListenerStruct->mHandlerIsString & aSubType) {
01630 
01631       nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener);
01632       if (jslistener) {
01633         nsAutoString eventString;
01634         if (NS_SUCCEEDED(aDOMEvent->GetType(eventString))) {
01635           nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + eventString);
01636 
01637           result = CompileEventHandlerInternal(jslistener->GetEventContext(),
01638                                                jslistener->GetEventScope(),
01639                                                jslistener->GetEventTarget(),
01640                                                atom, aListenerStruct,
01641                                                aCurrentTarget,
01642                                                aSubType);
01643         }
01644       }
01645     }
01646   }
01647 
01648   // nsCxPusher will push and pop (automatically) the current cx onto the
01649   // context stack
01650   nsCxPusher pusher;
01651 
01652   if (NS_SUCCEEDED(result) && pusher.Push(aCurrentTarget)) {
01653     nsCOMPtr<nsIPrivateDOMEvent> aPrivDOMEvent(do_QueryInterface(aDOMEvent));
01654     aPrivDOMEvent->SetCurrentTarget(aCurrentTarget);
01655     result = aListener->HandleEvent(aDOMEvent);
01656     aPrivDOMEvent->SetCurrentTarget(nsnull);
01657   }
01658 
01659   return result;
01660 }
01661 
01667 nsresult
01668 nsEventListenerManager::HandleEvent(nsPresContext* aPresContext,
01669                                     nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
01670                                     nsIDOMEventTarget* aCurrentTarget,
01671                                     PRUint32 aFlags,
01672                                     nsEventStatus* aEventStatus)
01673 {
01674   NS_ENSURE_ARG_POINTER(aEventStatus);
01675   nsresult ret = NS_OK;
01676 
01677   if (aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) {
01678     return ret;
01679   }
01680 
01681   if (aFlags & NS_EVENT_FLAG_INIT) {
01682     aFlags |= (NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE);
01683   }
01684   //Set the value of the internal PreventDefault flag properly based on aEventStatus
01685   if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
01686     aEvent->flags |= NS_EVENT_FLAG_NO_DEFAULT;
01687   }
01688   PRUint16 currentGroup = aFlags & NS_EVENT_FLAG_SYSTEM_EVENT;
01689 
01690   /* Without this addref, certain events, notably ones bound to
01691      keys which cause window deletion, can destroy this object
01692      before we're ready. */
01693   nsCOMPtr<nsIEventListenerManager> kungFuDeathGrip(this);
01694   nsVoidArray *listeners = nsnull;
01695 
01696   if (aEvent->message == NS_CONTEXTMENU || aEvent->message == NS_CONTEXTMENU_KEY) {
01697     ret = FixContextMenuEvent(aPresContext, aCurrentTarget, aEvent, aDOMEvent);
01698     if (NS_FAILED(ret)) {
01699       NS_WARNING("failed to fix context menu event target");
01700       ret = NS_OK;
01701     }
01702   }
01703 
01704 
01705   const EventTypeData* typeData = nsnull;
01706   const EventDispatchData* dispData = nsnull;
01707 
01708   if (aEvent->message == NS_USER_DEFINED_EVENT) {
01709     listeners = GetListenersByType(eEventArrayType_Hash, aEvent->userType, PR_FALSE);
01710   } else {
01711     for (PRInt32 i = 0; i < eEventArrayType_Hash; ++i) {
01712       typeData = &sEventTypes[i];
01713       for (PRInt32 j = 0; j < typeData->numEvents; ++j) {
01714         dispData = &(typeData->events[j]);
01715         if (aEvent->message == dispData->message) {
01716           listeners = GetListenersByType((EventArrayType)i, nsnull, PR_FALSE);
01717           goto found;
01718         }
01719       }
01720     }
01721   }
01722 
01723  found:
01724   if (listeners) {
01725     if (!*aDOMEvent) {
01726       ret = CreateEvent(aPresContext, aEvent, EmptyString(), aDOMEvent);
01727     }
01728 
01729     if (NS_SUCCEEDED(ret)) {
01730       PRInt32 count = listeners->Count();
01731       nsVoidArray originalListeners(count);
01732       originalListeners = *listeners;
01733 
01734       nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
01735 
01736       for (PRInt32 k = 0; !mListenersRemoved && listeners && k < count; ++k) {
01737         nsListenerStruct* ls = NS_STATIC_CAST(nsListenerStruct*, originalListeners.FastElementAt(k));
01738         // Don't fire the listener if it's been removed
01739 
01740         if (listeners->IndexOf(ls) != -1 && ls->mFlags & aFlags &&
01741             ls->mGroupFlags == currentGroup &&
01742             (NS_IS_TRUSTED_EVENT(aEvent) ||
01743              ls->mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED)) {
01744           nsRefPtr<nsIDOMEventListener> eventListener = ls->mListener.Get();
01745           NS_ASSERTION(eventListener, "listener wasn't preserved properly");
01746           if (eventListener) {
01747             // Try the type-specific listener interface
01748             PRBool hasInterface = PR_FALSE;
01749             if (typeData)
01750               DispatchToInterface(*aDOMEvent, eventListener,
01751                                   dispData->method, *typeData->iid,
01752                                   &hasInterface);
01753 
01754             // If it doesn't implement that, call the generic HandleEvent()
01755             if (!hasInterface && (ls->mSubType == NS_EVENT_BITS_NONE ||
01756                                   ls->mSubType & dispData->bits)) {
01757               HandleEventSubType(ls, eventListener, *aDOMEvent, aCurrentTarget,
01758                                  dispData ? dispData->bits : NS_EVENT_BITS_NONE,
01759                                  aFlags);
01760             }
01761           }
01762         }
01763       }
01764     }
01765   }
01766 
01767   if (aEvent->flags & NS_EVENT_FLAG_NO_DEFAULT) {
01768     *aEventStatus = nsEventStatus_eConsumeNoDefault;
01769   }
01770 
01771   return NS_OK;
01772 }
01773 
01778 NS_IMETHODIMP
01779 nsEventListenerManager::CreateEvent(nsPresContext* aPresContext,
01780                                     nsEvent* aEvent,
01781                                     const nsAString& aEventType,
01782                                     nsIDOMEvent** aDOMEvent)
01783 {
01784   *aDOMEvent = nsnull;
01785 
01786   if (aEvent) {
01787     switch(aEvent->eventStructType) {
01788     case NS_MUTATION_EVENT:
01789       return NS_NewDOMMutationEvent(aDOMEvent, aPresContext,
01790                                     NS_STATIC_CAST(nsMutationEvent*,aEvent));
01791     case NS_GUI_EVENT:
01792     case NS_COMPOSITION_EVENT:
01793     case NS_RECONVERSION_EVENT:
01794     case NS_QUERYCARETRECT_EVENT:
01795     case NS_SCROLLPORT_EVENT:
01796       return NS_NewDOMUIEvent(aDOMEvent, aPresContext,
01797                               NS_STATIC_CAST(nsGUIEvent*,aEvent));
01798     case NS_KEY_EVENT:
01799       return NS_NewDOMKeyboardEvent(aDOMEvent, aPresContext,
01800                                     NS_STATIC_CAST(nsKeyEvent*,aEvent));
01801     case NS_MOUSE_EVENT:
01802     case NS_MOUSE_SCROLL_EVENT:
01803     case NS_POPUP_EVENT:
01804       return NS_NewDOMMouseEvent(aDOMEvent, aPresContext,
01805                                  NS_STATIC_CAST(nsInputEvent*,aEvent));
01806     case NS_POPUPBLOCKED_EVENT:
01807       return NS_NewDOMPopupBlockedEvent(aDOMEvent, aPresContext,
01808                                         NS_STATIC_CAST(nsPopupBlockedEvent*,
01809                                                        aEvent));
01810     case NS_TEXT_EVENT:
01811       return NS_NewDOMTextEvent(aDOMEvent, aPresContext,
01812                                 NS_STATIC_CAST(nsTextEvent*,aEvent));
01813     case NS_BEFORE_PAGE_UNLOAD_EVENT:
01814       return
01815         NS_NewDOMBeforeUnloadEvent(aDOMEvent, aPresContext,
01816                                    NS_STATIC_CAST(nsBeforePageUnloadEvent*,
01817                                                   aEvent));
01818     case NS_PAGETRANSITION_EVENT:
01819       return NS_NewDOMPageTransitionEvent(aDOMEvent, aPresContext,
01820                                           NS_STATIC_CAST(nsPageTransitionEvent*,
01821                                                          aEvent));
01822 #ifdef MOZ_SVG
01823     case NS_SVG_EVENT:
01824       return NS_NewDOMSVGEvent(aDOMEvent, aPresContext,
01825                                aEvent);
01826     case NS_SVGZOOM_EVENT:
01827       return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext,
01828                                    NS_STATIC_CAST(nsGUIEvent*,aEvent));
01829 #endif // MOZ_SVG
01830     case NS_XUL_COMMAND_EVENT:
01831       return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext,
01832                                       NS_STATIC_CAST(nsXULCommandEvent*,
01833                                                      aEvent));
01834     }
01835 
01836     // For all other types of events, create a vanilla event object.
01837     return NS_NewDOMEvent(aDOMEvent, aPresContext, aEvent);
01838   }
01839 
01840   // And if we didn't get an event, check the type argument.
01841 
01842   if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
01843       aEventType.LowerCaseEqualsLiteral("mouseevents") ||
01844       aEventType.LowerCaseEqualsLiteral("mousescrollevents") ||
01845       aEventType.LowerCaseEqualsLiteral("popupevents"))
01846     return NS_NewDOMMouseEvent(aDOMEvent, aPresContext,
01847                                NS_STATIC_CAST(nsInputEvent*,aEvent));
01848   if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
01849       aEventType.LowerCaseEqualsLiteral("keyevents"))
01850     return NS_NewDOMKeyboardEvent(aDOMEvent, aPresContext,
01851                                   NS_STATIC_CAST(nsKeyEvent*,aEvent));
01852   if (aEventType.LowerCaseEqualsLiteral("mutationevent") ||
01853         aEventType.LowerCaseEqualsLiteral("mutationevents"))
01854     return NS_NewDOMMutationEvent(aDOMEvent, aPresContext,
01855                                   NS_STATIC_CAST(nsMutationEvent*,aEvent));
01856   if (aEventType.LowerCaseEqualsLiteral("textevent") ||
01857       aEventType.LowerCaseEqualsLiteral("textevents"))
01858     return NS_NewDOMTextEvent(aDOMEvent, aPresContext,
01859                               NS_STATIC_CAST(nsTextEvent*,aEvent));
01860   if (aEventType.LowerCaseEqualsLiteral("popupblockedevents"))
01861     return NS_NewDOMPopupBlockedEvent(aDOMEvent, aPresContext,
01862                                       NS_STATIC_CAST(nsPopupBlockedEvent*,
01863                                                      aEvent));
01864   if (aEventType.LowerCaseEqualsLiteral("uievent") ||
01865       aEventType.LowerCaseEqualsLiteral("uievents"))
01866     return NS_NewDOMUIEvent(aDOMEvent, aPresContext,
01867                             NS_STATIC_CAST(nsGUIEvent*,aEvent));
01868   if (aEventType.LowerCaseEqualsLiteral("event") ||
01869       aEventType.LowerCaseEqualsLiteral("events") ||
01870       aEventType.LowerCaseEqualsLiteral("htmlevents"))
01871     return NS_NewDOMEvent(aDOMEvent, aPresContext, aEvent);
01872 #ifdef MOZ_SVG
01873   if (aEventType.LowerCaseEqualsLiteral("svgevent") ||
01874       aEventType.LowerCaseEqualsLiteral("svgevents"))
01875     return NS_NewDOMSVGEvent(aDOMEvent, aPresContext,
01876                              aEvent);
01877   if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
01878       aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
01879     return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext,
01880                                  NS_STATIC_CAST(nsGUIEvent*,aEvent));
01881 #endif // MOZ_SVG
01882   if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
01883       aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
01884     return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext, nsnull);
01885 
01886   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
01887 }
01888 
01894 NS_IMETHODIMP
01895 nsEventListenerManager::CaptureEvent(PRInt32 aEventTypes)
01896 {
01897   return FlipCaptureBit(aEventTypes, PR_TRUE);
01898 }             
01899 
01905 NS_IMETHODIMP
01906 nsEventListenerManager::ReleaseEvent(PRInt32 aEventTypes)
01907 {
01908   return FlipCaptureBit(aEventTypes, PR_FALSE);
01909 }
01910 
01911 nsresult
01912 nsEventListenerManager::FlipCaptureBit(PRInt32 aEventTypes,
01913                                        PRBool aInitCapture)
01914 {
01915   // This method exists for Netscape 4.x event handling compatibility.
01916   // New events do not need to be added here.
01917 
01918   EventArrayType arrayType = eEventArrayType_None;
01919   PRUint8 bits = 0;
01920 
01921   if (aEventTypes & nsIDOMNSEvent::MOUSEDOWN) {
01922     arrayType = eEventArrayType_Mouse;
01923     bits = NS_EVENT_BITS_MOUSE_MOUSEDOWN; 
01924   }
01925   if (aEventTypes & nsIDOMNSEvent::MOUSEUP) {
01926     arrayType = eEventArrayType_Mouse;
01927     bits = NS_EVENT_BITS_MOUSE_MOUSEUP; 
01928   }
01929   if (aEventTypes & nsIDOMNSEvent::MOUSEOVER) {
01930     arrayType = eEventArrayType_Mouse;
01931     bits = NS_EVENT_BITS_MOUSE_MOUSEOVER; 
01932   }
01933   if (aEventTypes & nsIDOMNSEvent::MOUSEOUT) {
01934     arrayType = eEventArrayType_Mouse;
01935     bits = NS_EVENT_BITS_MOUSE_MOUSEOUT; 
01936   }
01937   if (aEventTypes & nsIDOMNSEvent::MOUSEMOVE) {
01938     arrayType = eEventArrayType_MouseMotion;
01939     bits = NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE; 
01940   }
01941   if (aEventTypes & nsIDOMNSEvent::CLICK) {
01942     arrayType = eEventArrayType_Mouse;
01943     bits = NS_EVENT_BITS_MOUSE_CLICK; 
01944   }
01945   if (aEventTypes & nsIDOMNSEvent::DBLCLICK) {
01946     arrayType = eEventArrayType_Mouse;
01947     bits = NS_EVENT_BITS_MOUSE_DBLCLICK; 
01948   }
01949   if (aEventTypes & nsIDOMNSEvent::KEYDOWN) {
01950     arrayType = eEventArrayType_Key;
01951     bits = NS_EVENT_BITS_KEY_KEYDOWN; 
01952   }
01953   if (aEventTypes & nsIDOMNSEvent::KEYUP) {
01954     arrayType = eEventArrayType_Key;
01955     bits = NS_EVENT_BITS_KEY_KEYUP; 
01956   }
01957   if (aEventTypes & nsIDOMNSEvent::KEYPRESS) {
01958     arrayType = eEventArrayType_Key;
01959     bits = NS_EVENT_BITS_KEY_KEYPRESS; 
01960   }
01961   if (aEventTypes & nsIDOMNSEvent::DRAGDROP) {
01962     arrayType = eEventArrayType_Drag;
01963     bits = NS_EVENT_BITS_DRAG_ENTER; 
01964   }
01965   /*if (aEventTypes & nsIDOMNSEvent::MOUSEDRAG) {
01966     arrayType = kIDOMMouseListenerarrayType;
01967     bits = NS_EVENT_BITS_MOUSE_MOUSEDOWN; 
01968   }*/
01969   if (aEventTypes & nsIDOMNSEvent::FOCUS) {
01970     arrayType = eEventArrayType_Focus;
01971     bits = NS_EVENT_BITS_FOCUS_FOCUS; 
01972   }
01973   if (aEventTypes & nsIDOMNSEvent::BLUR) {
01974     arrayType = eEventArrayType_Focus;
01975     bits = NS_EVENT_BITS_FOCUS_BLUR; 
01976   }
01977   if (aEventTypes & nsIDOMNSEvent::SELECT) {
01978     arrayType = eEventArrayType_Form;
01979     bits = NS_EVENT_BITS_FORM_SELECT; 
01980   }
01981   if (aEventTypes & nsIDOMNSEvent::CHANGE) {
01982     arrayType = eEventArrayType_Form;
01983     bits = NS_EVENT_BITS_FORM_CHANGE; 
01984   }
01985   if (aEventTypes & nsIDOMNSEvent::RESET) {
01986     arrayType = eEventArrayType_Form;
01987     bits = NS_EVENT_BITS_FORM_RESET; 
01988   }
01989   if (aEventTypes & nsIDOMNSEvent::SUBMIT) {
01990     arrayType = eEventArrayType_Form;
01991     bits = NS_EVENT_BITS_FORM_SUBMIT; 
01992   }
01993   if (aEventTypes & nsIDOMNSEvent::LOAD) {
01994     arrayType = eEventArrayType_Load;
01995     bits = NS_EVENT_BITS_LOAD_LOAD; 
01996   }
01997   if (aEventTypes & nsIDOMNSEvent::UNLOAD) {
01998     arrayType = eEventArrayType_Load;
01999     bits = NS_EVENT_BITS_LOAD_UNLOAD; 
02000   }
02001   if (aEventTypes & nsIDOMNSEvent::ABORT) {
02002     arrayType = eEventArrayType_Load;
02003     bits = NS_EVENT_BITS_LOAD_ABORT; 
02004   }
02005   if (aEventTypes & nsIDOMNSEvent::ERROR) {
02006     arrayType = eEventArrayType_Load;
02007     bits = NS_EVENT_BITS_LOAD_ERROR; 
02008   }
02009   if (aEventTypes & nsIDOMNSEvent::RESIZE) {
02010     arrayType = eEventArrayType_Paint;
02011     bits = NS_EVENT_BITS_PAINT_RESIZE; 
02012   }
02013   if (aEventTypes & nsIDOMNSEvent::SCROLL) {
02014     arrayType = eEventArrayType_Scroll;
02015     bits = NS_EVENT_BITS_PAINT_RESIZE; 
02016   }
02017 
02018   if (arrayType != eEventArrayType_None) {
02019     nsListenerStruct *ls = FindJSEventListener(arrayType);
02020 
02021     if (ls) {
02022       if (aInitCapture)
02023         ls->mSubTypeCapture |= bits;
02024       else
02025         ls->mSubTypeCapture &= ~bits;
02026 
02027       ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
02028     }
02029   }
02030 
02031   return NS_OK;
02032 }
02033 
02034 NS_IMETHODIMP
02035 nsEventListenerManager::Disconnect(PRBool)
02036 {
02037   mTarget = nsnull;
02038 
02039   // Bug 323807: nsDOMClassInfo::PreserveWrapper (and
02040   // nsIDOMGCParticipant) require that we remove all event listeners now
02041   // to remove any weak references in the nsDOMClassInfo's preserved
02042   // wrapper table to the target.
02043   return RemoveAllListeners();
02044 }
02045 
02046 NS_IMETHODIMP
02047 nsEventListenerManager::SetListenerTarget(nsISupports* aTarget)
02048 {
02049   NS_PRECONDITION(aTarget, "unexpected null pointer");
02050 
02051   //WEAK reference, must be set back to nsnull when done by calling Disconnect
02052   mTarget = aTarget;
02053   return NS_OK;
02054 }
02055 
02056 NS_IMETHODIMP
02057 nsEventListenerManager::GetSystemEventGroupLM(nsIDOMEventGroup **aGroup)
02058 {
02059   if (!gSystemEventGroup) {
02060     nsresult result;
02061     nsCOMPtr<nsIDOMEventGroup> group(do_CreateInstance(kDOMEventGroupCID,&result));
02062     if (NS_FAILED(result))
02063       return result;
02064 
02065     gSystemEventGroup = group;
02066     NS_ADDREF(gSystemEventGroup);
02067   }
02068 
02069   *aGroup = gSystemEventGroup;
02070   NS_ADDREF(*aGroup);
02071   return NS_OK;
02072 }
02073 
02074 nsresult
02075 nsEventListenerManager::GetDOM2EventGroup(nsIDOMEventGroup **aGroup)
02076 {
02077   if (!gDOM2EventGroup) {
02078     nsresult result;
02079     nsCOMPtr<nsIDOMEventGroup> group(do_CreateInstance(kDOMEventGroupCID,&result));
02080     if (NS_FAILED(result))
02081       return result;
02082 
02083     gDOM2EventGroup = group;
02084     NS_ADDREF(gDOM2EventGroup);
02085   }
02086 
02087   *aGroup = gDOM2EventGroup;
02088   NS_ADDREF(*aGroup);
02089   return NS_OK;
02090 }
02091 
02092 // nsIDOMEventTarget interface
02093 NS_IMETHODIMP 
02094 nsEventListenerManager::AddEventListener(const nsAString& aType, 
02095                                          nsIDOMEventListener* aListener, 
02096                                          PRBool aUseCapture)
02097 {
02098   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
02099 
02100   return AddEventListenerByType(aListener, aType, flags, nsnull);
02101 }
02102 
02103 NS_IMETHODIMP 
02104 nsEventListenerManager::RemoveEventListener(const nsAString& aType, 
02105                                             nsIDOMEventListener* aListener, 
02106                                             PRBool aUseCapture)
02107 {
02108   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
02109   
02110   return RemoveEventListenerByType(aListener, aType, flags, nsnull);
02111 }
02112 
02113 NS_IMETHODIMP
02114 nsEventListenerManager::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
02115 {
02116   nsCOMPtr<nsIContent> targetContent(do_QueryInterface(mTarget));
02117   if (!targetContent) {
02118     // nothing to dispatch on -- bad!
02119     return NS_ERROR_FAILURE;
02120   }
02121   
02122   nsCOMPtr<nsIDocument> document = targetContent->GetOwnerDoc();
02123 
02124   // Do nothing if the element does not belong to a document
02125   if (!document) {
02126     return NS_OK;
02127   }
02128 
02129   // Obtain a presentation shell
02130   nsIPresShell *shell = document->GetShellAt(0);
02131   if (!shell) {
02132     return NS_OK;
02133   }
02134 
02135   nsCOMPtr<nsPresContext> context = shell->GetPresContext();
02136 
02137   return context->EventStateManager()->
02138     DispatchNewEvent(mTarget, aEvent, _retval);
02139 }
02140 
02141 // nsIDOM3EventTarget interface
02142 NS_IMETHODIMP 
02143 nsEventListenerManager::AddGroupedEventListener(const nsAString& aType, 
02144                                                 nsIDOMEventListener* aListener, 
02145                                                 PRBool aUseCapture,
02146                                                 nsIDOMEventGroup* aEvtGrp)
02147 {
02148   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
02149 
02150   return AddEventListenerByType(aListener, aType, flags, aEvtGrp);
02151 }
02152 
02153 NS_IMETHODIMP 
02154 nsEventListenerManager::RemoveGroupedEventListener(const nsAString& aType, 
02155                                             nsIDOMEventListener* aListener, 
02156                                             PRBool aUseCapture,
02157                                             nsIDOMEventGroup* aEvtGrp)
02158 {
02159   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
02160   
02161   return RemoveEventListenerByType(aListener, aType, flags, aEvtGrp);
02162 }
02163 
02164 NS_IMETHODIMP
02165 nsEventListenerManager::CanTrigger(const nsAString & type, PRBool *_retval)
02166 {
02167   return NS_ERROR_NOT_IMPLEMENTED;
02168 }
02169 
02170 NS_IMETHODIMP
02171 nsEventListenerManager::IsRegisteredHere(const nsAString & type, PRBool *_retval)
02172 {
02173   return NS_ERROR_NOT_IMPLEMENTED;
02174 }
02175 
02176 // nsIDOMEventReceiver interface
02177 NS_IMETHODIMP 
02178 nsEventListenerManager::AddEventListenerByIID(nsIDOMEventListener *aListener, 
02179                                               const nsIID& aIID)
02180 {
02181   return AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
02182 }
02183 
02184 NS_IMETHODIMP 
02185 nsEventListenerManager::RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID)
02186 {
02187   return RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
02188 }
02189 
02190 NS_IMETHODIMP 
02191 nsEventListenerManager::GetListenerManager(nsIEventListenerManager** aInstancePtrResult)
02192 {
02193   NS_ENSURE_ARG_POINTER(aInstancePtrResult);
02194   *aInstancePtrResult = NS_STATIC_CAST(nsIEventListenerManager*, this);
02195   NS_ADDREF(*aInstancePtrResult);
02196   return NS_OK;
02197 }
02198  
02199 NS_IMETHODIMP 
02200 nsEventListenerManager::HandleEvent(nsIDOMEvent *aEvent)
02201 {
02202   PRBool defaultActionEnabled;
02203   return DispatchEvent(aEvent, &defaultActionEnabled);
02204 }
02205 
02206 NS_IMETHODIMP
02207 nsEventListenerManager::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
02208 {
02209   return GetSystemEventGroupLM(aGroup);
02210 }
02211 
02212 nsresult
02213 nsEventListenerManager::FixContextMenuEvent(nsPresContext* aPresContext,
02214                                             nsIDOMEventTarget* aCurrentTarget,
02215                                             nsEvent* aEvent,
02216                                             nsIDOMEvent** aDOMEvent)
02217 {
02218   nsIPresShell* shell = aPresContext->GetPresShell();
02219   if (!shell) {
02220     // Nothing to do.
02221     return NS_OK;
02222   }
02223 
02224   nsresult ret = NS_OK;
02225 
02226   if (nsnull == *aDOMEvent) {
02227     // If we're here because of the key-equiv for showing context menus, we
02228     // have to twiddle with the NS event to make sure the context menu comes
02229     // up in the upper left of the relevant content area before we create
02230     // the DOM event. Since we never call InitMouseEvent() on the event, 
02231     // the client X/Y will be 0,0. We can make use of that if the widget is null.
02232     if (aEvent->message == NS_CONTEXTMENU_KEY) {
02233       NS_IF_RELEASE(((nsGUIEvent*)aEvent)->widget);
02234       aPresContext->GetViewManager()->GetWidget(&((nsGUIEvent*)aEvent)->widget);
02235       aEvent->refPoint.x = 0;
02236       aEvent->refPoint.y = 0;
02237     }
02238     ret = NS_NewDOMMouseEvent(aDOMEvent, aPresContext, NS_STATIC_CAST(nsInputEvent*, aEvent));
02239     NS_ENSURE_SUCCESS(ret, ret);
02240   }
02241 
02242   // see if we should use the caret position for the popup
02243   if (aEvent->message == NS_CONTEXTMENU_KEY) {
02244     if (PrepareToUseCaretPosition(((nsGUIEvent*)aEvent)->widget, aEvent, shell))
02245       return NS_OK;
02246   }
02247 
02248   // If we're here because of the key-equiv for showing context menus, we
02249   // have to reset the event target to the currently focused element. Get it
02250   // from the focus controller.
02251   nsCOMPtr<nsIDOMEventTarget> currentTarget(aCurrentTarget);
02252   nsCOMPtr<nsIDOMElement> currentFocus;
02253 
02254   if (aEvent->message == NS_CONTEXTMENU_KEY) {
02255     nsIDocument *doc = shell->GetDocument();
02256     if (doc) {
02257       nsCOMPtr<nsPIDOMWindow> privWindow = do_QueryInterface(doc->GetScriptGlobalObject());
02258       if (privWindow) {
02259         nsIFocusController *focusController =
02260           privWindow->GetRootFocusController();
02261         if (focusController)
02262           focusController->GetFocusedElement(getter_AddRefs(currentFocus));
02263       }
02264     }
02265   }
02266 
02267   if (currentFocus) {
02268     // Reset event coordinates relative to focused frame in view
02269     nsPoint targetPt;
02270     GetCoordinatesFor(currentFocus, aPresContext, shell, targetPt);
02271     aEvent->refPoint.x = targetPt.x;
02272     aEvent->refPoint.y = targetPt.y;
02273 
02274     currentTarget = do_QueryInterface(currentFocus);
02275     nsCOMPtr<nsIPrivateDOMEvent> pEvent(do_QueryInterface(*aDOMEvent));
02276     pEvent->SetTarget(currentTarget);
02277   }
02278 
02279   return ret;
02280 }
02281 
02282 // nsEventListenerManager::PrepareToUseCaretPosition
02283 //
02284 //    This checks to see if we should use the caret position for popup context
02285 //    menus. If we should, it fills in refpoint and point on the event and
02286 //    returns true. This function will also scroll the window as needed to make
02287 //    the caret visible.
02288 //
02289 //    The event widget should be the widget that generated the event, and
02290 //    whose coordinate system the resulting event's refPoint should be
02291 //    relative to.
02292 
02293 PRBool
02294 nsEventListenerManager::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
02295                                                   nsEvent* aEvent,
02296                                                   nsIPresShell* aShell)
02297 {
02298   nsresult rv;
02299   NS_ASSERTION(aEventWidget, "Event widget is null");
02300   NS_ASSERTION(aShell, "Shell is null");
02301 
02302   // check caret visibility
02303   nsCOMPtr<nsICaret> caret;
02304   rv = aShell->GetCaret(getter_AddRefs(caret));
02305   NS_ENSURE_SUCCESS(rv, PR_FALSE);
02306   NS_ENSURE_TRUE(caret, PR_FALSE);
02307 
02308   PRBool caretVisible = PR_FALSE;
02309   rv = caret->GetCaretVisible(&caretVisible);
02310   if (NS_FAILED(rv) || ! caretVisible)
02311     return PR_FALSE;
02312 
02313   // caret selection, watch out: GetCaretDOMSelection can return null but NS_OK
02314   nsCOMPtr<nsISelection> domSelection;
02315   rv = caret->GetCaretDOMSelection(getter_AddRefs(domSelection));
02316   NS_ENSURE_SUCCESS(rv, PR_FALSE);
02317   NS_ENSURE_TRUE(domSelection, PR_FALSE);
02318 
02319   // since the match could be an anonymous textnode inside a
02320   // <textarea> or text <input>, we need to get the outer frame
02321   // note: frames are not refcounted
02322   nsIFrame* frame = nsnull; // may be NULL
02323   nsITextControlFrame* tcFrame = nsnull; // may be NULL
02324   nsCOMPtr<nsIDOMNode> node;
02325   rv = domSelection->GetFocusNode(getter_AddRefs(node));
02326   NS_ENSURE_SUCCESS(rv, PR_FALSE);
02327   NS_ENSURE_TRUE(node, PR_FALSE);
02328   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
02329   for ( ; content; content = content->GetParent()) {
02330     if (!content->IsNativeAnonymous()) {
02331       rv = aShell->GetPrimaryFrameFor(content, &frame);
02332       if (NS_FAILED(rv) || frame) {
02333         // not refcounted, will be NULL for some elements
02334         CallQueryInterface(frame, &tcFrame);
02335       }
02336       break;
02337     }
02338   }
02339 
02340   // It seems like selCon->ScrollSelectionIntoView should be enough, but it's
02341   // not. The problem is that scrolling the selection into view when it is
02342   // below the current viewport will align the top line of the frame exactly
02343   // with the bottom of the window. This is fine, BUT, the popup event causes
02344   // the control to be re-focused which does this exact call to
02345   // ScrollFrameIntoView, which has a one-pixel disagreement of whether the
02346   // frame is actually in view. The result is that the frame is aligned with
02347   // the top of the window, but the menu is still at the bottom.
02348   //
02349   // Doing this call first forces the frame to be in view, eliminating the
02350   // problem. The only difference in the result is that if your cursor is in
02351   // an edit box below the current view, you'll get the edit box aligned with
02352   // the top of the window. This is arguably better behavior anyway.
02353   if (frame) {
02354     rv = aShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
02355                                      NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
02356     NS_ENSURE_SUCCESS(rv, PR_FALSE);
02357   }
02358 
02359   // Actually scroll the selection (ie caret) into view. Note that this must
02360   // be synchronous since we will be checking the caret position on the screen.
02361   //
02362   // Be easy about errors, and just don't scroll in those cases. Better to have
02363   // the correct menu at a weird place than the wrong menu.
02364   nsCOMPtr<nsISelectionController> selCon;
02365   if (tcFrame)
02366     tcFrame->GetSelectionContr(getter_AddRefs(selCon));
02367   else
02368     selCon = do_QueryInterface(aShell);
02369   if (selCon) {
02370     rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
02371         nsISelectionController::SELECTION_FOCUS_REGION, PR_TRUE);
02372     NS_ENSURE_SUCCESS(rv, PR_FALSE);
02373   }
02374 
02375   // get caret position relative to some view (normally the same as the
02376   // event widget view, but this is not guaranteed)
02377   PRBool isCollapsed;
02378   nsIView* view;
02379   nsRect caretCoords;
02380   rv = caret->GetCaretCoordinates(nsICaret::eRenderingViewCoordinates,
02381                                   domSelection, &caretCoords, &isCollapsed,
02382                                   &view);
02383   NS_ENSURE_SUCCESS(rv, PR_FALSE);
02384 
02385   // in case the view used for caret coordinates was something else, we need
02386   // to bring those coordinates into the space of the widget view
02387   nsIView* widgetView = nsIView::GetViewFor(aEventWidget);
02388   NS_ENSURE_TRUE(widgetView, PR_FALSE);
02389   nsPoint viewToWidget;
02390   widgetView->GetNearestWidget(&viewToWidget);
02391   nsPoint viewDelta = view->GetOffsetTo(widgetView) + viewToWidget;
02392 
02393   // caret coordinates are in twips, convert to pixels for refpoint
02394   float t2p = aShell->GetPresContext()->TwipsToPixels();
02395   aEvent->refPoint.x = NSTwipsToIntPixels(viewDelta.x + caretCoords.x + caretCoords.width, t2p);
02396   aEvent->refPoint.y = NSTwipsToIntPixels(viewDelta.y + caretCoords.y + caretCoords.height, t2p);
02397 
02398   // convert to coordinate system for point
02399   aEvent->point.x = aEvent->point.y = 0;
02400   nsPresContext* context = aShell->GetPresContext();
02401   if (context) {
02402     nsIFrame* eventFrame;
02403     context->EventStateManager()->GetEventTarget(&eventFrame);
02404     if (eventFrame) {
02405       aEvent->point = nsLayoutUtils::GetEventCoordinatesForNearestView(
02406           aEvent, eventFrame);
02407     }
02408   }
02409   return PR_TRUE;
02410 }
02411 
02412 // Get coordinates relative to root view for element, 
02413 // first ensuring the element is onscreen
02414 void
02415 nsEventListenerManager::GetCoordinatesFor(nsIDOMElement *aCurrentEl, 
02416                                           nsPresContext *aPresContext,
02417                                           nsIPresShell *aPresShell, 
02418                                           nsPoint& aTargetPt)
02419 {
02420   nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl));
02421   nsIFrame *frame = nsnull;
02422   aPresShell->GetPrimaryFrameFor(focusedContent, &frame);
02423   if (frame) {
02424     aPresShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_ANYWHERE,
02425                                            NS_PRESSHELL_SCROLL_ANYWHERE);
02426 
02427     nsPoint frameOrigin(0, 0);
02428 
02429     // Get the frame's origin within its view
02430     nsIView *view = frame->GetClosestView(&frameOrigin);
02431     NS_ASSERTION(view, "No view for frame");
02432 
02433     nsIViewManager* vm = aPresShell->GetViewManager();
02434     nsIView *rootView = nsnull;
02435     vm->GetRootView(rootView);
02436     NS_ASSERTION(rootView, "No root view in pres shell");
02437 
02438     // View's origin within its root view
02439     frameOrigin += view->GetOffsetTo(rootView);
02440 
02441     // Start context menu down and to the right from top left of frame
02442     // use the lineheight. This is a good distance to move the context
02443     // menu away from the top left corner of the frame. If we always 
02444     // used the frame height, the context menu could end up far away,
02445     // for example when we're focused on linked images.
02446     // On the other hand, we want to use the frame height if it's less
02447     // than the current line height, so that the context menu appears
02448     // associated with the correct frame.
02449     nscoord extra = frame->GetSize().height;
02450     nsIScrollableView *scrollView =
02451       nsLayoutUtils::GetNearestScrollingView(view, nsLayoutUtils::eEither);
02452     if (scrollView) {
02453       nscoord scrollViewLineHeight;
02454       scrollView->GetLineHeight(&scrollViewLineHeight);
02455       if (extra > scrollViewLineHeight) {
02456         extra = scrollViewLineHeight; 
02457       }
02458     }
02459 
02460     PRInt32 extraPixelsY = 0;
02461 #ifdef MOZ_XUL
02462     // Tree view special case (tree items have no frames)
02463     // Get the focused row and add its coordinates, which are already in pixels
02464     // XXX Boris, should we create a new interface so that event listener manager doesn't
02465     // need to know about trees? Something like nsINodelessChildCreator which
02466     // could provide the current focus coordinates?
02467     nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aCurrentEl));
02468     if (xulElement) {
02469       nsCOMPtr<nsIBoxObject> box;
02470       xulElement->GetBoxObject(getter_AddRefs(box));
02471       nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
02472       if (treeBox) {
02473         // Factor in focused row
02474         nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
02475           do_QueryInterface(aCurrentEl);
02476         NS_ASSERTION(multiSelect, "No multi select interface for tree");
02477 
02478         PRInt32 currentIndex;
02479         multiSelect->GetCurrentIndex(&currentIndex);
02480         if (currentIndex >= 0) {
02481           treeBox->EnsureRowIsVisible(currentIndex);
02482           PRInt32 firstVisibleRow, rowHeight;
02483           treeBox->GetFirstVisibleRow(&firstVisibleRow);
02484           treeBox->GetRowHeight(&rowHeight);
02485           extraPixelsY = (currentIndex - firstVisibleRow + 1) * rowHeight;
02486           extra = 0;
02487 
02488           nsCOMPtr<nsITreeColumns> cols;
02489           treeBox->GetColumns(getter_AddRefs(cols));
02490           if (cols) {
02491             nsCOMPtr<nsITreeColumn> col;
02492             cols->GetFirstColumn(getter_AddRefs(col));
02493             if (col) {
02494               nsCOMPtr<nsIDOMElement> colElement;
02495               col->GetElement(getter_AddRefs(colElement));
02496               nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement));
02497               if (colContent) {
02498                 aPresShell->GetPrimaryFrameFor(colContent, &frame);
02499                 if (frame) {
02500                   frameOrigin.y += frame->GetSize().height;
02501                 }
02502               }
02503             }
02504           }
02505         }
02506       }
02507     }
02508 #endif
02509 
02510     // Convert from twips to pixels
02511     float t2p = aPresContext->TwipsToPixels();
02512     aTargetPt.x = NSTwipsToIntPixels(frameOrigin.x + extra, t2p);
02513     aTargetPt.y = NSTwipsToIntPixels(frameOrigin.y + extra, t2p) + extraPixelsY;
02514   }
02515 }
02516 
02517 PRBool
02518 nsEventListenerManager::HasUnloadListeners()
02519 {
02520   nsVoidArray *listeners = GetListenersByType(eEventArrayType_Load, nsnull,
02521                                               PR_FALSE);
02522   if (listeners) {
02523     PRInt32 count = listeners->Count();
02524     for (PRInt32 i = 0; i < count; ++i) {
02525       PRUint32 subtype = NS_STATIC_CAST(nsListenerStruct*,
02526                                         listeners->FastElementAt(i))->mSubType;
02527       if (subtype == NS_EVENT_BITS_NONE ||
02528           subtype & (NS_EVENT_BITS_LOAD_UNLOAD |
02529                      NS_EVENT_BITS_LOAD_BEFORE_UNLOAD))
02530         return PR_TRUE;
02531     }
02532   }
02533 
02534   return PR_FALSE;
02535 }
02536 
02537 nsresult
02538 NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult) 
02539 {
02540   nsIEventListenerManager* l = new nsEventListenerManager();
02541 
02542   if (!l) {
02543     return NS_ERROR_OUT_OF_MEMORY;
02544   }
02545   
02546   return CallQueryInterface(l, aInstancePtrResult);
02547 }
02548