JSEventHandler.h (6343B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_JSEventHandler_h_ 8 #define mozilla_JSEventHandler_h_ 9 10 #include "mozilla/MemoryReporting.h" 11 #include "mozilla/dom/EventHandlerBinding.h" 12 #include "nsAtom.h" 13 #include "nsCOMPtr.h" 14 #include "nsCycleCollectionParticipant.h" 15 #include "nsIDOMEventListener.h" 16 #include "nsIScriptContext.h" 17 18 namespace mozilla { 19 namespace dom { 20 class EventTarget; 21 } // namespace dom 22 23 class TypedEventHandler { 24 public: 25 enum HandlerType { 26 eUnset = 0, 27 eNormal = 0x1, 28 eOnError = 0x2, 29 eOnBeforeUnload = 0x3, 30 eTypeBits = 0x3 31 }; 32 33 TypedEventHandler() : mBits(0) {} 34 35 explicit TypedEventHandler(dom::EventHandlerNonNull* aHandler) : mBits(0) { 36 Assign(aHandler, eNormal); 37 } 38 39 explicit TypedEventHandler(dom::OnErrorEventHandlerNonNull* aHandler) 40 : mBits(0) { 41 Assign(aHandler, eOnError); 42 } 43 44 explicit TypedEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) 45 : mBits(0) { 46 Assign(aHandler, eOnBeforeUnload); 47 } 48 49 TypedEventHandler(const TypedEventHandler& aOther) { 50 if (aOther.HasEventHandler()) { 51 // Have to make sure we take our own ref 52 Assign(aOther.Ptr(), aOther.Type()); 53 } else { 54 mBits = 0; 55 } 56 } 57 58 ~TypedEventHandler() { ReleaseHandler(); } 59 60 HandlerType Type() const { return HandlerType(mBits & eTypeBits); } 61 62 bool HasEventHandler() const { return !!Ptr(); } 63 64 void SetHandler(const TypedEventHandler& aHandler) { 65 if (aHandler.HasEventHandler()) { 66 ReleaseHandler(); 67 Assign(aHandler.Ptr(), aHandler.Type()); 68 } else { 69 ForgetHandler(); 70 } 71 } 72 73 dom::EventHandlerNonNull* NormalEventHandler() const { 74 MOZ_ASSERT(Type() == eNormal && Ptr()); 75 return reinterpret_cast<dom::EventHandlerNonNull*>(Ptr()); 76 } 77 78 void SetHandler(dom::EventHandlerNonNull* aHandler) { 79 ReleaseHandler(); 80 Assign(aHandler, eNormal); 81 } 82 83 dom::OnBeforeUnloadEventHandlerNonNull* OnBeforeUnloadEventHandler() const { 84 MOZ_ASSERT(Type() == eOnBeforeUnload); 85 return reinterpret_cast<dom::OnBeforeUnloadEventHandlerNonNull*>(Ptr()); 86 } 87 88 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) { 89 ReleaseHandler(); 90 Assign(aHandler, eOnBeforeUnload); 91 } 92 93 dom::OnErrorEventHandlerNonNull* OnErrorEventHandler() const { 94 MOZ_ASSERT(Type() == eOnError); 95 return reinterpret_cast<dom::OnErrorEventHandlerNonNull*>(Ptr()); 96 } 97 98 void SetHandler(dom::OnErrorEventHandlerNonNull* aHandler) { 99 ReleaseHandler(); 100 Assign(aHandler, eOnError); 101 } 102 103 dom::CallbackFunction* Ptr() const { 104 // Have to cast eTypeBits so we don't have to worry about 105 // promotion issues after the bitflip. 106 return reinterpret_cast<dom::CallbackFunction*>(mBits & 107 ~uintptr_t(eTypeBits)); 108 } 109 110 void ForgetHandler() { 111 ReleaseHandler(); 112 mBits = 0; 113 } 114 115 bool operator==(const TypedEventHandler& aOther) const { 116 return Ptr() && aOther.Ptr() && 117 Ptr()->CallbackPreserveColor() == 118 aOther.Ptr()->CallbackPreserveColor(); 119 } 120 121 private: 122 void operator=(const TypedEventHandler&) = delete; 123 124 void ReleaseHandler() { 125 nsISupports* ptr = Ptr(); 126 NS_IF_RELEASE(ptr); 127 } 128 129 void Assign(nsISupports* aHandler, HandlerType aType) { 130 MOZ_ASSERT(aHandler, "Must have handler"); 131 NS_ADDREF(aHandler); 132 mBits = uintptr_t(aHandler) | uintptr_t(aType); 133 } 134 135 uintptr_t mBits; 136 }; 137 138 /** 139 * Implemented by script event listeners. Used to retrieve the script object 140 * corresponding to the event target and the handler itself. 141 * 142 * Note, mTarget is a raw pointer and the owner of the JSEventHandler object 143 * is expected to call Disconnect()! 144 */ 145 146 #define NS_JSEVENTHANDLER_IID \ 147 {0x4f486881, 0x1956, 0x4079, {0x8c, 0xa0, 0xf3, 0xbd, 0x60, 0x5c, 0xc2, 0x79}} 148 149 class JSEventHandler : public nsIDOMEventListener { 150 public: 151 NS_INLINE_DECL_STATIC_IID(NS_JSEVENTHANDLER_IID) 152 153 JSEventHandler(dom::EventTarget* aTarget, nsAtom* aType, 154 const TypedEventHandler& aTypedHandler); 155 156 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 157 158 // nsIDOMEventListener interface 159 NS_DECL_NSIDOMEVENTLISTENER 160 161 void Disconnect() { mTarget = nullptr; } 162 163 const TypedEventHandler& GetTypedEventHandler() const { 164 return mTypedHandler; 165 } 166 167 void ForgetHandler() { mTypedHandler.ForgetHandler(); } 168 169 nsAtom* EventName() const { return mEventName; } 170 171 // Set a handler for this event listener. The handler must already 172 // be bound to the right target. 173 void SetHandler(const TypedEventHandler& aTypedHandler) { 174 mTypedHandler.SetHandler(aTypedHandler); 175 } 176 void SetHandler(dom::EventHandlerNonNull* aHandler) { 177 mTypedHandler.SetHandler(aHandler); 178 } 179 void SetHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler) { 180 mTypedHandler.SetHandler(aHandler); 181 } 182 void SetHandler(dom::OnErrorEventHandlerNonNull* aHandler) { 183 mTypedHandler.SetHandler(aHandler); 184 } 185 186 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { 187 return 0; 188 189 // Measurement of the following members may be added later if DMD finds it 190 // is worthwhile: 191 // - mTarget 192 // 193 // The following members are not measured: 194 // - mTypedHandler: may be shared with others 195 // - mEventName: shared with others 196 } 197 198 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) { 199 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 200 } 201 202 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(JSEventHandler) 203 204 bool IsBlackForCC(); 205 206 protected: 207 virtual ~JSEventHandler(); 208 209 dom::EventTarget* mTarget; 210 RefPtr<nsAtom> mEventName; 211 TypedEventHandler mTypedHandler; 212 }; 213 214 } // namespace mozilla 215 216 /** 217 * Factory function. aHandler must already be bound to aTarget. 218 * aContext is allowed to be null if aHandler is already set up. 219 */ 220 nsresult NS_NewJSEventHandler(mozilla::dom::EventTarget* aTarget, nsAtom* aType, 221 const mozilla::TypedEventHandler& aTypedHandler, 222 mozilla::JSEventHandler** aReturn); 223 224 #endif // mozilla_JSEventHandler_h_