Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/events/PointerEventHandler.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 "PointerEventHandler.h"
8
#include "nsIFrame.h"
9
#include "PointerEvent.h"
10
#include "mozilla/PresShell.h"
11
#include "mozilla/dom/MouseEventBinding.h"
12
13
namespace mozilla {
14
15
using namespace dom;
16
17
static bool sPointerEventEnabled = true;
18
static bool sPointerEventImplicitCapture = false;
19
20
class PointerInfo final
21
{
22
public:
23
  uint16_t mPointerType;
24
  bool mActiveState;
25
  bool mPrimaryState;
26
  bool mPreventMouseEventByContent;
27
  explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
28
                       bool aPrimaryState)
29
    : mPointerType(aPointerType)
30
    , mActiveState(aActiveState)
31
    , mPrimaryState(aPrimaryState)
32
    , mPreventMouseEventByContent(false)
33
0
  {
34
0
  }
35
};
36
37
// Keeps a map between pointerId and element that currently capturing pointer
38
// with such pointerId. If pointerId is absent in this map then nobody is
39
// capturing it. Additionally keep information about pending capturing content.
40
static nsClassHashtable<nsUint32HashKey,
41
                        PointerCaptureInfo>* sPointerCaptureList;
42
43
// Keeps information about pointers such as pointerId, activeState, pointerType,
44
// primaryState
45
static nsClassHashtable<nsUint32HashKey, PointerInfo>* sActivePointersIds;
46
47
/* static */ void
48
PointerEventHandler::Initialize()
49
0
{
50
0
  static bool initialized = false;
51
0
  if (initialized) {
52
0
    return;
53
0
  }
54
0
  initialized = true;
55
0
  Preferences::AddBoolVarCache(&sPointerEventEnabled,
56
0
                               "dom.w3c_pointer_events.enabled", true);
57
0
  Preferences::AddBoolVarCache(&sPointerEventImplicitCapture,
58
0
                               "dom.w3c_pointer_events.implicit_capture", true);
59
0
}
60
61
/* static */ void
62
PointerEventHandler::InitializeStatics()
63
3
{
64
3
  MOZ_ASSERT(!sPointerCaptureList, "InitializeStatics called multiple times!");
65
3
  sPointerCaptureList =
66
3
    new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
67
3
  sActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
68
3
}
69
70
/* static */ void
71
PointerEventHandler::ReleaseStatics()
72
0
{
73
0
  MOZ_ASSERT(sPointerCaptureList, "ReleaseStatics called without Initialize!");
74
0
  delete sPointerCaptureList;
75
0
  sPointerCaptureList = nullptr;
76
0
  delete sActivePointersIds;
77
0
  sActivePointersIds = nullptr;
78
0
}
79
80
/* static */ bool
81
PointerEventHandler::IsPointerEventEnabled()
82
0
{
83
0
  return sPointerEventEnabled;
84
0
}
85
86
/* static */ bool
87
PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled()
88
0
{
89
0
  return sPointerEventEnabled && sPointerEventImplicitCapture;
90
0
}
91
92
/* static */ void
93
PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent)
94
0
{
95
0
  if (!IsPointerEventEnabled() || !aEvent) {
96
0
    return;
97
0
  }
98
0
  switch (aEvent->mMessage) {
99
0
  case eMouseEnterIntoWidget:
100
0
    // In this case we have to know information about available mouse pointers
101
0
    sActivePointersIds->Put(aEvent->pointerId,
102
0
                            new PointerInfo(false, aEvent->inputSource, true));
103
0
    break;
104
0
  case ePointerDown:
105
0
    // In this case we switch pointer to active state
106
0
    if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
107
0
      sActivePointersIds->Put(pointerEvent->pointerId,
108
0
                              new PointerInfo(true, pointerEvent->inputSource,
109
0
                                              pointerEvent->mIsPrimary));
110
0
    }
111
0
    break;
112
0
  case ePointerCancel:
113
0
    // pointercancel means a pointer is unlikely to continue to produce pointer
114
0
    // events. In that case, we should turn off active state or remove the
115
0
    // pointer from active pointers.
116
0
  case ePointerUp:
117
0
    // In this case we remove information about pointer or turn off active state
118
0
    if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
119
0
      if(pointerEvent->inputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
120
0
        sActivePointersIds->Put(pointerEvent->pointerId,
121
0
                                new PointerInfo(false,
122
0
                                                pointerEvent->inputSource,
123
0
                                                pointerEvent->mIsPrimary));
124
0
      } else {
125
0
        sActivePointersIds->Remove(pointerEvent->pointerId);
126
0
      }
127
0
    }
128
0
    break;
129
0
  case eMouseExitFromWidget:
130
0
    // In this case we have to remove information about disappeared mouse
131
0
    // pointers
132
0
    sActivePointersIds->Remove(aEvent->pointerId);
133
0
    break;
134
0
  default:
135
0
    break;
136
0
  }
137
0
}
138
139
/* static */ void
140
PointerEventHandler::SetPointerCaptureById(uint32_t aPointerId,
141
                                           nsIContent* aContent)
142
0
{
143
0
  MOZ_ASSERT(aContent);
144
0
  if (MouseEvent_Binding::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
145
0
    nsIPresShell::SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
146
0
  }
147
0
148
0
  PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
149
0
  if (pointerCaptureInfo) {
150
0
    pointerCaptureInfo->mPendingContent = aContent;
151
0
  } else {
152
0
    sPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
153
0
  }
154
0
}
155
156
/* static */ PointerCaptureInfo*
157
PointerEventHandler::GetPointerCaptureInfo(uint32_t aPointerId)
158
0
{
159
0
  PointerCaptureInfo* pointerCaptureInfo = nullptr;
160
0
  sPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
161
0
  return pointerCaptureInfo;
162
0
}
163
164
/* static */ void
165
PointerEventHandler::ReleasePointerCaptureById(uint32_t aPointerId)
166
0
{
167
0
  PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
168
0
  if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
169
0
    if (MouseEvent_Binding::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
170
0
      nsIPresShell::SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
171
0
    }
172
0
    pointerCaptureInfo->mPendingContent = nullptr;
173
0
  }
174
0
}
175
176
/* static */ void
177
PointerEventHandler::ReleaseAllPointerCapture()
178
0
{
179
0
  for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
180
0
    PointerCaptureInfo* data = iter.UserData();
181
0
    if (data && data->mPendingContent) {
182
0
      ReleasePointerCaptureById(iter.Key());
183
0
    }
184
0
  }
185
0
}
186
187
/* static */ bool
188
PointerEventHandler::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
189
0
{
190
0
  PointerInfo* pointerInfo = nullptr;
191
0
  if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
192
0
    aActiveState = pointerInfo->mActiveState;
193
0
    return true;
194
0
  }
195
0
  return false;
196
0
}
197
198
/* static */ void
199
PointerEventHandler::MaybeProcessPointerCapture(WidgetGUIEvent* aEvent)
200
{
201
  switch (aEvent->mClass) {
202
  case eMouseEventClass:
203
    ProcessPointerCaptureForMouse(aEvent->AsMouseEvent());
204
    break;
205
  case eTouchEventClass:
206
    ProcessPointerCaptureForTouch(aEvent->AsTouchEvent());
207
    break;
208
  default:
209
    break;
210
  }
211
}
212
213
/* static */ void
214
PointerEventHandler::ProcessPointerCaptureForMouse(WidgetMouseEvent* aEvent)
215
0
{
216
0
  if (!ShouldGeneratePointerEventFromMouse(aEvent)) {
217
0
    return;
218
0
  }
219
0
220
0
  PointerCaptureInfo* info = GetPointerCaptureInfo(aEvent->pointerId);
221
0
  if (!info || info->mPendingContent == info->mOverrideContent) {
222
0
    return;
223
0
  }
224
0
  WidgetPointerEvent localEvent(*aEvent);
225
0
  InitPointerEventFromMouse(&localEvent, aEvent, eVoidEvent);
226
0
  CheckPointerCaptureState(&localEvent);
227
0
}
228
229
/* static */ void
230
PointerEventHandler::ProcessPointerCaptureForTouch(WidgetTouchEvent* aEvent)
231
0
{
232
0
  if (!ShouldGeneratePointerEventFromTouch(aEvent)) {
233
0
    return;
234
0
  }
235
0
236
0
  for (uint32_t i = 0; i < aEvent->mTouches.Length(); ++i) {
237
0
    Touch* touch = aEvent->mTouches[i];
238
0
    if (!TouchManager::ShouldConvertTouchToPointer(touch, aEvent)) {
239
0
      continue;
240
0
    }
241
0
    PointerCaptureInfo* info = GetPointerCaptureInfo(touch->Identifier());
242
0
    if (!info || info->mPendingContent == info->mOverrideContent) {
243
0
      continue;
244
0
    }
245
0
    WidgetPointerEvent event(aEvent->IsTrusted(), eVoidEvent, aEvent->mWidget);
246
0
    InitPointerEventFromTouch(&event, aEvent, touch, i == 0);
247
0
    CheckPointerCaptureState(&event);
248
0
  }
249
0
}
250
251
/* static */ void
252
PointerEventHandler::CheckPointerCaptureState(WidgetPointerEvent* aEvent)
253
0
{
254
0
  // Handle pending pointer capture before any pointer events except
255
0
  // gotpointercapture / lostpointercapture.
256
0
  if (!aEvent) {
257
0
    return;
258
0
  }
259
0
  MOZ_ASSERT(IsPointerEventEnabled());
260
0
  MOZ_ASSERT(aEvent->mClass == ePointerEventClass);
261
0
262
0
  PointerCaptureInfo* captureInfo = GetPointerCaptureInfo(aEvent->pointerId);
263
0
264
0
  if (!captureInfo ||
265
0
      captureInfo->mPendingContent == captureInfo->mOverrideContent) {
266
0
    return;
267
0
  }
268
0
  // cache captureInfo->mPendingContent since it may be changed in the pointer
269
0
  // event listener
270
0
  nsIContent* pendingContent = captureInfo->mPendingContent.get();
271
0
  if (captureInfo->mOverrideContent) {
272
0
    DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false, aEvent,
273
0
                                         captureInfo->mOverrideContent);
274
0
  }
275
0
  if (pendingContent) {
276
0
    DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aEvent,
277
0
                                         pendingContent);
278
0
  }
279
0
280
0
  captureInfo->mOverrideContent = pendingContent;
281
0
  if (captureInfo->Empty()) {
282
0
    sPointerCaptureList->Remove(aEvent->pointerId);
283
0
  }
284
0
}
285
286
/* static */ void
287
PointerEventHandler::ImplicitlyCapturePointer(nsIFrame* aFrame,
288
                                              WidgetEvent* aEvent)
289
0
{
290
0
  MOZ_ASSERT(aEvent->mMessage == ePointerDown);
291
0
  if (!aFrame || !IsPointerEventEnabled() ||
292
0
      !IsPointerEventImplicitCaptureForTouchEnabled()) {
293
0
    return;
294
0
  }
295
0
  WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
296
0
  NS_WARNING_ASSERTION(pointerEvent,
297
0
                       "Call ImplicitlyCapturePointer with non-pointer event");
298
0
  if (pointerEvent->inputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
299
0
    // We only implicitly capture the pointer for touch device.
300
0
    return;
301
0
  }
302
0
  nsCOMPtr<nsIContent> target;
303
0
  aFrame->GetContentForEvent(aEvent, getter_AddRefs(target));
304
0
  while (target && !target->IsElement()) {
305
0
    target = target->GetParent();
306
0
  }
307
0
  if (NS_WARN_IF(!target)) {
308
0
    return;
309
0
  }
310
0
  SetPointerCaptureById(pointerEvent->pointerId, target);
311
0
}
312
313
/* static */ void
314
PointerEventHandler::ImplicitlyReleasePointerCapture(WidgetEvent* aEvent)
315
0
{
316
0
  MOZ_ASSERT(aEvent);
317
0
  if (aEvent->mMessage != ePointerUp && aEvent->mMessage != ePointerCancel) {
318
0
    return;
319
0
  }
320
0
  WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
321
0
  ReleasePointerCaptureById(pointerEvent->pointerId);
322
0
  CheckPointerCaptureState(pointerEvent);
323
0
}
324
325
/* static */ nsIContent*
326
PointerEventHandler::GetPointerCapturingContent(uint32_t aPointerId)
327
0
{
328
0
  PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
329
0
  if (pointerCaptureInfo) {
330
0
    return pointerCaptureInfo->mOverrideContent;
331
0
  }
332
0
  return nullptr;
333
0
}
334
335
/* static */ nsIContent*
336
PointerEventHandler::GetPointerCapturingContent(WidgetGUIEvent* aEvent)
337
0
{
338
0
  if (!IsPointerEventEnabled() || (aEvent->mClass != ePointerEventClass &&
339
0
                                   aEvent->mClass != eMouseEventClass) ||
340
0
      aEvent->mMessage == ePointerDown || aEvent->mMessage == eMouseDown) {
341
0
    // Pointer capture should only be applied to all pointer events and mouse
342
0
    // events except ePointerDown and eMouseDown;
343
0
    return nullptr;
344
0
  }
345
0
346
0
  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
347
0
  if (!mouseEvent) {
348
0
    return nullptr;
349
0
  }
350
0
  return GetPointerCapturingContent(mouseEvent->pointerId);
351
0
}
352
353
/* static */ void
354
PointerEventHandler::ReleaseIfCaptureByDescendant(nsIContent* aContent)
355
0
{
356
0
  // We should check that aChild does not contain pointer capturing elements.
357
0
  // If it does we should release the pointer capture for the elements.
358
0
  for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
359
0
    PointerCaptureInfo* data = iter.UserData();
360
0
    if (data && data->mPendingContent &&
361
0
        nsContentUtils::ContentIsDescendantOf(data->mPendingContent,
362
0
                                              aContent)) {
363
0
      ReleasePointerCaptureById(iter.Key());
364
0
    }
365
0
  }
366
0
}
367
368
/* static */ void
369
PointerEventHandler::PreHandlePointerEventsPreventDefault(
370
                       WidgetPointerEvent* aPointerEvent,
371
                       WidgetGUIEvent* aMouseOrTouchEvent)
372
0
{
373
0
  if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
374
0
    return;
375
0
  }
376
0
  PointerInfo* pointerInfo = nullptr;
377
0
  if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
378
0
      !pointerInfo) {
379
0
    // The PointerInfo for active pointer should be added for normal cases. But
380
0
    // in some cases, we may receive mouse events before adding PointerInfo in
381
0
    // sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
382
0
    // or change preference 'dom.w3c_pointer_events.enabled' from off to on).
383
0
    // In these cases, we could ignore them because they are not the events
384
0
    // between a DefaultPrevented pointerdown and the corresponding pointerup.
385
0
    return;
386
0
  }
387
0
  if (!pointerInfo->mPreventMouseEventByContent) {
388
0
    return;
389
0
  }
390
0
  aMouseOrTouchEvent->PreventDefault(false);
391
0
  aMouseOrTouchEvent->mFlags.mOnlyChromeDispatch = true;
392
0
  if (aPointerEvent->mMessage == ePointerUp) {
393
0
    pointerInfo->mPreventMouseEventByContent = false;
394
0
  }
395
0
}
396
397
/* static */ void
398
PointerEventHandler::PostHandlePointerEventsPreventDefault(
399
                       WidgetPointerEvent* aPointerEvent,
400
                       WidgetGUIEvent* aMouseOrTouchEvent)
401
0
{
402
0
  if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
403
0
      !aPointerEvent->DefaultPreventedByContent()) {
404
0
    return;
405
0
  }
406
0
  PointerInfo* pointerInfo = nullptr;
407
0
  if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
408
0
      !pointerInfo) {
409
0
    // We already added the PointerInfo for active pointer when
410
0
    // PresShell::HandleEvent handling pointerdown event.
411
#ifdef DEBUG
412
    MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
413
#endif // #ifdef DEBUG
414
    return;
415
0
  }
416
0
  // PreventDefault only applied for active pointers.
417
0
  if (!pointerInfo->mActiveState) {
418
0
    return;
419
0
  }
420
0
  aMouseOrTouchEvent->PreventDefault(false);
421
0
  aMouseOrTouchEvent->mFlags.mOnlyChromeDispatch = true;
422
0
  pointerInfo->mPreventMouseEventByContent = true;
423
0
}
424
425
/* static */ void
426
PointerEventHandler::InitPointerEventFromMouse(
427
                       WidgetPointerEvent* aPointerEvent,
428
                       WidgetMouseEvent* aMouseEvent,
429
                       EventMessage aMessage)
430
0
{
431
0
  MOZ_ASSERT(aPointerEvent);
432
0
  MOZ_ASSERT(aMouseEvent);
433
0
  aPointerEvent->pointerId = aMouseEvent->pointerId;
434
0
  aPointerEvent->inputSource = aMouseEvent->inputSource;
435
0
  aPointerEvent->mMessage = aMessage;
436
0
  aPointerEvent->button = aMouseEvent->mMessage == eMouseMove ?
437
0
                            WidgetMouseEvent::eNoButton : aMouseEvent->button;
438
0
439
0
  aPointerEvent->buttons = aMouseEvent->buttons;
440
0
  aPointerEvent->pressure = aPointerEvent->buttons ?
441
0
                              aMouseEvent->pressure ?
442
0
                                aMouseEvent->pressure : 0.5f :
443
0
                              0.0f;
444
0
}
445
446
/* static */ void
447
PointerEventHandler::InitPointerEventFromTouch(
448
                       WidgetPointerEvent* aPointerEvent,
449
                       WidgetTouchEvent* aTouchEvent,
450
                       mozilla::dom::Touch* aTouch,
451
                       bool aIsPrimary)
452
0
{
453
0
  MOZ_ASSERT(aPointerEvent);
454
0
  MOZ_ASSERT(aTouchEvent);
455
0
456
0
  int16_t button = aTouchEvent->mMessage == eTouchMove ?
457
0
                     WidgetMouseEvent::eNoButton :
458
0
                     WidgetMouseEvent::eLeftButton;
459
0
460
0
  int16_t buttons = aTouchEvent->mMessage == eTouchEnd ?
461
0
                      WidgetMouseEvent::eNoButtonFlag :
462
0
                      WidgetMouseEvent::eLeftButtonFlag;
463
0
464
0
  aPointerEvent->mIsPrimary = aIsPrimary;
465
0
  aPointerEvent->pointerId = aTouch->Identifier();
466
0
  aPointerEvent->mRefPoint = aTouch->mRefPoint;
467
0
  aPointerEvent->mModifiers = aTouchEvent->mModifiers;
468
0
  aPointerEvent->mWidth = aTouch->RadiusX(CallerType::System);
469
0
  aPointerEvent->mHeight = aTouch->RadiusY(CallerType::System);
470
0
  aPointerEvent->tiltX = aTouch->tiltX;
471
0
  aPointerEvent->tiltY = aTouch->tiltY;
472
0
  aPointerEvent->mTime = aTouchEvent->mTime;
473
0
  aPointerEvent->mTimeStamp = aTouchEvent->mTimeStamp;
474
0
  aPointerEvent->mFlags = aTouchEvent->mFlags;
475
0
  aPointerEvent->button = button;
476
0
  aPointerEvent->buttons = buttons;
477
0
  aPointerEvent->inputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
478
0
}
479
480
/* static */ void
481
PointerEventHandler::DispatchPointerFromMouseOrTouch(
482
                       PresShell* aShell,
483
                       nsIFrame* aFrame,
484
                       nsIContent* aContent,
485
                       WidgetGUIEvent* aEvent,
486
                       bool aDontRetargetEvents,
487
                       nsEventStatus* aStatus,
488
                       nsIContent** aTargetContent)
489
0
{
490
0
  MOZ_ASSERT(IsPointerEventEnabled());
491
0
  MOZ_ASSERT(aFrame || aContent);
492
0
  MOZ_ASSERT(aEvent);
493
0
494
0
  EventMessage pointerMessage = eVoidEvent;
495
0
  if (aEvent->mClass == eMouseEventClass) {
496
0
    WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
497
0
    // 1. If it is not mouse then it is likely will come as touch event
498
0
    // 2. We don't synthesize pointer events for those events that are not
499
0
    //    dispatched to DOM.
500
0
    if (!mouseEvent->convertToPointer ||
501
0
        !aEvent->IsAllowedToDispatchDOMEvent()) {
502
0
      return;
503
0
    }
504
0
    int16_t button = mouseEvent->button;
505
0
    switch (mouseEvent->mMessage) {
506
0
    case eMouseMove:
507
0
      button = WidgetMouseEvent::eNoButton;
508
0
      pointerMessage = ePointerMove;
509
0
      break;
510
0
    case eMouseUp:
511
0
      pointerMessage = mouseEvent->buttons ? ePointerMove : ePointerUp;
512
0
      break;
513
0
    case eMouseDown:
514
0
      pointerMessage =
515
0
        mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
516
0
        ePointerMove : ePointerDown;
517
0
      break;
518
0
    default:
519
0
      return;
520
0
    }
521
0
522
0
    WidgetPointerEvent event(*mouseEvent);
523
0
    InitPointerEventFromMouse(&event, mouseEvent, pointerMessage);
524
0
    event.convertToPointer = mouseEvent->convertToPointer = false;
525
0
    RefPtr<PresShell> shell(aShell);
526
0
    if (!aFrame) {
527
0
      shell = PresShell::GetShellForEventTarget(nullptr, aContent);
528
0
      if (!shell) {
529
0
        return;
530
0
      }
531
0
    }
532
0
    PreHandlePointerEventsPreventDefault(&event, aEvent);
533
0
    // Dispatch pointer event to the same target which is found by the
534
0
    // corresponding mouse event.
535
0
    shell->HandleEventWithTarget(&event, aFrame, aContent, aStatus, true,
536
0
                                 aTargetContent);
537
0
    PostHandlePointerEventsPreventDefault(&event, aEvent);
538
0
  } else if (aEvent->mClass == eTouchEventClass) {
539
0
    WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
540
0
    // loop over all touches and dispatch pointer events on each touch
541
0
    // copy the event
542
0
    switch (touchEvent->mMessage) {
543
0
    case eTouchMove:
544
0
      pointerMessage = ePointerMove;
545
0
      break;
546
0
    case eTouchEnd:
547
0
      pointerMessage = ePointerUp;
548
0
      break;
549
0
    case eTouchStart:
550
0
      pointerMessage = ePointerDown;
551
0
      break;
552
0
    case eTouchCancel:
553
0
    case eTouchPointerCancel:
554
0
      pointerMessage = ePointerCancel;
555
0
      break;
556
0
    default:
557
0
      return;
558
0
    }
559
0
560
0
    RefPtr<PresShell> shell(aShell);
561
0
    for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
562
0
      Touch* touch = touchEvent->mTouches[i];
563
0
      if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
564
0
        continue;
565
0
      }
566
0
567
0
      WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
568
0
                               touchEvent->mWidget);
569
0
570
0
      InitPointerEventFromTouch(&event, touchEvent, touch, i == 0);
571
0
      event.convertToPointer = touch->convertToPointer = false;
572
0
      if (aEvent->mMessage == eTouchStart) {
573
0
        // We already did hit test for touchstart in PresShell. We should
574
0
        // dispatch pointerdown to the same target as touchstart.
575
0
        nsCOMPtr<nsIContent> content = do_QueryInterface(touch->mTarget);
576
0
        if (!content) {
577
0
          continue;
578
0
        }
579
0
580
0
        nsIFrame* frame = content->GetPrimaryFrame();
581
0
        shell = PresShell::GetShellForEventTarget(frame, content);
582
0
        if (!shell) {
583
0
          continue;
584
0
        }
585
0
586
0
        PreHandlePointerEventsPreventDefault(&event, aEvent);
587
0
        shell->HandleEventWithTarget(&event, frame, content, aStatus, true,
588
0
                                     nullptr);
589
0
        PostHandlePointerEventsPreventDefault(&event, aEvent);
590
0
      } else {
591
0
        // We didn't hit test for other touch events. Spec doesn't mention that
592
0
        // all pointer events should be dispatched to the same target as their
593
0
        // corresponding touch events. Call PresShell::HandleEvent so that we do
594
0
        // hit test for pointer events.
595
0
        PreHandlePointerEventsPreventDefault(&event, aEvent);
596
0
        shell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
597
0
        PostHandlePointerEventsPreventDefault(&event, aEvent);
598
0
      }
599
0
    }
600
0
  }
601
0
}
602
603
/* static */ uint16_t
604
PointerEventHandler::GetPointerType(uint32_t aPointerId)
605
0
{
606
0
  PointerInfo* pointerInfo = nullptr;
607
0
  if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
608
0
    return pointerInfo->mPointerType;
609
0
  }
610
0
  return MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
611
0
}
612
613
/* static */ bool
614
PointerEventHandler::GetPointerPrimaryState(uint32_t aPointerId)
615
0
{
616
0
  PointerInfo* pointerInfo = nullptr;
617
0
  if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
618
0
    return pointerInfo->mPrimaryState;
619
0
  }
620
0
  return false;
621
0
}
622
623
/* static */ void
624
PointerEventHandler::DispatchGotOrLostPointerCaptureEvent(
625
                       bool aIsGotCapture,
626
                       const WidgetPointerEvent* aPointerEvent,
627
                       nsIContent* aCaptureTarget)
628
0
{
629
0
  nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
630
0
  nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
631
0
  if (NS_WARN_IF(!shell)) {
632
0
    return;
633
0
  }
634
0
635
0
  if (!aIsGotCapture && !aCaptureTarget->IsInComposedDoc()) {
636
0
    // If the capturing element was removed from the DOM tree, fire
637
0
    // ePointerLostCapture at the document.
638
0
    PointerEventInit init;
639
0
    init.mPointerId = aPointerEvent->pointerId;
640
0
    init.mBubbles = true;
641
0
    init.mComposed = true;
642
0
    ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
643
0
    init.mIsPrimary = aPointerEvent->mIsPrimary;
644
0
    RefPtr<PointerEvent> event;
645
0
    event = PointerEvent::Constructor(aCaptureTarget,
646
0
                                      NS_LITERAL_STRING("lostpointercapture"),
647
0
                                      init);
648
0
    targetDoc->DispatchEvent(*event);
649
0
    return;
650
0
  }
651
0
  nsEventStatus status = nsEventStatus_eIgnore;
652
0
  WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
653
0
                                aIsGotCapture ? ePointerGotCapture :
654
0
                                                ePointerLostCapture,
655
0
                                aPointerEvent->mWidget);
656
0
657
0
  localEvent.AssignPointerEventData(*aPointerEvent, true);
658
0
  DebugOnly<nsresult> rv = shell->HandleEventWithTarget(
659
0
                                    &localEvent,
660
0
                                    aCaptureTarget->GetPrimaryFrame(),
661
0
                                    aCaptureTarget, &status);
662
0
663
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
664
0
                       "DispatchGotOrLostPointerCaptureEvent failed");
665
0
}
666
667
} // namespace mozilla