1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License
6 : * Version 1.1 (the "License"); you may not use this file except in
7 : * compliance with the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Corporation
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Olli Pettay <Olli.Pettay@helsinki.fi>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsDOMEventTargetHelper.h"
40 : #include "nsContentUtils.h"
41 : #include "nsEventDispatcher.h"
42 : #include "nsGUIEvent.h"
43 : #include "nsIDocument.h"
44 : #include "nsIJSContextStack.h"
45 : #include "nsDOMJSUtils.h"
46 : #include "prprf.h"
47 : #include "nsGlobalWindow.h"
48 :
49 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper)
50 23568 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventListenerWrapper)
51 3507 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
52 3507 : NS_INTERFACE_MAP_END_AGGREGATED(mListener)
53 :
54 14307 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMEventListenerWrapper)
55 17814 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMEventListenerWrapper)
56 :
57 353 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEventListenerWrapper)
58 353 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListener)
59 353 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
60 :
61 353 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEventListenerWrapper)
62 353 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListener)
63 353 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
64 :
65 : NS_IMETHODIMP
66 3433 : nsDOMEventListenerWrapper::HandleEvent(nsIDOMEvent* aEvent)
67 : {
68 3433 : return mListener->HandleEvent(aEvent);
69 : }
70 :
71 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventTargetHelper)
72 :
73 6262 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMEventTargetHelper)
74 6262 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
75 6262 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
76 :
77 641 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDOMEventTargetHelper)
78 641 : if (NS_UNLIKELY(cb.WantDebugInfo())) {
79 : char name[512];
80 0 : nsAutoString uri;
81 0 : if (tmp->mOwner && tmp->mOwner->GetExtantDocument()) {
82 0 : tmp->mOwner->GetExtantDocument()->GetDocumentURI(uri);
83 : }
84 : PR_snprintf(name, sizeof(name), "nsDOMEventTargetHelper %s",
85 0 : NS_ConvertUTF16toUTF8(uri).get());
86 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsDOMEventTargetHelper),
87 0 : name);
88 : } else {
89 641 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDOMEventTargetHelper, tmp->mRefCnt.get())
90 : }
91 :
92 641 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
93 641 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mListenerManager,
94 : nsEventListenerManager)
95 641 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
96 :
97 623 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEventTargetHelper)
98 623 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
99 623 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
100 623 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
101 :
102 143214 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventTargetHelper)
103 117383 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
104 101949 : NS_INTERFACE_MAP_ENTRY(nsISupports)
105 98236 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
106 28470 : NS_INTERFACE_MAP_END
107 :
108 238329 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMEventTargetHelper)
109 238329 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMEventTargetHelper)
110 :
111 34390 : NS_IMPL_DOMTARGET_DEFAULTS(nsDOMEventTargetHelper);
112 :
113 7354 : nsDOMEventTargetHelper::~nsDOMEventTargetHelper()
114 : {
115 3677 : if (mOwner) {
116 0 : static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
117 : }
118 3677 : if (mListenerManager) {
119 2839 : mListenerManager->Disconnect();
120 : }
121 3677 : nsContentUtils::ReleaseWrapper(this, this);
122 7354 : }
123 :
124 : void
125 77 : nsDOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
126 : {
127 77 : if (mOwner) {
128 0 : static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
129 0 : mOwner = nsnull;
130 0 : mHasOrHasHadOwner = false;
131 : }
132 77 : if (aOwner) {
133 0 : mOwner = aOwner;
134 0 : mHasOrHasHadOwner = true;
135 0 : static_cast<nsGlobalWindow*>(mOwner)->AddEventTargetObject(this);
136 : }
137 77 : }
138 :
139 : void
140 3003 : nsDOMEventTargetHelper::BindToOwner(nsDOMEventTargetHelper* aOther)
141 : {
142 3003 : if (mOwner) {
143 0 : static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
144 0 : mOwner = nsnull;
145 0 : mHasOrHasHadOwner = false;
146 : }
147 3003 : if (aOther) {
148 3003 : mHasOrHasHadOwner = aOther->HasOrHasHadOwner();
149 3003 : if (aOther->GetOwner()) {
150 0 : mOwner = aOther->GetOwner();
151 0 : mHasOrHasHadOwner = true;
152 0 : static_cast<nsGlobalWindow*>(mOwner)->AddEventTargetObject(this);
153 : }
154 : }
155 3003 : }
156 :
157 : void
158 0 : nsDOMEventTargetHelper::DisconnectFromOwner()
159 : {
160 0 : mOwner = nsnull;
161 : // Event listeners can't be handled anymore, so we can release them here.
162 0 : if (mListenerManager) {
163 0 : mListenerManager->Disconnect();
164 0 : mListenerManager = nsnull;
165 : }
166 0 : }
167 :
168 : NS_IMETHODIMP
169 29 : nsDOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
170 : nsIDOMEventListener* aListener,
171 : bool aUseCapture)
172 : {
173 29 : nsEventListenerManager* elm = GetListenerManager(false);
174 29 : if (elm) {
175 29 : elm->RemoveEventListener(aType, aListener, aUseCapture);
176 : }
177 :
178 29 : return NS_OK;
179 : }
180 :
181 0 : NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsDOMEventTargetHelper)
182 :
183 : NS_IMETHODIMP
184 4582 : nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
185 : nsIDOMEventListener *aListener,
186 : bool aUseCapture,
187 : bool aWantsUntrusted,
188 : PRUint8 aOptionalArgc)
189 : {
190 4582 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
191 : "Won't check if this is chrome, you want to set "
192 : "aWantsUntrusted to false or make the aWantsUntrusted "
193 : "explicit by making aOptionalArgc non-zero.");
194 :
195 4582 : if (aOptionalArgc < 2) {
196 : nsresult rv;
197 4582 : nsIScriptContext* context = GetContextForEventHandlers(&rv);
198 4582 : NS_ENSURE_SUCCESS(rv, rv);
199 : nsCOMPtr<nsIDocument> doc =
200 9164 : nsContentUtils::GetDocumentFromScriptContext(context);
201 4582 : aWantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc);
202 : }
203 :
204 4582 : nsEventListenerManager* elm = GetListenerManager(true);
205 4582 : NS_ENSURE_STATE(elm);
206 4582 : elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
207 4582 : return NS_OK;
208 : }
209 :
210 : NS_IMETHODIMP
211 0 : nsDOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
212 : nsIDOMEventListener *aListener,
213 : bool aUseCapture,
214 : bool aWantsUntrusted,
215 : PRUint8 aOptionalArgc)
216 : {
217 0 : NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
218 : "Won't check if this is chrome, you want to set "
219 : "aWantsUntrusted to false or make the aWantsUntrusted "
220 : "explicit by making aOptionalArgc non-zero.");
221 :
222 0 : if (aOptionalArgc < 2) {
223 : nsresult rv;
224 0 : nsIScriptContext* context = GetContextForEventHandlers(&rv);
225 0 : NS_ENSURE_SUCCESS(rv, rv);
226 : nsCOMPtr<nsIDocument> doc =
227 0 : nsContentUtils::GetDocumentFromScriptContext(context);
228 0 : aWantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc);
229 : }
230 :
231 : return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
232 0 : aWantsUntrusted);
233 : }
234 :
235 : NS_IMETHODIMP
236 4858 : nsDOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
237 : {
238 4858 : nsEventStatus status = nsEventStatus_eIgnore;
239 : nsresult rv =
240 4858 : nsEventDispatcher::DispatchDOMEvent(this, nsnull, aEvent, nsnull, &status);
241 :
242 4858 : *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
243 4858 : return rv;
244 : }
245 :
246 : nsresult
247 3508 : nsDOMEventTargetHelper::RemoveAddEventListener(const nsAString& aType,
248 : nsRefPtr<nsDOMEventListenerWrapper>& aCurrent,
249 : nsIDOMEventListener* aNew)
250 : {
251 3508 : if (aCurrent) {
252 27 : RemoveEventListener(aType, aCurrent, false);
253 27 : aCurrent = nsnull;
254 : }
255 3508 : if (aNew) {
256 3507 : aCurrent = new nsDOMEventListenerWrapper(aNew);
257 3507 : NS_ENSURE_TRUE(aCurrent, NS_ERROR_OUT_OF_MEMORY);
258 3507 : nsIDOMEventTarget::AddEventListener(aType, aCurrent, false);
259 : }
260 3508 : return NS_OK;
261 : }
262 :
263 : nsresult
264 3 : nsDOMEventTargetHelper::GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
265 : nsIDOMEventListener** aListener)
266 : {
267 3 : NS_ENSURE_ARG_POINTER(aListener);
268 3 : if (aWrapper) {
269 0 : NS_IF_ADDREF(*aListener = aWrapper->GetInner());
270 : } else {
271 3 : *aListener = nsnull;
272 : }
273 3 : return NS_OK;
274 : }
275 :
276 :
277 : nsresult
278 9859 : nsDOMEventTargetHelper::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
279 : {
280 9859 : aVisitor.mCanHandle = true;
281 9859 : aVisitor.mParentTarget = nsnull;
282 9859 : return NS_OK;
283 : }
284 :
285 : nsresult
286 9962 : nsDOMEventTargetHelper::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
287 : {
288 9962 : return NS_OK;
289 : }
290 :
291 : nsresult
292 5078 : nsDOMEventTargetHelper::DispatchDOMEvent(nsEvent* aEvent,
293 : nsIDOMEvent* aDOMEvent,
294 : nsPresContext* aPresContext,
295 : nsEventStatus* aEventStatus)
296 : {
297 : return
298 : nsEventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent, aPresContext,
299 5078 : aEventStatus);
300 : }
301 :
302 : nsEventListenerManager*
303 32736 : nsDOMEventTargetHelper::GetListenerManager(bool aCreateIfNotFound)
304 : {
305 32736 : if (!mListenerManager && aCreateIfNotFound) {
306 3168 : mListenerManager = new nsEventListenerManager(this);
307 : }
308 :
309 32736 : return mListenerManager;
310 : }
311 :
312 : nsIScriptContext*
313 10130 : nsDOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
314 : {
315 10130 : *aRv = CheckInnerWindowCorrectness();
316 10130 : if (NS_FAILED(*aRv)) {
317 0 : return nsnull;
318 : }
319 0 : return mOwner ? static_cast<nsGlobalWindow*>(mOwner)->GetContextInternal()
320 10130 : : nsnull;
321 : }
322 :
323 : void
324 2 : nsDOMEventTargetHelper::Init(JSContext* aCx)
325 : {
326 2 : JSContext* cx = aCx;
327 2 : if (!cx) {
328 2 : nsIJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
329 :
330 2 : if (!stack)
331 0 : return;
332 :
333 2 : if (NS_FAILED(stack->Peek(&cx)) || !cx)
334 0 : return;
335 : }
336 :
337 2 : NS_ASSERTION(cx, "Should have returned earlier ...");
338 2 : nsIScriptContext* context = GetScriptContextFromJSContext(cx);
339 2 : if (context) {
340 : nsCOMPtr<nsPIDOMWindow> window =
341 0 : do_QueryInterface(context->GetGlobalObject());
342 0 : if (window) {
343 0 : BindToOwner(window->GetCurrentInnerWindow());
344 : }
345 : }
346 4392 : }
|