Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/events/DOMEventTargetHelper.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "nsContentUtils.h"
8
#include "nsIDocument.h"
9
#include "mozilla/Sprintf.h"
10
#include "nsGlobalWindow.h"
11
#include "mozilla/dom/Event.h"
12
#include "mozilla/dom/ScriptSettings.h"
13
#include "mozilla/DOMEventTargetHelper.h"
14
#include "mozilla/EventDispatcher.h"
15
#include "mozilla/EventListenerManager.h"
16
#include "mozilla/Likely.h"
17
18
namespace mozilla {
19
20
using namespace dom;
21
22
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper)
23
24
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper)
25
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
26
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
27
28
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
29
0
  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
30
0
    char name[512];
31
0
    nsAutoString uri;
32
0
    if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) {
33
0
      Unused << tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri);
34
0
    }
35
0
36
0
    nsXPCOMCycleCollectionParticipant* participant = nullptr;
37
0
    CallQueryInterface(tmp, &participant);
38
0
39
0
    SprintfLiteral(name, "%s %s",
40
0
                   participant->ClassName(),
41
0
                   NS_ConvertUTF16toUTF8(uri).get());
42
0
    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
43
0
  } else {
44
0
    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get())
45
0
  }
46
0
47
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
48
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
49
50
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
51
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
52
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
53
0
  tmp->MaybeDontKeepAlive();
54
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
55
56
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
57
0
  bool hasLiveWrapper = tmp->HasKnownLiveWrapper();
58
0
  if (hasLiveWrapper || tmp->IsCertainlyAliveForCC()) {
59
0
    if (tmp->mListenerManager) {
60
0
      tmp->mListenerManager->MarkForCC();
61
0
    }
62
0
    if (!hasLiveWrapper && tmp->PreservingWrapper()) {
63
0
      tmp->MarkWrapperLive();
64
0
    }
65
0
    return true;
66
0
  }
67
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
68
0
69
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
70
0
  return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
71
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
72
73
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
74
0
  return tmp->HasKnownLiveWrapper();
75
0
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
76
77
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
78
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
79
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
80
0
  NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
81
0
  NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper)
82
0
NS_INTERFACE_MAP_END
83
84
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
85
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
86
                                                   LastRelease())
87
88
DOMEventTargetHelper::~DOMEventTargetHelper()
89
0
{
90
0
  if (mParentObject) {
91
0
    mParentObject->RemoveEventTargetObject(this);
92
0
  }
93
0
  if (mListenerManager) {
94
0
    mListenerManager->Disconnect();
95
0
  }
96
0
  ReleaseWrapper(this);
97
0
}
98
99
void
100
DOMEventTargetHelper::BindToOwner(nsPIDOMWindowInner* aOwner)
101
0
{
102
0
  // Make sure to bind via BindToOwner(nsIGlobalObject*) so
103
0
  // subclasses can override the method to perform additional
104
0
  // actions.
105
0
  nsIGlobalObject* global = aOwner ? aOwner->AsGlobal() : nullptr;
106
0
  BindToOwner(global);
107
0
}
108
109
void
110
DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
111
0
{
112
0
  BindToOwnerInternal(aOwner);
113
0
}
114
115
void
116
DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
117
0
{
118
0
  // Make sure to bind via BindToOwner(nsIGlobalObject*) so
119
0
  // subclasses can override the method to perform additional
120
0
  // actions.
121
0
  if (!aOther) {
122
0
    BindToOwner(static_cast<nsIGlobalObject*>(nullptr));
123
0
    return;
124
0
  }
125
0
  BindToOwner(aOther->GetParentObject());
126
0
  mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
127
0
}
128
129
void
130
DOMEventTargetHelper::DisconnectFromOwner()
131
0
{
132
0
  if (mParentObject) {
133
0
    mParentObject->RemoveEventTargetObject(this);
134
0
  }
135
0
  mOwnerWindow = nullptr;
136
0
  mParentObject = nullptr;
137
0
  // Event listeners can't be handled anymore, so we can release them here.
138
0
  if (mListenerManager) {
139
0
    mListenerManager->Disconnect();
140
0
    mListenerManager = nullptr;
141
0
  }
142
0
143
0
  MaybeDontKeepAlive();
144
0
}
145
146
nsPIDOMWindowInner*
147
DOMEventTargetHelper::GetWindowIfCurrent() const
148
0
{
149
0
  if (NS_FAILED(CheckInnerWindowCorrectness())) {
150
0
    return nullptr;
151
0
  }
152
0
153
0
  return GetOwner();
154
0
}
155
156
nsIDocument*
157
DOMEventTargetHelper::GetDocumentIfCurrent() const
158
0
{
159
0
  nsPIDOMWindowInner* win = GetWindowIfCurrent();
160
0
  if (!win) {
161
0
    return nullptr;
162
0
  }
163
0
164
0
  return win->GetDoc();
165
0
}
166
167
bool
168
DOMEventTargetHelper::ComputeDefaultWantsUntrusted(ErrorResult& aRv)
169
0
{
170
0
  bool wantsUntrusted;
171
0
  nsresult rv = WantsUntrusted(&wantsUntrusted);
172
0
  if (NS_FAILED(rv)) {
173
0
    aRv.Throw(rv);
174
0
    return false;
175
0
  }
176
0
  return wantsUntrusted;
177
0
}
178
179
bool
180
DOMEventTargetHelper::DispatchEvent(Event& aEvent, CallerType aCallerType,
181
                                    ErrorResult& aRv)
182
0
{
183
0
  nsEventStatus status = nsEventStatus_eIgnore;
184
0
  nsresult rv =
185
0
    EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent, nullptr, &status);
186
0
  bool retval = !aEvent.DefaultPrevented(aCallerType);
187
0
  if (NS_FAILED(rv)) {
188
0
    aRv.Throw(rv);
189
0
  }
190
0
  return retval;
191
0
}
192
193
nsresult
194
DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
195
0
{
196
0
  RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
197
0
  event->InitEvent(aEventName, false, false);
198
0
199
0
  return DispatchTrustedEvent(event);
200
0
}
201
202
nsresult
203
DOMEventTargetHelper::DispatchTrustedEvent(Event* event)
204
0
{
205
0
  event->SetTrusted(true);
206
0
207
0
  ErrorResult rv;
208
0
  DispatchEvent(*event, rv);
209
0
  return rv.StealNSResult();
210
0
}
211
212
void
213
DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
214
0
{
215
0
  aVisitor.mCanHandle = true;
216
0
  aVisitor.SetParentTarget(nullptr, false);
217
0
}
218
219
nsresult
220
DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
221
0
{
222
0
  return NS_OK;
223
0
}
224
225
EventListenerManager*
226
DOMEventTargetHelper::GetOrCreateListenerManager()
227
0
{
228
0
  if (!mListenerManager) {
229
0
    mListenerManager = new EventListenerManager(this);
230
0
  }
231
0
232
0
  return mListenerManager;
233
0
}
234
235
EventListenerManager*
236
DOMEventTargetHelper::GetExistingListenerManager() const
237
0
{
238
0
  return mListenerManager;
239
0
}
240
241
nsresult
242
DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
243
0
{
244
0
  nsresult rv = CheckInnerWindowCorrectness();
245
0
  NS_ENSURE_SUCCESS(rv, rv);
246
0
247
0
  nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
248
0
  // We can let listeners on workers to always handle all the events.
249
0
  *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
250
0
  return rv;
251
0
}
252
253
void
254
DOMEventTargetHelper::EventListenerAdded(nsAtom* aType)
255
0
{
256
0
  MaybeUpdateKeepAlive();
257
0
}
258
259
void
260
DOMEventTargetHelper::EventListenerRemoved(nsAtom* aType)
261
0
{
262
0
  MaybeUpdateKeepAlive();
263
0
}
264
265
void
266
DOMEventTargetHelper::KeepAliveIfHasListenersFor(const nsAString& aType)
267
0
{
268
0
  mKeepingAliveTypes.mStrings.AppendElement(aType);
269
0
  MaybeUpdateKeepAlive();
270
0
}
271
272
void
273
DOMEventTargetHelper::KeepAliveIfHasListenersFor(nsAtom* aType)
274
0
{
275
0
  mKeepingAliveTypes.mAtoms.AppendElement(aType);
276
0
  MaybeUpdateKeepAlive();
277
0
}
278
279
void
280
DOMEventTargetHelper::IgnoreKeepAliveIfHasListenersFor(const nsAString& aType)
281
0
{
282
0
  mKeepingAliveTypes.mStrings.RemoveElement(aType);
283
0
  MaybeUpdateKeepAlive();
284
0
}
285
286
void
287
DOMEventTargetHelper::IgnoreKeepAliveIfHasListenersFor(nsAtom* aType)
288
0
{
289
0
  mKeepingAliveTypes.mAtoms.RemoveElement(aType);
290
0
  MaybeUpdateKeepAlive();
291
0
}
292
293
void
294
DOMEventTargetHelper::MaybeUpdateKeepAlive()
295
0
{
296
0
  bool shouldBeKeptAlive = false;
297
0
298
0
  if (NS_SUCCEEDED(CheckInnerWindowCorrectness())) {
299
0
    if (!mKeepingAliveTypes.mAtoms.IsEmpty()) {
300
0
      for (uint32_t i = 0; i < mKeepingAliveTypes.mAtoms.Length(); ++i) {
301
0
        if (HasListenersFor(mKeepingAliveTypes.mAtoms[i])) {
302
0
          shouldBeKeptAlive = true;
303
0
          break;
304
0
        }
305
0
      }
306
0
    }
307
0
308
0
    if (!shouldBeKeptAlive && !mKeepingAliveTypes.mStrings.IsEmpty()) {
309
0
      for (uint32_t i = 0; i < mKeepingAliveTypes.mStrings.Length(); ++i) {
310
0
        if (HasListenersFor(mKeepingAliveTypes.mStrings[i])) {
311
0
          shouldBeKeptAlive = true;
312
0
          break;
313
0
        }
314
0
      }
315
0
    }
316
0
  }
317
0
318
0
  if (shouldBeKeptAlive == mIsKeptAlive) {
319
0
    return;
320
0
  }
321
0
322
0
  mIsKeptAlive = shouldBeKeptAlive;
323
0
  if (mIsKeptAlive) {
324
0
    AddRef();
325
0
  } else {
326
0
    Release();
327
0
  }
328
0
}
329
330
void
331
DOMEventTargetHelper::MaybeDontKeepAlive()
332
0
{
333
0
  if (mIsKeptAlive) {
334
0
    mIsKeptAlive = false;
335
0
    Release();
336
0
  }
337
0
}
338
339
void
340
DOMEventTargetHelper::BindToOwnerInternal(nsIGlobalObject* aOwner)
341
0
{
342
0
  if (mParentObject) {
343
0
    mParentObject->RemoveEventTargetObject(this);
344
0
    if (mOwnerWindow) {
345
0
      mOwnerWindow = nullptr;
346
0
    }
347
0
    mParentObject = nullptr;
348
0
    mHasOrHasHadOwnerWindow = false;
349
0
  }
350
0
  if (aOwner) {
351
0
    mParentObject = aOwner;
352
0
    aOwner->AddEventTargetObject(this);
353
0
    // Let's cache the result of this QI for fast access and off main thread usage
354
0
    mOwnerWindow = nsCOMPtr<nsPIDOMWindowInner>(do_QueryInterface(aOwner)).get();
355
0
    if (mOwnerWindow) {
356
0
      mHasOrHasHadOwnerWindow = true;
357
0
    }
358
0
  }
359
0
}
360
361
} // namespace mozilla