Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/events/Event.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 "AccessCheck.h"
8
#include "base/basictypes.h"
9
#include "ipc/IPCMessageUtils.h"
10
#include "mozilla/dom/Event.h"
11
#include "mozilla/dom/ShadowRoot.h"
12
#include "mozilla/EventDispatcher.h"
13
#include "mozilla/ContentEvents.h"
14
#include "mozilla/DOMEventTargetHelper.h"
15
#include "mozilla/EventStateManager.h"
16
#include "mozilla/InternalMutationEvent.h"
17
#include "mozilla/dom/Performance.h"
18
#include "mozilla/dom/WorkerPrivate.h"
19
#include "mozilla/MiscEvents.h"
20
#include "mozilla/MouseEvents.h"
21
#include "mozilla/Preferences.h"
22
#include "mozilla/TextEvents.h"
23
#include "mozilla/TouchEvents.h"
24
#include "nsContentUtils.h"
25
#include "nsCOMPtr.h"
26
#include "nsDeviceContext.h"
27
#include "nsError.h"
28
#include "nsGlobalWindow.h"
29
#include "nsIFrame.h"
30
#include "nsIContent.h"
31
#include "nsIContentInlines.h"
32
#include "nsIDocument.h"
33
#include "nsIPresShell.h"
34
#include "nsIScrollableFrame.h"
35
#include "nsJSEnvironment.h"
36
#include "nsLayoutUtils.h"
37
#include "nsPIWindowRoot.h"
38
#include "nsRFPService.h"
39
40
namespace mozilla {
41
namespace dom {
42
43
static char *sPopupAllowedEvents;
44
45
static bool sReturnHighResTimeStamp = false;
46
static bool sReturnHighResTimeStampIsSet = false;
47
48
Event::Event(EventTarget* aOwner,
49
             nsPresContext* aPresContext,
50
             WidgetEvent* aEvent)
51
0
{
52
0
  ConstructorInit(aOwner, aPresContext, aEvent);
53
0
}
54
55
Event::Event(nsPIDOMWindowInner* aParent)
56
0
{
57
0
  ConstructorInit(nsGlobalWindowInner::Cast(aParent), nullptr, nullptr);
58
0
}
59
60
void
61
Event::ConstructorInit(EventTarget* aOwner,
62
                       nsPresContext* aPresContext,
63
                       WidgetEvent* aEvent)
64
0
{
65
0
  SetOwner(aOwner);
66
0
  mIsMainThreadEvent = NS_IsMainThread();
67
0
68
0
  if (mIsMainThreadEvent && !sReturnHighResTimeStampIsSet) {
69
0
    Preferences::AddBoolVarCache(&sReturnHighResTimeStamp,
70
0
                                 "dom.event.highrestimestamp.enabled",
71
0
                                 sReturnHighResTimeStamp);
72
0
    sReturnHighResTimeStampIsSet = true;
73
0
  }
74
0
75
0
  mPrivateDataDuplicated = false;
76
0
  mWantsPopupControlCheck = false;
77
0
78
0
  if (aEvent) {
79
0
    mEvent = aEvent;
80
0
    mEventIsInternal = false;
81
0
  }
82
0
  else {
83
0
    mEventIsInternal = true;
84
0
    /*
85
0
      A derived class might want to allocate its own type of aEvent
86
0
      (derived from WidgetEvent). To do this, it should take care to pass
87
0
      a non-nullptr aEvent to this ctor, e.g.:
88
0
89
0
        FooEvent::FooEvent(..., WidgetEvent* aEvent)
90
0
          : Event(..., aEvent ? aEvent : new WidgetEvent())
91
0
92
0
      Then, to override the mEventIsInternal assignments done by the
93
0
      base ctor, it should do this in its own ctor:
94
0
95
0
        FooEvent::FooEvent(..., WidgetEvent* aEvent)
96
0
        ...
97
0
        {
98
0
          ...
99
0
          if (aEvent) {
100
0
            mEventIsInternal = false;
101
0
          }
102
0
          else {
103
0
            mEventIsInternal = true;
104
0
          }
105
0
          ...
106
0
        }
107
0
     */
108
0
    mEvent = new WidgetEvent(false, eVoidEvent);
109
0
    mEvent->mTime = PR_Now();
110
0
  }
111
0
112
0
  InitPresContextData(aPresContext);
113
0
}
114
115
void
116
Event::InitPresContextData(nsPresContext* aPresContext)
117
0
{
118
0
  mPresContext = aPresContext;
119
0
  // Get the explicit original target (if it's anonymous make it null)
120
0
  {
121
0
    nsCOMPtr<nsIContent> content = GetTargetFromFrame();
122
0
    mExplicitOriginalTarget = content;
123
0
    if (content && content->IsInAnonymousSubtree()) {
124
0
      mExplicitOriginalTarget = nullptr;
125
0
    }
126
0
  }
127
0
}
128
129
Event::~Event()
130
0
{
131
0
  NS_ASSERT_OWNINGTHREAD(Event);
132
0
133
0
  if (mEventIsInternal && mEvent) {
134
0
    delete mEvent;
135
0
  }
136
0
}
137
138
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
139
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
140
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
141
0
  NS_INTERFACE_MAP_ENTRY(Event)
142
0
NS_INTERFACE_MAP_END
143
144
NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
145
NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
146
147
NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
148
149
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
150
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
151
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
152
153
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
154
0
  if (tmp->mEventIsInternal) {
155
0
    tmp->mEvent->mTarget = nullptr;
156
0
    tmp->mEvent->mCurrentTarget = nullptr;
157
0
    tmp->mEvent->mOriginalTarget = nullptr;
158
0
    tmp->mEvent->mRelatedTarget = nullptr;
159
0
    tmp->mEvent->mOriginalRelatedTarget = nullptr;
160
0
    switch (tmp->mEvent->mClass) {
161
0
      case eDragEventClass: {
162
0
        WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
163
0
        dragEvent->mDataTransfer = nullptr;
164
0
        break;
165
0
      }
166
0
      case eClipboardEventClass:
167
0
        tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
168
0
        break;
169
0
      case eMutationEventClass:
170
0
        tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
171
0
        break;
172
0
      default:
173
0
        break;
174
0
    }
175
0
  }
176
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
177
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
178
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
179
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
180
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
181
182
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
183
0
  if (tmp->mEventIsInternal) {
184
0
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
185
0
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
186
0
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
187
0
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
188
0
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
189
0
    switch (tmp->mEvent->mClass) {
190
0
      case eDragEventClass: {
191
0
        WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
192
0
        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
193
0
        cb.NoteXPCOMChild(dragEvent->mDataTransfer);
194
0
        break;
195
0
      }
196
0
      case eClipboardEventClass:
197
0
        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
198
0
        cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
199
0
        break;
200
0
      case eMutationEventClass:
201
0
        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
202
0
        cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
203
0
        break;
204
0
      default:
205
0
        break;
206
0
    }
207
0
  }
208
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
209
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
210
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
211
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
212
213
214
JSObject*
215
Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
216
0
{
217
0
  return WrapObjectInternal(aCx, aGivenProto);
218
0
}
219
220
JSObject*
221
Event::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
222
0
{
223
0
  return Event_Binding::Wrap(aCx, this, aGivenProto);
224
0
}
225
226
void
227
Event::GetType(nsAString& aType) const
228
0
{
229
0
  GetWidgetEventType(mEvent, aType);
230
0
}
231
232
EventTarget*
233
Event::GetTarget() const
234
0
{
235
0
  return mEvent->GetDOMEventTarget();
236
0
}
237
238
EventTarget*
239
Event::GetCurrentTarget() const
240
0
{
241
0
  return mEvent->GetCurrentDOMEventTarget();
242
0
}
243
244
void
245
Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
246
0
{
247
0
  EventDispatcher::GetComposedPathFor(mEvent, aPath);
248
0
}
249
250
//
251
// Get the actual event target node (may have been retargeted for mouse events)
252
//
253
already_AddRefed<nsIContent>
254
Event::GetTargetFromFrame()
255
0
{
256
0
  if (!mPresContext) { return nullptr; }
257
0
258
0
  // Get the mTarget frame (have to get the ESM first)
259
0
  nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
260
0
  if (!targetFrame) { return nullptr; }
261
0
262
0
  // get the real content
263
0
  nsCOMPtr<nsIContent> realEventContent;
264
0
  targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
265
0
  return realEventContent.forget();
266
0
}
267
268
EventTarget*
269
Event::GetExplicitOriginalTarget() const
270
0
{
271
0
  if (mExplicitOriginalTarget) {
272
0
    return mExplicitOriginalTarget;
273
0
  }
274
0
  return GetTarget();
275
0
}
276
277
EventTarget*
278
Event::GetOriginalTarget() const
279
0
{
280
0
  return mEvent->GetOriginalDOMEventTarget();
281
0
}
282
283
EventTarget*
284
Event::GetComposedTarget() const
285
0
{
286
0
  EventTarget* et = GetOriginalTarget();
287
0
  nsCOMPtr<nsIContent> content = do_QueryInterface(et);
288
0
  if (!content) {
289
0
    return et;
290
0
  }
291
0
  nsIContent* nonChrome = content->FindFirstNonChromeOnlyAccessContent();
292
0
  return nonChrome ?
293
0
    static_cast<EventTarget*>(nonChrome) :
294
0
    static_cast<EventTarget*>(content->GetComposedDoc());
295
0
}
296
297
void
298
Event::SetTrusted(bool aTrusted)
299
0
{
300
0
  mEvent->mFlags.mIsTrusted = aTrusted;
301
0
}
302
303
bool
304
Event::Init(mozilla::dom::EventTarget* aGlobal)
305
0
{
306
0
  if (!mIsMainThreadEvent) {
307
0
    return IsCurrentThreadRunningChromeWorker();
308
0
  }
309
0
  bool trusted = false;
310
0
  nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aGlobal);
311
0
  if (w) {
312
0
    nsCOMPtr<nsIDocument> d = w->GetExtantDoc();
313
0
    if (d) {
314
0
      trusted = nsContentUtils::IsChromeDoc(d);
315
0
      nsPresContext* presContext = d->GetPresContext();
316
0
      if (presContext) {
317
0
        InitPresContextData(presContext);
318
0
      }
319
0
    }
320
0
  }
321
0
  return trusted;
322
0
}
323
324
// static
325
already_AddRefed<Event>
326
Event::Constructor(const GlobalObject& aGlobal,
327
                   const nsAString& aType,
328
                   const EventInit& aParam,
329
                   ErrorResult& aRv)
330
0
{
331
0
  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
332
0
  return Constructor(t, aType, aParam);
333
0
}
334
335
// static
336
already_AddRefed<Event>
337
Event::Constructor(EventTarget* aEventTarget,
338
                   const nsAString& aType,
339
                   const EventInit& aParam)
340
0
{
341
0
  RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
342
0
  bool trusted = e->Init(aEventTarget);
343
0
  e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
344
0
  e->SetTrusted(trusted);
345
0
  e->SetComposed(aParam.mComposed);
346
0
  return e.forget();
347
0
}
348
349
uint16_t
350
Event::EventPhase() const
351
0
{
352
0
  // Note, remember to check that this works also
353
0
  // if or when Bug 235441 is fixed.
354
0
  if ((mEvent->mCurrentTarget &&
355
0
       mEvent->mCurrentTarget == mEvent->mTarget) ||
356
0
       mEvent->mFlags.InTargetPhase()) {
357
0
    return Event_Binding::AT_TARGET;
358
0
  }
359
0
  if (mEvent->mFlags.mInCapturePhase) {
360
0
    return Event_Binding::CAPTURING_PHASE;
361
0
  }
362
0
  if (mEvent->mFlags.mInBubblingPhase) {
363
0
    return Event_Binding::BUBBLING_PHASE;
364
0
  }
365
0
  return Event_Binding::NONE;
366
0
}
367
368
void
369
Event::StopPropagation()
370
0
{
371
0
  mEvent->StopPropagation();
372
0
}
373
374
void
375
Event::StopImmediatePropagation()
376
0
{
377
0
  mEvent->StopImmediatePropagation();
378
0
}
379
380
void
381
Event::StopCrossProcessForwarding()
382
0
{
383
0
  mEvent->StopCrossProcessForwarding();
384
0
}
385
386
void
387
Event::PreventDefault()
388
0
{
389
0
  // This method is called only from C++ code which must handle default action
390
0
  // of this event.  So, pass true always.
391
0
  PreventDefaultInternal(true);
392
0
}
393
394
void
395
Event::PreventDefault(JSContext* aCx, CallerType aCallerType)
396
0
{
397
0
  // Note that at handling default action, another event may be dispatched.
398
0
  // Then, JS in content mey be call preventDefault()
399
0
  // even in the event is in system event group.  Therefore, don't refer
400
0
  // mInSystemGroup here.
401
0
  nsIPrincipal* principal = mIsMainThreadEvent ?
402
0
                              nsContentUtils::SubjectPrincipal(aCx) : nullptr;
403
0
404
0
  PreventDefaultInternal(aCallerType == CallerType::System, principal);
405
0
}
406
407
void
408
Event::PreventDefaultInternal(bool aCalledByDefaultHandler,
409
                              nsIPrincipal* aPrincipal)
410
0
{
411
0
  if (!mEvent->mFlags.mCancelable) {
412
0
    return;
413
0
  }
414
0
  if (mEvent->mFlags.mInPassiveListener) {
415
0
    nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(mOwner));
416
0
    if (win) {
417
0
      if (nsIDocument* doc = win->GetExtantDoc()) {
418
0
        nsString type;
419
0
        GetType(type);
420
0
        const char16_t* params[] = { type.get() };
421
0
        doc->WarnOnceAbout(nsIDocument::ePreventDefaultFromPassiveListener,
422
0
          false, params, ArrayLength(params));
423
0
      }
424
0
    }
425
0
    return;
426
0
  }
427
0
428
0
  mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
429
0
430
0
  if (!IsTrusted()) {
431
0
    return;
432
0
  }
433
0
434
0
  WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
435
0
  if (!dragEvent) {
436
0
    return;
437
0
  }
438
0
439
0
  nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->mCurrentTarget);
440
0
  if (!node) {
441
0
    nsCOMPtr<nsPIDOMWindowOuter> win =
442
0
      do_QueryInterface(mEvent->mCurrentTarget);
443
0
    if (!win) {
444
0
      return;
445
0
    }
446
0
    node = win->GetExtantDoc();
447
0
  }
448
0
  if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
449
0
    dragEvent->mDefaultPreventedOnContent = true;
450
0
  }
451
0
}
452
453
void
454
Event::SetEventType(const nsAString& aEventTypeArg)
455
0
{
456
0
  mEvent->mSpecifiedEventTypeString.Truncate();
457
0
  if (mIsMainThreadEvent) {
458
0
    mEvent->mSpecifiedEventType =
459
0
      nsContentUtils::GetEventMessageAndAtom(aEventTypeArg, mEvent->mClass,
460
0
                                             &(mEvent->mMessage));
461
0
    mEvent->SetDefaultComposed();
462
0
  } else {
463
0
    mEvent->mSpecifiedEventType =
464
0
      NS_Atomize(NS_LITERAL_STRING("on") + aEventTypeArg);
465
0
    mEvent->mMessage = eUnidentifiedEvent;
466
0
    mEvent->SetComposed(aEventTypeArg);
467
0
  }
468
0
  mEvent->SetDefaultComposedInNativeAnonymousContent();
469
0
}
470
471
already_AddRefed<EventTarget>
472
Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
473
0
{
474
0
  nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
475
0
  if (relatedTarget) {
476
0
    nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
477
0
478
0
    if (content && content->ChromeOnlyAccess() &&
479
0
        !nsContentUtils::CanAccessNativeAnon()) {
480
0
      content = content->FindFirstNonChromeOnlyAccessContent();
481
0
      relatedTarget = do_QueryInterface(content);
482
0
    }
483
0
484
0
    if (relatedTarget) {
485
0
      relatedTarget = relatedTarget->GetTargetForDOMEvent();
486
0
    }
487
0
  }
488
0
  return relatedTarget.forget();
489
0
}
490
491
void
492
Event::InitEvent(const nsAString& aEventTypeArg,
493
                 mozilla::CanBubble aCanBubbleArg,
494
                 mozilla::Cancelable aCancelableArg,
495
                 mozilla::Composed aComposedArg)
496
0
{
497
0
  // Make sure this event isn't already being dispatched.
498
0
  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
499
0
500
0
  if (IsTrusted()) {
501
0
    // Ensure the caller is permitted to dispatch trusted DOM events.
502
0
    if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
503
0
      SetTrusted(false);
504
0
    }
505
0
  }
506
0
507
0
  SetEventType(aEventTypeArg);
508
0
509
0
  mEvent->mFlags.mBubbles = aCanBubbleArg == CanBubble::eYes;
510
0
  mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
511
0
  if (aComposedArg != Composed::eDefault) {
512
0
    mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
513
0
  }
514
0
515
0
  mEvent->mFlags.mDefaultPrevented = false;
516
0
  mEvent->mFlags.mDefaultPreventedByContent = false;
517
0
  mEvent->mFlags.mDefaultPreventedByChrome = false;
518
0
  mEvent->mFlags.mPropagationStopped = false;
519
0
  mEvent->mFlags.mImmediatePropagationStopped = false;
520
0
521
0
  // Clearing the old targets, so that the event is targeted correctly when
522
0
  // re-dispatching it.
523
0
  mEvent->mTarget = nullptr;
524
0
  mEvent->mOriginalTarget = nullptr;
525
0
}
526
527
void
528
Event::DuplicatePrivateData()
529
0
{
530
0
  NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
531
0
  if (mEventIsInternal) {
532
0
    return;
533
0
  }
534
0
535
0
  mEvent = mEvent->Duplicate();
536
0
  mPresContext = nullptr;
537
0
  mEventIsInternal = true;
538
0
  mPrivateDataDuplicated = true;
539
0
}
540
541
void
542
Event::SetTarget(EventTarget* aTarget)
543
0
{
544
0
  mEvent->mTarget = aTarget;
545
0
}
546
547
bool
548
Event::IsDispatchStopped()
549
0
{
550
0
  return mEvent->PropagationStopped();
551
0
}
552
553
WidgetEvent*
554
Event::WidgetEventPtr()
555
0
{
556
0
  return mEvent;
557
0
}
558
559
// return true if eventName is contained within events, delimited by
560
// spaces
561
static bool
562
PopupAllowedForEvent(const char *eventName)
563
0
{
564
0
  if (!sPopupAllowedEvents) {
565
0
    Event::PopupAllowedEventsChanged();
566
0
567
0
    if (!sPopupAllowedEvents) {
568
0
      return false;
569
0
    }
570
0
  }
571
0
572
0
  nsDependentCString events(sPopupAllowedEvents);
573
0
574
0
  nsCString::const_iterator start, end;
575
0
  nsCString::const_iterator startiter(events.BeginReading(start));
576
0
  events.EndReading(end);
577
0
578
0
  while (startiter != end) {
579
0
    nsCString::const_iterator enditer(end);
580
0
581
0
    if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
582
0
      return false;
583
0
584
0
    // the match is surrounded by spaces, or at a string boundary
585
0
    if ((startiter == start || *--startiter == ' ') &&
586
0
        (enditer == end || *enditer == ' ')) {
587
0
      return true;
588
0
    }
589
0
590
0
    // Move on and see if there are other matches. (The delimitation
591
0
    // requirement makes it pointless to begin the next search before
592
0
    // the end of the invalid match just found.)
593
0
    startiter = enditer;
594
0
  }
595
0
596
0
  return false;
597
0
}
598
599
// static
600
PopupControlState
601
Event::GetEventPopupControlState(WidgetEvent* aEvent, Event* aDOMEvent)
602
0
{
603
0
  // generally if an event handler is running, new windows are disallowed.
604
0
  // check for exceptions:
605
0
  PopupControlState abuse = openAbused;
606
0
607
0
  if (aDOMEvent && aDOMEvent->GetWantsPopupControlCheck()) {
608
0
    nsAutoString type;
609
0
    aDOMEvent->GetType(type);
610
0
    if (PopupAllowedForEvent(NS_ConvertUTF16toUTF8(type).get())) {
611
0
      return openAllowed;
612
0
    }
613
0
  }
614
0
615
0
  switch(aEvent->mClass) {
616
0
  case eBasicEventClass:
617
0
    // For these following events only allow popups if they're
618
0
    // triggered while handling user input. See
619
0
    // nsPresShell::HandleEventInternal() for details.
620
0
    if (EventStateManager::IsHandlingUserInput()) {
621
0
      abuse = openBlocked;
622
0
      switch(aEvent->mMessage) {
623
0
      case eFormSelect:
624
0
        if (PopupAllowedForEvent("select")) {
625
0
          abuse = openControlled;
626
0
        }
627
0
        break;
628
0
      case eFormChange:
629
0
        if (PopupAllowedForEvent("change")) {
630
0
          abuse = openControlled;
631
0
        }
632
0
        break;
633
0
      default:
634
0
        break;
635
0
      }
636
0
    }
637
0
    break;
638
0
  case eEditorInputEventClass:
639
0
    // For this following event only allow popups if it's triggered
640
0
    // while handling user input. See
641
0
    // nsPresShell::HandleEventInternal() for details.
642
0
    if (EventStateManager::IsHandlingUserInput()) {
643
0
      abuse = openBlocked;
644
0
      switch(aEvent->mMessage) {
645
0
      case eEditorInput:
646
0
        if (PopupAllowedForEvent("input")) {
647
0
          abuse = openControlled;
648
0
        }
649
0
        break;
650
0
      default:
651
0
        break;
652
0
      }
653
0
    }
654
0
    break;
655
0
  case eInputEventClass:
656
0
    // For this following event only allow popups if it's triggered
657
0
    // while handling user input. See
658
0
    // nsPresShell::HandleEventInternal() for details.
659
0
    if (EventStateManager::IsHandlingUserInput()) {
660
0
      abuse = openBlocked;
661
0
      switch(aEvent->mMessage) {
662
0
      case eFormChange:
663
0
        if (PopupAllowedForEvent("change")) {
664
0
          abuse = openControlled;
665
0
        }
666
0
        break;
667
0
      case eXULCommand:
668
0
        abuse = openControlled;
669
0
        break;
670
0
      default:
671
0
        break;
672
0
      }
673
0
    }
674
0
    break;
675
0
  case eKeyboardEventClass:
676
0
    if (aEvent->IsTrusted()) {
677
0
      abuse = openBlocked;
678
0
      uint32_t key = aEvent->AsKeyboardEvent()->mKeyCode;
679
0
      switch(aEvent->mMessage) {
680
0
      case eKeyPress:
681
0
        // return key on focused button. see note at eMouseClick.
682
0
        if (key == NS_VK_RETURN) {
683
0
          abuse = openAllowed;
684
0
        } else if (PopupAllowedForEvent("keypress")) {
685
0
          abuse = openControlled;
686
0
        }
687
0
        break;
688
0
      case eKeyUp:
689
0
        // space key on focused button. see note at eMouseClick.
690
0
        if (key == NS_VK_SPACE) {
691
0
          abuse = openAllowed;
692
0
        } else if (PopupAllowedForEvent("keyup")) {
693
0
          abuse = openControlled;
694
0
        }
695
0
        break;
696
0
      case eKeyDown:
697
0
        if (PopupAllowedForEvent("keydown")) {
698
0
          abuse = openControlled;
699
0
        }
700
0
        break;
701
0
      default:
702
0
        break;
703
0
      }
704
0
    }
705
0
    break;
706
0
  case eTouchEventClass:
707
0
    if (aEvent->IsTrusted()) {
708
0
      abuse = openBlocked;
709
0
      switch (aEvent->mMessage) {
710
0
      case eTouchStart:
711
0
        if (PopupAllowedForEvent("touchstart")) {
712
0
          abuse = openControlled;
713
0
        }
714
0
        break;
715
0
      case eTouchEnd:
716
0
        if (PopupAllowedForEvent("touchend")) {
717
0
          abuse = openControlled;
718
0
        }
719
0
        break;
720
0
      default:
721
0
        break;
722
0
      }
723
0
    }
724
0
    break;
725
0
  case eMouseEventClass:
726
0
    if (aEvent->IsTrusted() &&
727
0
        aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
728
0
      abuse = openBlocked;
729
0
      switch(aEvent->mMessage) {
730
0
      case eMouseUp:
731
0
        if (PopupAllowedForEvent("mouseup")) {
732
0
          abuse = openControlled;
733
0
        }
734
0
        break;
735
0
      case eMouseDown:
736
0
        if (PopupAllowedForEvent("mousedown")) {
737
0
          abuse = openControlled;
738
0
        }
739
0
        break;
740
0
      case eMouseClick:
741
0
        /* Click events get special treatment because of their
742
0
           historical status as a more legitimate event handler. If
743
0
           click popups are enabled in the prefs, clear the popup
744
0
           status completely. */
745
0
        if (PopupAllowedForEvent("click")) {
746
0
          abuse = openAllowed;
747
0
        }
748
0
        break;
749
0
      case eMouseDoubleClick:
750
0
        if (PopupAllowedForEvent("dblclick")) {
751
0
          abuse = openControlled;
752
0
        }
753
0
        break;
754
0
      default:
755
0
        break;
756
0
      }
757
0
    }
758
0
    break;
759
0
  case ePointerEventClass:
760
0
    if (aEvent->IsTrusted() &&
761
0
        aEvent->AsPointerEvent()->button == WidgetMouseEvent::eLeftButton) {
762
0
      switch(aEvent->mMessage) {
763
0
      case ePointerUp:
764
0
        if (PopupAllowedForEvent("pointerup")) {
765
0
          abuse = openControlled;
766
0
        }
767
0
        break;
768
0
      case ePointerDown:
769
0
        if (PopupAllowedForEvent("pointerdown")) {
770
0
          abuse = openControlled;
771
0
        }
772
0
        break;
773
0
      default:
774
0
        break;
775
0
      }
776
0
    }
777
0
    break;
778
0
  case eFormEventClass:
779
0
    // For these following events only allow popups if they're
780
0
    // triggered while handling user input. See
781
0
    // nsPresShell::HandleEventInternal() for details.
782
0
    if (EventStateManager::IsHandlingUserInput()) {
783
0
      abuse = openBlocked;
784
0
      switch(aEvent->mMessage) {
785
0
      case eFormSubmit:
786
0
        if (PopupAllowedForEvent("submit")) {
787
0
          abuse = openControlled;
788
0
        }
789
0
        break;
790
0
      case eFormReset:
791
0
        if (PopupAllowedForEvent("reset")) {
792
0
          abuse = openControlled;
793
0
        }
794
0
        break;
795
0
      default:
796
0
        break;
797
0
      }
798
0
    }
799
0
    break;
800
0
  default:
801
0
    break;
802
0
  }
803
0
804
0
  return abuse;
805
0
}
806
807
// static
808
void
809
Event::PopupAllowedEventsChanged()
810
0
{
811
0
  if (sPopupAllowedEvents) {
812
0
    free(sPopupAllowedEvents);
813
0
  }
814
0
815
0
  nsAutoCString str;
816
0
  Preferences::GetCString("dom.popup_allowed_events", str);
817
0
818
0
  // We'll want to do this even if str is empty to avoid looking up
819
0
  // this pref all the time if it's not set.
820
0
  sPopupAllowedEvents = ToNewCString(str);
821
0
}
822
823
// static
824
void
825
Event::Shutdown()
826
0
{
827
0
  if (sPopupAllowedEvents) {
828
0
    free(sPopupAllowedEvents);
829
0
  }
830
0
}
831
832
// static
833
CSSIntPoint
834
Event::GetScreenCoords(nsPresContext* aPresContext,
835
                       WidgetEvent* aEvent,
836
                       LayoutDeviceIntPoint aPoint)
837
0
{
838
0
  if (EventStateManager::sIsPointerLocked) {
839
0
    return EventStateManager::sLastScreenPoint;
840
0
  }
841
0
842
0
  if (!aEvent ||
843
0
       (aEvent->mClass != eMouseEventClass &&
844
0
        aEvent->mClass != eMouseScrollEventClass &&
845
0
        aEvent->mClass != eWheelEventClass &&
846
0
        aEvent->mClass != ePointerEventClass &&
847
0
        aEvent->mClass != eTouchEventClass &&
848
0
        aEvent->mClass != eDragEventClass &&
849
0
        aEvent->mClass != eSimpleGestureEventClass)) {
850
0
    return CSSIntPoint(0, 0);
851
0
  }
852
0
853
0
  // Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
854
0
  // seem incorrect, but it is needed to maintain legacy functionality.
855
0
  WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
856
0
  if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
857
0
    return CSSIntPoint(aPoint.x, aPoint.y);
858
0
  }
859
0
860
0
  nsPoint pt =
861
0
    LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
862
0
863
0
  if (nsIPresShell* ps = aPresContext->GetPresShell()) {
864
0
    pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));
865
0
  }
866
0
867
0
  pt += LayoutDevicePixel::ToAppUnits(guiEvent->mWidget->WidgetToScreenOffset(),
868
0
                                      aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
869
0
870
0
  return CSSPixel::FromAppUnitsRounded(pt);
871
0
}
872
873
// static
874
CSSIntPoint
875
Event::GetPageCoords(nsPresContext* aPresContext,
876
                     WidgetEvent* aEvent,
877
                     LayoutDeviceIntPoint aPoint,
878
                     CSSIntPoint aDefaultPoint)
879
0
{
880
0
  CSSIntPoint pagePoint =
881
0
    Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
882
0
883
0
  // If there is some scrolling, add scroll info to client point.
884
0
  if (aPresContext && aPresContext->GetPresShell()) {
885
0
    nsIPresShell* shell = aPresContext->GetPresShell();
886
0
    nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
887
0
    if (scrollframe) {
888
0
      pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
889
0
    }
890
0
  }
891
0
892
0
  return pagePoint;
893
0
}
894
895
// static
896
CSSIntPoint
897
Event::GetClientCoords(nsPresContext* aPresContext,
898
                       WidgetEvent* aEvent,
899
                       LayoutDeviceIntPoint aPoint,
900
                       CSSIntPoint aDefaultPoint)
901
0
{
902
0
  if (EventStateManager::sIsPointerLocked) {
903
0
    return EventStateManager::sLastClientPoint;
904
0
  }
905
0
906
0
  if (!aEvent ||
907
0
      (aEvent->mClass != eMouseEventClass &&
908
0
       aEvent->mClass != eMouseScrollEventClass &&
909
0
       aEvent->mClass != eWheelEventClass &&
910
0
       aEvent->mClass != eTouchEventClass &&
911
0
       aEvent->mClass != eDragEventClass &&
912
0
       aEvent->mClass != ePointerEventClass &&
913
0
       aEvent->mClass != eSimpleGestureEventClass) ||
914
0
      !aPresContext ||
915
0
      !aEvent->AsGUIEvent()->mWidget) {
916
0
    return aDefaultPoint;
917
0
  }
918
0
919
0
  nsIPresShell* shell = aPresContext->GetPresShell();
920
0
  if (!shell) {
921
0
    return CSSIntPoint(0, 0);
922
0
  }
923
0
  nsIFrame* rootFrame = shell->GetRootFrame();
924
0
  if (!rootFrame) {
925
0
    return CSSIntPoint(0, 0);
926
0
  }
927
0
  nsPoint pt =
928
0
    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
929
0
930
0
  return CSSIntPoint::FromAppUnitsRounded(pt);
931
0
}
932
933
// static
934
CSSIntPoint
935
Event::GetOffsetCoords(nsPresContext* aPresContext,
936
                       WidgetEvent* aEvent,
937
                       LayoutDeviceIntPoint aPoint,
938
                       CSSIntPoint aDefaultPoint)
939
0
{
940
0
  if (!aEvent->mTarget) {
941
0
    return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
942
0
  }
943
0
  nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->mTarget);
944
0
  if (!content || !aPresContext) {
945
0
    return CSSIntPoint(0, 0);
946
0
  }
947
0
  nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
948
0
  if (!shell) {
949
0
    return CSSIntPoint(0, 0);
950
0
  }
951
0
  shell->FlushPendingNotifications(FlushType::Layout);
952
0
  nsIFrame* frame = content->GetPrimaryFrame();
953
0
  if (!frame) {
954
0
    return CSSIntPoint(0, 0);
955
0
  }
956
0
  nsIFrame* rootFrame = shell->GetRootFrame();
957
0
  if (!rootFrame) {
958
0
    return CSSIntPoint(0, 0);
959
0
  }
960
0
  CSSIntPoint clientCoords =
961
0
    GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
962
0
  nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
963
0
  if (nsLayoutUtils::TransformPoint(rootFrame, frame, pt) ==
964
0
      nsLayoutUtils::TRANSFORM_SUCCEEDED) {
965
0
    pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
966
0
    return CSSPixel::FromAppUnitsRounded(pt);
967
0
  }
968
0
  return CSSIntPoint(0, 0);
969
0
}
970
971
// To be called ONLY by Event::GetType (which has the additional
972
// logic for handling user-defined events).
973
// static
974
const char*
975
Event::GetEventName(EventMessage aEventType)
976
0
{
977
0
  switch(aEventType) {
978
0
#define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
979
0
  case _message: return #name_;
980
0
#include "mozilla/EventNameList.h"
981
0
#undef MESSAGE_TO_EVENT
982
0
  default:
983
0
    break;
984
0
  }
985
0
  // XXXldb We can hit this case for WidgetEvent objects that we didn't
986
0
  // create and that are not user defined events since this function and
987
0
  // SetEventType are incomplete.  (But fixing that requires fixing the
988
0
  // arrays in nsEventListenerManager too, since the events for which
989
0
  // this is a problem generally *are* created by Event.)
990
0
  return nullptr;
991
0
}
992
993
bool
994
Event::DefaultPrevented(CallerType aCallerType) const
995
0
{
996
0
  NS_ENSURE_TRUE(mEvent, false);
997
0
998
0
  // If preventDefault() has never been called, just return false.
999
0
  if (!mEvent->DefaultPrevented()) {
1000
0
    return false;
1001
0
  }
1002
0
1003
0
  // If preventDefault() has been called by content, return true.  Otherwise,
1004
0
  // i.e., preventDefault() has been called by chrome, return true only when
1005
0
  // this is called by chrome.
1006
0
  return mEvent->DefaultPreventedByContent() ||
1007
0
         aCallerType == CallerType::System;
1008
0
}
1009
1010
bool
1011
Event::ReturnValue(CallerType aCallerType) const
1012
0
{
1013
0
  return !DefaultPrevented(aCallerType);
1014
0
}
1015
1016
void
1017
Event::SetReturnValue(bool aReturnValue, CallerType aCallerType)
1018
0
{
1019
0
  if (!aReturnValue) {
1020
0
    PreventDefaultInternal(aCallerType == CallerType::System);
1021
0
  }
1022
0
}
1023
1024
double
1025
Event::TimeStamp()
1026
0
{
1027
0
  if (!sReturnHighResTimeStamp) {
1028
0
    // In the situation where you have set a very old, not-very-supported
1029
0
    // non-default preference, we will always reduce the precision,
1030
0
    // regardless of system principal or not.
1031
0
    // The timestamp is absolute, so we supply a zero context mix-in.
1032
0
    double ret = static_cast<double>(mEvent->mTime);
1033
0
    return nsRFPService::ReduceTimePrecisionAsMSecs(ret, 0);
1034
0
  }
1035
0
1036
0
  if (mEvent->mTimeStamp.IsNull()) {
1037
0
    return 0.0;
1038
0
  }
1039
0
1040
0
  if (mIsMainThreadEvent) {
1041
0
    if (NS_WARN_IF(!mOwner)) {
1042
0
      return 0.0;
1043
0
    }
1044
0
1045
0
    nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mOwner);
1046
0
    if (NS_WARN_IF(!win)) {
1047
0
      return 0.0;
1048
0
    }
1049
0
1050
0
    Performance* perf = win->GetPerformance();
1051
0
    if (NS_WARN_IF(!perf)) {
1052
0
      return 0.0;
1053
0
    }
1054
0
1055
0
    double ret = perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
1056
0
    MOZ_ASSERT(mOwner->PrincipalOrNull());
1057
0
    if (nsContentUtils::IsSystemPrincipal(mOwner->PrincipalOrNull()))
1058
0
      return ret;
1059
0
1060
0
    return nsRFPService::ReduceTimePrecisionAsMSecs(ret,
1061
0
      perf->GetRandomTimelineSeed());
1062
0
  }
1063
0
1064
0
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
1065
0
  MOZ_ASSERT(workerPrivate);
1066
0
1067
0
  double ret = workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
1068
0
  if (workerPrivate->UsesSystemPrincipal())
1069
0
    return ret;
1070
0
1071
0
  return nsRFPService::ReduceTimePrecisionAsMSecs(ret,
1072
0
    workerPrivate->GetRandomTimelineSeed());
1073
0
}
1074
1075
void
1076
Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
1077
0
{
1078
0
  if (aSerializeInterfaceType) {
1079
0
    IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
1080
0
  }
1081
0
1082
0
  nsString type;
1083
0
  GetType(type);
1084
0
  IPC::WriteParam(aMsg, type);
1085
0
1086
0
  IPC::WriteParam(aMsg, Bubbles());
1087
0
  IPC::WriteParam(aMsg, Cancelable());
1088
0
  IPC::WriteParam(aMsg, IsTrusted());
1089
0
  IPC::WriteParam(aMsg, Composed());
1090
0
1091
0
  // No timestamp serialization for now!
1092
0
}
1093
1094
bool
1095
Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
1096
0
{
1097
0
  nsString type;
1098
0
  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
1099
0
1100
0
  bool bubbles = false;
1101
0
  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
1102
0
1103
0
  bool cancelable = false;
1104
0
  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
1105
0
1106
0
  bool trusted = false;
1107
0
  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
1108
0
1109
0
  bool composed = false;
1110
0
  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &composed), false);
1111
0
1112
0
  InitEvent(type, bubbles, cancelable);
1113
0
  SetTrusted(trusted);
1114
0
  SetComposed(composed);
1115
0
1116
0
  return true;
1117
0
}
1118
1119
void
1120
Event::SetOwner(EventTarget* aOwner)
1121
0
{
1122
0
  mOwner = nullptr;
1123
0
1124
0
  if (!aOwner) {
1125
0
    return;
1126
0
  }
1127
0
1128
0
  nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
1129
0
  if (n) {
1130
0
    mOwner = n->OwnerDoc()->GetScopeObject();
1131
0
    return;
1132
0
  }
1133
0
1134
0
  nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(aOwner);
1135
0
  if (w) {
1136
0
    mOwner = do_QueryInterface(w);
1137
0
    return;
1138
0
  }
1139
0
1140
0
  nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
1141
0
  if (eth) {
1142
0
    mOwner = eth->GetParentObject();
1143
0
    return;
1144
0
  }
1145
0
1146
#ifdef DEBUG
1147
  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
1148
  MOZ_ASSERT(root, "Unexpected EventTarget!");
1149
#endif
1150
}
1151
1152
void
1153
Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType)
1154
0
{
1155
0
  if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
1156
0
    aType = aEvent->mSpecifiedEventTypeString;
1157
0
    return;
1158
0
  }
1159
0
1160
0
  const char* name = GetEventName(aEvent->mMessage);
1161
0
1162
0
  if (name) {
1163
0
    CopyASCIItoUTF16(mozilla::MakeStringSpan(name), aType);
1164
0
    return;
1165
0
  } else if (aEvent->mMessage == eUnidentifiedEvent &&
1166
0
             aEvent->mSpecifiedEventType) {
1167
0
    // Remove "on"
1168
0
    aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
1169
0
    aEvent->mSpecifiedEventTypeString = aType;
1170
0
    return;
1171
0
  }
1172
0
1173
0
  aType.Truncate();
1174
0
}
1175
1176
} // namespace dom
1177
} // namespace mozilla
1178
1179
using namespace mozilla;
1180
using namespace mozilla::dom;
1181
1182
already_AddRefed<Event>
1183
NS_NewDOMEvent(EventTarget* aOwner,
1184
               nsPresContext* aPresContext,
1185
               WidgetEvent* aEvent)
1186
0
{
1187
0
  RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
1188
0
  return it.forget();
1189
0
}