1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/DOMEventTargetHelper.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,281 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_DOMEventTargetHelper_h_ 1.10 +#define mozilla_DOMEventTargetHelper_h_ 1.11 + 1.12 +#include "nsCOMPtr.h" 1.13 +#include "nsGkAtoms.h" 1.14 +#include "nsCycleCollectionParticipant.h" 1.15 +#include "nsPIDOMWindow.h" 1.16 +#include "nsIScriptGlobalObject.h" 1.17 +#include "nsIScriptContext.h" 1.18 +#include "MainThreadUtils.h" 1.19 +#include "mozilla/Attributes.h" 1.20 +#include "mozilla/EventListenerManager.h" 1.21 +#include "mozilla/dom/EventTarget.h" 1.22 + 1.23 +class JSCompartment; 1.24 + 1.25 +namespace mozilla { 1.26 + 1.27 +class ErrorResult; 1.28 + 1.29 +#define NS_DOMEVENTTARGETHELPER_IID \ 1.30 +{ 0xa28385c6, 0x9451, 0x4d7e, \ 1.31 + { 0xa3, 0xdd, 0xf4, 0xb6, 0x87, 0x2f, 0xa4, 0x76 } } 1.32 + 1.33 +class DOMEventTargetHelper : public dom::EventTarget 1.34 +{ 1.35 +public: 1.36 + DOMEventTargetHelper() 1.37 + : mParentObject(nullptr) 1.38 + , mOwnerWindow(nullptr) 1.39 + , mHasOrHasHadOwnerWindow(false) 1.40 + { 1.41 + } 1.42 + DOMEventTargetHelper(nsPIDOMWindow* aWindow) 1.43 + : mParentObject(nullptr) 1.44 + , mOwnerWindow(nullptr) 1.45 + , mHasOrHasHadOwnerWindow(false) 1.46 + { 1.47 + BindToOwner(aWindow); 1.48 + // All objects coming through here are WebIDL objects 1.49 + SetIsDOMBinding(); 1.50 + } 1.51 + DOMEventTargetHelper(DOMEventTargetHelper* aOther) 1.52 + : mParentObject(nullptr) 1.53 + , mOwnerWindow(nullptr) 1.54 + , mHasOrHasHadOwnerWindow(false) 1.55 + { 1.56 + BindToOwner(aOther); 1.57 + // All objects coming through here are WebIDL objects 1.58 + SetIsDOMBinding(); 1.59 + } 1.60 + 1.61 + virtual ~DOMEventTargetHelper(); 1.62 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.63 + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(DOMEventTargetHelper) 1.64 + 1.65 + NS_DECL_NSIDOMEVENTTARGET 1.66 + 1.67 + virtual EventListenerManager* GetExistingListenerManager() const MOZ_OVERRIDE; 1.68 + virtual EventListenerManager* GetOrCreateListenerManager() MOZ_OVERRIDE; 1.69 + 1.70 + using dom::EventTarget::RemoveEventListener; 1.71 + virtual void AddEventListener(const nsAString& aType, 1.72 + dom::EventListener* aListener, 1.73 + bool aCapture, 1.74 + const dom::Nullable<bool>& aWantsUntrusted, 1.75 + ErrorResult& aRv) MOZ_OVERRIDE; 1.76 + 1.77 + NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMEVENTTARGETHELPER_IID) 1.78 + 1.79 + void GetParentObject(nsIScriptGlobalObject **aParentObject) 1.80 + { 1.81 + if (mParentObject) { 1.82 + CallQueryInterface(mParentObject, aParentObject); 1.83 + } else { 1.84 + *aParentObject = nullptr; 1.85 + } 1.86 + } 1.87 + 1.88 + static DOMEventTargetHelper* FromSupports(nsISupports* aSupports) 1.89 + { 1.90 + dom::EventTarget* target = static_cast<dom::EventTarget*>(aSupports); 1.91 +#ifdef DEBUG 1.92 + { 1.93 + nsCOMPtr<dom::EventTarget> target_qi = do_QueryInterface(aSupports); 1.94 + 1.95 + // If this assertion fires the QI implementation for the object in 1.96 + // question doesn't use the EventTarget pointer as the 1.97 + // nsISupports pointer. That must be fixed, or we'll crash... 1.98 + NS_ASSERTION(target_qi == target, "Uh, fix QI!"); 1.99 + } 1.100 +#endif 1.101 + 1.102 + return static_cast<DOMEventTargetHelper*>(target); 1.103 + } 1.104 + 1.105 + bool HasListenersFor(nsIAtom* aTypeWithOn) 1.106 + { 1.107 + return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn); 1.108 + } 1.109 + 1.110 + nsresult SetEventHandler(nsIAtom* aType, 1.111 + JSContext* aCx, 1.112 + const JS::Value& aValue); 1.113 + using dom::EventTarget::SetEventHandler; 1.114 + void GetEventHandler(nsIAtom* aType, 1.115 + JSContext* aCx, 1.116 + JS::Value* aValue); 1.117 + using dom::EventTarget::GetEventHandler; 1.118 + virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE 1.119 + { 1.120 + return nsPIDOMWindow::GetOuterFromCurrentInner(GetOwner()); 1.121 + } 1.122 + 1.123 + nsresult CheckInnerWindowCorrectness() 1.124 + { 1.125 + NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow); 1.126 + if (mOwnerWindow) { 1.127 + NS_ASSERTION(mOwnerWindow->IsInnerWindow(), "Should have inner window here!\n"); 1.128 + nsPIDOMWindow* outer = mOwnerWindow->GetOuterWindow(); 1.129 + if (!outer || outer->GetCurrentInnerWindow() != mOwnerWindow) { 1.130 + return NS_ERROR_FAILURE; 1.131 + } 1.132 + } 1.133 + return NS_OK; 1.134 + } 1.135 + 1.136 + nsPIDOMWindow* GetOwner() const { return mOwnerWindow; } 1.137 + void BindToOwner(nsIGlobalObject* aOwner); 1.138 + void BindToOwner(nsPIDOMWindow* aOwner); 1.139 + void BindToOwner(DOMEventTargetHelper* aOther); 1.140 + virtual void DisconnectFromOwner(); 1.141 + nsIGlobalObject* GetParentObject() const { return mParentObject; } 1.142 + bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; } 1.143 + 1.144 + virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE; 1.145 + virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE; 1.146 + virtual void EventListenerWasAdded(const nsAString& aType, 1.147 + ErrorResult& aRv, 1.148 + JSCompartment* aCompartment = nullptr) {} 1.149 + virtual void EventListenerWasRemoved(const nsAString& aType, 1.150 + ErrorResult& aRv, 1.151 + JSCompartment* aCompartment = nullptr) {} 1.152 +protected: 1.153 + nsresult WantsUntrusted(bool* aRetVal); 1.154 + 1.155 + nsRefPtr<EventListenerManager> mListenerManager; 1.156 + // Dispatch a trusted, non-cancellable and non-bubbling event to |this|. 1.157 + nsresult DispatchTrustedEvent(const nsAString& aEventName); 1.158 + // Make |event| trusted and dispatch |aEvent| to |this|. 1.159 + nsresult DispatchTrustedEvent(nsIDOMEvent* aEvent); 1.160 + 1.161 + virtual void LastRelease() {} 1.162 +private: 1.163 + // Inner window or sandbox. 1.164 + nsIGlobalObject* mParentObject; 1.165 + // mParentObject pre QI-ed and cached 1.166 + // (it is needed for off main thread access) 1.167 + nsPIDOMWindow* mOwnerWindow; 1.168 + bool mHasOrHasHadOwnerWindow; 1.169 +}; 1.170 + 1.171 +NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper, 1.172 + NS_DOMEVENTTARGETHELPER_IID) 1.173 + 1.174 +} // namespace mozilla 1.175 + 1.176 +// XPIDL event handlers 1.177 +#define NS_IMPL_EVENT_HANDLER(_class, _event) \ 1.178 + NS_IMETHODIMP _class::GetOn##_event(JSContext* aCx, \ 1.179 + JS::MutableHandle<JS::Value> aValue) \ 1.180 + { \ 1.181 + GetEventHandler(nsGkAtoms::on##_event, aCx, aValue.address()); \ 1.182 + return NS_OK; \ 1.183 + } \ 1.184 + NS_IMETHODIMP _class::SetOn##_event(JSContext* aCx, \ 1.185 + JS::Handle<JS::Value> aValue) \ 1.186 + { \ 1.187 + return SetEventHandler(nsGkAtoms::on##_event, aCx, aValue); \ 1.188 + } 1.189 + 1.190 +#define NS_IMPL_FORWARD_EVENT_HANDLER(_class, _event, _baseclass) \ 1.191 + NS_IMETHODIMP _class::GetOn##_event(JSContext* aCx, \ 1.192 + JS::MutableHandle<JS::Value> aValue) \ 1.193 + { \ 1.194 + return _baseclass::GetOn##_event(aCx, aValue); \ 1.195 + } \ 1.196 + NS_IMETHODIMP _class::SetOn##_event(JSContext* aCx, \ 1.197 + JS::Handle<JS::Value> aValue) \ 1.198 + { \ 1.199 + return _baseclass::SetOn##_event(aCx, aValue); \ 1.200 + } 1.201 + 1.202 +// WebIDL event handlers 1.203 +#define IMPL_EVENT_HANDLER(_event) \ 1.204 + inline mozilla::dom::EventHandlerNonNull* GetOn##_event() \ 1.205 + { \ 1.206 + if (NS_IsMainThread()) { \ 1.207 + return GetEventHandler(nsGkAtoms::on##_event, EmptyString()); \ 1.208 + } \ 1.209 + return GetEventHandler(nullptr, NS_LITERAL_STRING(#_event)); \ 1.210 + } \ 1.211 + inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback) \ 1.212 + { \ 1.213 + if (NS_IsMainThread()) { \ 1.214 + SetEventHandler(nsGkAtoms::on##_event, EmptyString(), aCallback); \ 1.215 + } else { \ 1.216 + SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), aCallback); \ 1.217 + } \ 1.218 + } 1.219 + 1.220 +/* Use this macro to declare functions that forward the behavior of this 1.221 + * interface to another object. 1.222 + * This macro doesn't forward PreHandleEvent because sometimes subclasses 1.223 + * want to override it. 1.224 + */ 1.225 +#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \ 1.226 + NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \ 1.227 + return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \ 1.228 + } \ 1.229 + NS_IMETHOD AddSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture, bool aWantsUntrusted, uint8_t _argc) { \ 1.230 + return _to AddSystemEventListener(type, listener, aUseCapture, aWantsUntrusted, _argc); \ 1.231 + } \ 1.232 + NS_IMETHOD RemoveEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture) { \ 1.233 + return _to RemoveEventListener(type, listener, useCapture); \ 1.234 + } \ 1.235 + NS_IMETHOD RemoveSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture) { \ 1.236 + return _to RemoveSystemEventListener(type, listener, aUseCapture); \ 1.237 + } \ 1.238 + NS_IMETHOD DispatchEvent(nsIDOMEvent *evt, bool *_retval) { \ 1.239 + return _to DispatchEvent(evt, _retval); \ 1.240 + } \ 1.241 + virtual mozilla::dom::EventTarget* GetTargetForDOMEvent() { \ 1.242 + return _to GetTargetForDOMEvent(); \ 1.243 + } \ 1.244 + virtual mozilla::dom::EventTarget* GetTargetForEventTargetChain() { \ 1.245 + return _to GetTargetForEventTargetChain(); \ 1.246 + } \ 1.247 + virtual nsresult WillHandleEvent( \ 1.248 + mozilla::EventChainPostVisitor & aVisitor) { \ 1.249 + return _to WillHandleEvent(aVisitor); \ 1.250 + } \ 1.251 + virtual nsresult PostHandleEvent( \ 1.252 + mozilla::EventChainPostVisitor & aVisitor) { \ 1.253 + return _to PostHandleEvent(aVisitor); \ 1.254 + } \ 1.255 + virtual nsresult DispatchDOMEvent(mozilla::WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent, nsPresContext* aPresContext, nsEventStatus* aEventStatus) { \ 1.256 + return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); \ 1.257 + } \ 1.258 + virtual mozilla::EventListenerManager* GetOrCreateListenerManager() { \ 1.259 + return _to GetOrCreateListenerManager(); \ 1.260 + } \ 1.261 + virtual mozilla::EventListenerManager* GetExistingListenerManager() const { \ 1.262 + return _to GetExistingListenerManager(); \ 1.263 + } \ 1.264 + virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv) { \ 1.265 + return _to GetContextForEventHandlers(aRv); \ 1.266 + } \ 1.267 + virtual JSContext * GetJSContextForEventHandlers(void) { \ 1.268 + return _to GetJSContextForEventHandlers(); \ 1.269 + } 1.270 + 1.271 +#define NS_REALLY_FORWARD_NSIDOMEVENTTARGET(_class) \ 1.272 + using _class::AddEventListener; \ 1.273 + using _class::RemoveEventListener; \ 1.274 + NS_FORWARD_NSIDOMEVENTTARGET(_class::) \ 1.275 + virtual mozilla::EventListenerManager* \ 1.276 + GetOrCreateListenerManager() { \ 1.277 + return _class::GetOrCreateListenerManager(); \ 1.278 + } \ 1.279 + virtual mozilla::EventListenerManager* \ 1.280 + GetExistingListenerManager() const { \ 1.281 + return _class::GetExistingListenerManager(); \ 1.282 + } 1.283 + 1.284 +#endif // mozilla_DOMEventTargetHelper_h_