Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/base/AccessibleCaretEventHub.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 "AccessibleCaretEventHub.h"
8
9
#include "AccessibleCaretLogger.h"
10
#include "AccessibleCaretManager.h"
11
#include "Layers.h"
12
#include "gfxPrefs.h"
13
#include "mozilla/AutoRestore.h"
14
#include "mozilla/MouseEvents.h"
15
#include "mozilla/StaticPrefs.h"
16
#include "mozilla/TextEvents.h"
17
#include "mozilla/TouchEvents.h"
18
#include "mozilla/dom/MouseEventBinding.h"
19
#include "mozilla/dom/Selection.h"
20
#include "nsCanvasFrame.h"
21
#include "nsDocShell.h"
22
#include "nsFocusManager.h"
23
#include "nsFrameSelection.h"
24
#include "nsIDocument.h"
25
#include "nsITimer.h"
26
#include "nsPresContext.h"
27
28
using namespace mozilla;
29
using namespace mozilla::dom;
30
31
namespace mozilla {
32
33
#undef AC_LOG
34
#define AC_LOG(message, ...)                                                   \
35
0
  AC_LOG_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
36
37
#undef AC_LOGV
38
#define AC_LOGV(message, ...)                                                  \
39
0
  AC_LOGV_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
40
41
NS_IMPL_ISUPPORTS(AccessibleCaretEventHub, nsIReflowObserver, nsIScrollObserver,
42
                  nsISupportsWeakReference);
43
44
// -----------------------------------------------------------------------------
45
// NoActionState
46
//
47
class AccessibleCaretEventHub::NoActionState
48
  : public AccessibleCaretEventHub::State
49
{
50
public:
51
0
  const char* Name() const override { return "NoActionState"; }
52
53
  MOZ_CAN_RUN_SCRIPT
54
  nsEventStatus OnPress(AccessibleCaretEventHub* aContext,
55
                        const nsPoint& aPoint,
56
                        int32_t aTouchId,
57
                        EventClassID aEventClass) override
58
0
  {
59
0
    nsEventStatus rv = nsEventStatus_eIgnore;
60
0
61
0
    if (NS_SUCCEEDED(aContext->mManager->PressCaret(aPoint, aEventClass))) {
62
0
      aContext->SetState(AccessibleCaretEventHub::PressCaretState());
63
0
      rv = nsEventStatus_eConsumeNoDefault;
64
0
    } else {
65
0
      aContext->SetState(AccessibleCaretEventHub::PressNoCaretState());
66
0
    }
67
0
68
0
    aContext->mPressPoint = aPoint;
69
0
    aContext->mActiveTouchId = aTouchId;
70
0
71
0
    return rv;
72
0
  }
73
74
  MOZ_CAN_RUN_SCRIPT
75
  void OnScrollStart(AccessibleCaretEventHub* aContext) override
76
0
  {
77
0
    aContext->mManager->OnScrollStart();
78
0
    aContext->SetState(AccessibleCaretEventHub::ScrollState());
79
0
  }
80
81
  MOZ_CAN_RUN_SCRIPT
82
  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override
83
0
  {
84
0
    aContext->mManager->OnScrollPositionChanged();
85
0
  }
86
87
  MOZ_CAN_RUN_SCRIPT
88
  void OnSelectionChanged(AccessibleCaretEventHub* aContext,
89
                          nsIDocument* aDoc,
90
                          dom::Selection* aSel,
91
                          int16_t aReason) override
92
0
  {
93
0
    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
94
0
  }
95
96
  MOZ_CAN_RUN_SCRIPT
97
  void OnBlur(AccessibleCaretEventHub* aContext,
98
              bool aIsLeavingDocument) override
99
0
  {
100
0
    aContext->mManager->OnBlur();
101
0
  }
102
103
  MOZ_CAN_RUN_SCRIPT
104
  void OnReflow(AccessibleCaretEventHub* aContext) override
105
0
  {
106
0
    aContext->mManager->OnReflow();
107
0
  }
108
109
  void Enter(AccessibleCaretEventHub* aContext) override
110
0
  {
111
0
    aContext->mPressPoint = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
112
0
    aContext->mActiveTouchId = kInvalidTouchId;
113
0
  }
114
};
115
116
// -----------------------------------------------------------------------------
117
// PressCaretState: Always consume the event since we've pressed on the caret.
118
//
119
class AccessibleCaretEventHub::PressCaretState
120
  : public AccessibleCaretEventHub::State
121
{
122
public:
123
0
  const char* Name() const override { return "PressCaretState"; }
124
125
  MOZ_CAN_RUN_SCRIPT
126
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
127
                       const nsPoint& aPoint) override
128
0
  {
129
0
    if (aContext->MoveDistanceIsLarge(aPoint)) {
130
0
      if (NS_SUCCEEDED(aContext->mManager->DragCaret(aPoint))) {
131
0
        aContext->SetState(AccessibleCaretEventHub::DragCaretState());
132
0
      }
133
0
    }
134
0
135
0
    return nsEventStatus_eConsumeNoDefault;
136
0
  }
137
138
  MOZ_CAN_RUN_SCRIPT
139
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override
140
0
  {
141
0
    aContext->mManager->ReleaseCaret();
142
0
    aContext->mManager->TapCaret(aContext->mPressPoint);
143
0
    aContext->SetState(AccessibleCaretEventHub::NoActionState());
144
0
145
0
    return nsEventStatus_eConsumeNoDefault;
146
0
  }
147
148
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
149
                          const nsPoint& aPoint) override
150
0
  {
151
0
    return nsEventStatus_eConsumeNoDefault;
152
0
  }
153
};
154
155
// -----------------------------------------------------------------------------
156
// DragCaretState: Always consume the event since we've pressed on the caret.
157
//
158
class AccessibleCaretEventHub::DragCaretState
159
  : public AccessibleCaretEventHub::State
160
{
161
public:
162
0
  const char* Name() const override { return "DragCaretState"; }
163
164
  MOZ_CAN_RUN_SCRIPT
165
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
166
                       const nsPoint& aPoint) override
167
0
  {
168
0
    aContext->mManager->DragCaret(aPoint);
169
0
170
0
    return nsEventStatus_eConsumeNoDefault;
171
0
  }
172
173
  MOZ_CAN_RUN_SCRIPT
174
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override
175
0
  {
176
0
    aContext->mManager->ReleaseCaret();
177
0
    aContext->SetState(AccessibleCaretEventHub::NoActionState());
178
0
179
0
    return nsEventStatus_eConsumeNoDefault;
180
0
  }
181
};
182
183
// -----------------------------------------------------------------------------
184
// PressNoCaretState
185
//
186
class AccessibleCaretEventHub::PressNoCaretState
187
  : public AccessibleCaretEventHub::State
188
{
189
public:
190
0
  const char* Name() const override { return "PressNoCaretState"; }
191
192
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
193
                       const nsPoint& aPoint) override
194
0
  {
195
0
    if (aContext->MoveDistanceIsLarge(aPoint)) {
196
0
      aContext->SetState(AccessibleCaretEventHub::NoActionState());
197
0
    }
198
0
199
0
    return nsEventStatus_eIgnore;
200
0
  }
201
202
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override
203
0
  {
204
0
    aContext->SetState(AccessibleCaretEventHub::NoActionState());
205
0
206
0
    return nsEventStatus_eIgnore;
207
0
  }
208
209
  MOZ_CAN_RUN_SCRIPT
210
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
211
                          const nsPoint& aPoint) override
212
0
  {
213
0
    aContext->SetState(AccessibleCaretEventHub::LongTapState());
214
0
215
0
    return aContext->GetState()->OnLongTap(aContext, aPoint);
216
0
  }
217
218
  MOZ_CAN_RUN_SCRIPT
219
  void OnScrollStart(AccessibleCaretEventHub* aContext) override
220
0
  {
221
0
    aContext->mManager->OnScrollStart();
222
0
    aContext->SetState(AccessibleCaretEventHub::ScrollState());
223
0
  }
224
225
  MOZ_CAN_RUN_SCRIPT
226
  void OnBlur(AccessibleCaretEventHub* aContext,
227
              bool aIsLeavingDocument) override
228
0
  {
229
0
    aContext->mManager->OnBlur();
230
0
    if (aIsLeavingDocument) {
231
0
      aContext->SetState(AccessibleCaretEventHub::NoActionState());
232
0
    }
233
0
  }
234
235
  MOZ_CAN_RUN_SCRIPT
236
  void OnSelectionChanged(AccessibleCaretEventHub* aContext,
237
                          nsIDocument* aDoc,
238
                          dom::Selection* aSel,
239
                          int16_t aReason) override
240
0
  {
241
0
    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
242
0
  }
243
244
  MOZ_CAN_RUN_SCRIPT
245
  void OnReflow(AccessibleCaretEventHub* aContext) override
246
0
  {
247
0
    aContext->mManager->OnReflow();
248
0
  }
249
250
  void Enter(AccessibleCaretEventHub* aContext) override
251
0
  {
252
0
    aContext->LaunchLongTapInjector();
253
0
  }
254
255
  void Leave(AccessibleCaretEventHub* aContext) override
256
0
  {
257
0
    aContext->CancelLongTapInjector();
258
0
  }
259
};
260
261
// -----------------------------------------------------------------------------
262
// ScrollState
263
//
264
class AccessibleCaretEventHub::ScrollState
265
  : public AccessibleCaretEventHub::State
266
{
267
public:
268
0
  const char* Name() const override { return "ScrollState"; }
269
270
  MOZ_CAN_RUN_SCRIPT
271
  void OnScrollEnd(AccessibleCaretEventHub* aContext) override
272
0
  {
273
0
    aContext->mManager->OnScrollEnd();
274
0
    aContext->SetState(AccessibleCaretEventHub::NoActionState());
275
0
  }
276
277
  MOZ_CAN_RUN_SCRIPT
278
  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override
279
0
  {
280
0
    aContext->mManager->OnScrollPositionChanged();
281
0
  }
282
283
  MOZ_CAN_RUN_SCRIPT
284
  void OnBlur(AccessibleCaretEventHub* aContext,
285
              bool aIsLeavingDocument) override
286
0
  {
287
0
    aContext->mManager->OnBlur();
288
0
    if (aIsLeavingDocument) {
289
0
      aContext->SetState(AccessibleCaretEventHub::NoActionState());
290
0
    }
291
0
  }
292
};
293
294
// -----------------------------------------------------------------------------
295
// LongTapState
296
//
297
class AccessibleCaretEventHub::LongTapState
298
  : public AccessibleCaretEventHub::State
299
{
300
public:
301
0
  const char* Name() const override { return "LongTapState"; }
302
303
  MOZ_CAN_RUN_SCRIPT
304
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
305
                          const nsPoint& aPoint) override
306
0
  {
307
0
    // In general text selection is lower-priority than the context menu. If
308
0
    // we consume this long-press event, then it prevents the context menu from
309
0
    // showing up on desktop Firefox (because that happens on long-tap-up, if
310
0
    // the long-tap was not cancelled). So we return eIgnore instead.
311
0
    aContext->mManager->SelectWordOrShortcut(aPoint);
312
0
    return nsEventStatus_eIgnore;
313
0
  }
314
315
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override
316
0
  {
317
0
    aContext->SetState(AccessibleCaretEventHub::NoActionState());
318
0
319
0
    // Do not consume the release since the press is not consumed in
320
0
    // PressNoCaretState either.
321
0
    return nsEventStatus_eIgnore;
322
0
  }
323
324
  MOZ_CAN_RUN_SCRIPT
325
  void OnScrollStart(AccessibleCaretEventHub* aContext) override
326
0
  {
327
0
    aContext->mManager->OnScrollStart();
328
0
    aContext->SetState(AccessibleCaretEventHub::ScrollState());
329
0
  }
330
331
  MOZ_CAN_RUN_SCRIPT
332
  void OnReflow(AccessibleCaretEventHub* aContext) override
333
0
  {
334
0
    aContext->mManager->OnReflow();
335
0
  }
336
};
337
338
// -----------------------------------------------------------------------------
339
// Implementation of AccessibleCaretEventHub methods
340
//
341
AccessibleCaretEventHub::State*
342
AccessibleCaretEventHub::GetState() const
343
0
{
344
0
  return mState;
345
0
}
346
347
void
348
AccessibleCaretEventHub::SetState(State* aState)
349
0
{
350
0
  MOZ_ASSERT(aState);
351
0
352
0
  AC_LOG("%s -> %s", mState->Name(), aState->Name());
353
0
354
0
  mState->Leave(this);
355
0
  mState = aState;
356
0
  mState->Enter(this);
357
0
}
358
359
MOZ_IMPL_STATE_CLASS_GETTER(NoActionState)
360
MOZ_IMPL_STATE_CLASS_GETTER(PressCaretState)
361
MOZ_IMPL_STATE_CLASS_GETTER(DragCaretState)
362
MOZ_IMPL_STATE_CLASS_GETTER(PressNoCaretState)
363
MOZ_IMPL_STATE_CLASS_GETTER(ScrollState)
364
MOZ_IMPL_STATE_CLASS_GETTER(LongTapState)
365
366
AccessibleCaretEventHub::AccessibleCaretEventHub(nsIPresShell* aPresShell)
367
  : mPresShell(aPresShell)
368
0
{
369
0
}
370
371
void
372
AccessibleCaretEventHub::Init()
373
0
{
374
0
  if (mInitialized && mManager) {
375
0
    mManager->OnFrameReconstruction();
376
0
  }
377
0
378
0
  if (mInitialized || !mPresShell || !mPresShell->GetCanvasFrame()) {
379
0
    return;
380
0
  }
381
0
382
0
  // Without nsAutoScriptBlocker, the script might be run after constructing
383
0
  // mFirstCaret in AccessibleCaretManager's constructor, which might destructs
384
0
  // the whole frame tree. Therefore we'll fail to construct mSecondCaret
385
0
  // because we cannot get root frame or canvas frame from mPresShell to inject
386
0
  // anonymous content. To avoid that, we protect Init() by nsAutoScriptBlocker.
387
0
  // To reproduce, run "./mach crashtest layout/base/crashtests/897852.html"
388
0
  // without the following scriptBlocker.
389
0
  nsAutoScriptBlocker scriptBlocker;
390
0
391
0
  nsPresContext* presContext = mPresShell->GetPresContext();
392
0
  MOZ_ASSERT(presContext, "PresContext should be given in PresShell::Init()");
393
0
394
0
  nsIDocShell* docShell = presContext->GetDocShell();
395
0
  if (!docShell) {
396
0
    return;
397
0
  }
398
0
399
0
  nsCOMPtr<nsIDocShell> curDocShell = docShell;
400
0
  do {
401
0
    curDocShell->AddWeakReflowObserver(this);
402
0
    curDocShell->AddWeakScrollObserver(this);
403
0
404
0
    nsCOMPtr<nsIDocShellTreeItem> tmp;
405
0
    curDocShell->GetSameTypeParent(getter_AddRefs(tmp));
406
0
    curDocShell = do_QueryInterface(tmp);
407
0
  } while (curDocShell);
408
0
409
0
  mDocShell = static_cast<nsDocShell*>(docShell);
410
0
411
0
  if (StaticPrefs::layout_accessiblecaret_use_long_tap_injector()) {
412
0
    mLongTapInjectorTimer = NS_NewTimer();
413
0
  }
414
0
415
0
  mManager = MakeUnique<AccessibleCaretManager>(mPresShell);
416
0
417
0
  mInitialized = true;
418
0
}
419
420
void
421
AccessibleCaretEventHub::Terminate()
422
0
{
423
0
  if (!mInitialized) {
424
0
    return;
425
0
  }
426
0
427
0
  nsCOMPtr<nsIDocShell> curDocShell = mDocShell.get();
428
0
  while (curDocShell) {
429
0
    curDocShell->RemoveWeakReflowObserver(this);
430
0
    curDocShell->RemoveWeakScrollObserver(this);
431
0
432
0
    nsCOMPtr<nsIDocShellTreeItem> tmp;
433
0
    curDocShell->GetSameTypeParent(getter_AddRefs(tmp));
434
0
    curDocShell = do_QueryInterface(tmp);
435
0
  }
436
0
437
0
  if (mLongTapInjectorTimer) {
438
0
    mLongTapInjectorTimer->Cancel();
439
0
  }
440
0
441
0
  mManager->Terminate();
442
0
  mPresShell = nullptr;
443
0
  mInitialized = false;
444
0
}
445
446
nsEventStatus
447
AccessibleCaretEventHub::HandleEvent(WidgetEvent* aEvent)
448
0
{
449
0
  nsEventStatus status = nsEventStatus_eIgnore;
450
0
451
0
  if (!mInitialized) {
452
0
    return status;
453
0
  }
454
0
455
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
456
0
457
0
  switch (aEvent->mClass) {
458
0
    case eMouseEventClass:
459
0
      status = HandleMouseEvent(aEvent->AsMouseEvent());
460
0
      break;
461
0
462
0
    case eTouchEventClass:
463
0
      status = HandleTouchEvent(aEvent->AsTouchEvent());
464
0
      break;
465
0
466
0
    case eKeyboardEventClass:
467
0
      status = HandleKeyboardEvent(aEvent->AsKeyboardEvent());
468
0
      break;
469
0
470
0
    default:
471
0
      break;
472
0
  }
473
0
474
0
  return status;
475
0
}
476
477
nsEventStatus
478
AccessibleCaretEventHub::HandleMouseEvent(WidgetMouseEvent* aEvent)
479
0
{
480
0
  nsEventStatus rv = nsEventStatus_eIgnore;
481
0
482
0
  if (aEvent->button != WidgetMouseEvent::eLeftButton) {
483
0
    return rv;
484
0
  }
485
0
486
0
  int32_t id =
487
0
    (mActiveTouchId == kInvalidTouchId ? kDefaultTouchId : mActiveTouchId);
488
0
  nsPoint point = GetMouseEventPosition(aEvent);
489
0
490
0
  if (aEvent->mMessage == eMouseDown ||
491
0
      aEvent->mMessage == eMouseUp ||
492
0
      aEvent->mMessage == eMouseClick ||
493
0
      aEvent->mMessage == eMouseDoubleClick ||
494
0
      aEvent->mMessage == eMouseLongTap) {
495
0
    // Don't reset the source on mouse movement since that can
496
0
    // happen anytime, even randomly during a touch sequence.
497
0
    mManager->SetLastInputSource(aEvent->inputSource);
498
0
  }
499
0
500
0
  switch (aEvent->mMessage) {
501
0
    case eMouseDown:
502
0
      AC_LOGV("Before eMouseDown, state: %s", mState->Name());
503
0
      rv = mState->OnPress(this, point, id, eMouseEventClass);
504
0
      AC_LOGV("After eMouseDown, state: %s, consume: %d", mState->Name(), rv);
505
0
      break;
506
0
507
0
    case eMouseMove:
508
0
      AC_LOGV("Before eMouseMove, state: %s", mState->Name());
509
0
      rv = mState->OnMove(this, point);
510
0
      AC_LOGV("After eMouseMove, state: %s, consume: %d", mState->Name(), rv);
511
0
      break;
512
0
513
0
    case eMouseUp:
514
0
      AC_LOGV("Before eMouseUp, state: %s", mState->Name());
515
0
      rv = mState->OnRelease(this);
516
0
      AC_LOGV("After eMouseUp, state: %s, consume: %d", mState->Name(), rv);
517
0
      break;
518
0
519
0
    case eMouseLongTap:
520
0
      AC_LOGV("Before eMouseLongTap, state: %s", mState->Name());
521
0
      rv = mState->OnLongTap(this, point);
522
0
      AC_LOGV("After eMouseLongTap, state: %s, consume: %d", mState->Name(),
523
0
              rv);
524
0
      break;
525
0
526
0
    default:
527
0
      break;
528
0
  }
529
0
530
0
  return rv;
531
0
}
532
533
nsEventStatus
534
AccessibleCaretEventHub::HandleTouchEvent(WidgetTouchEvent* aEvent)
535
0
{
536
0
  if (aEvent->mTouches.IsEmpty()) {
537
0
    AC_LOG("%s: Receive a touch event without any touch data!", __FUNCTION__);
538
0
    return nsEventStatus_eIgnore;
539
0
  }
540
0
541
0
  nsEventStatus rv = nsEventStatus_eIgnore;
542
0
543
0
  int32_t id =
544
0
    (mActiveTouchId == kInvalidTouchId ? aEvent->mTouches[0]->Identifier()
545
0
                                       : mActiveTouchId);
546
0
  nsPoint point = GetTouchEventPosition(aEvent, id);
547
0
548
0
  mManager->SetLastInputSource(MouseEvent_Binding::MOZ_SOURCE_TOUCH);
549
0
550
0
  switch (aEvent->mMessage) {
551
0
    case eTouchStart:
552
0
      AC_LOGV("Before eTouchStart, state: %s", mState->Name());
553
0
      rv = mState->OnPress(this, point, id, eTouchEventClass);
554
0
      AC_LOGV("After eTouchStart, state: %s, consume: %d", mState->Name(), rv);
555
0
      break;
556
0
557
0
    case eTouchMove:
558
0
      AC_LOGV("Before eTouchMove, state: %s", mState->Name());
559
0
      rv = mState->OnMove(this, point);
560
0
      AC_LOGV("After eTouchMove, state: %s, consume: %d", mState->Name(), rv);
561
0
      break;
562
0
563
0
    case eTouchEnd:
564
0
      AC_LOGV("Before eTouchEnd, state: %s", mState->Name());
565
0
      rv = mState->OnRelease(this);
566
0
      AC_LOGV("After eTouchEnd, state: %s, consume: %d", mState->Name(), rv);
567
0
      break;
568
0
569
0
    case eTouchCancel:
570
0
      AC_LOGV("Got eTouchCancel, state: %s", mState->Name());
571
0
      // Do nothing since we don't really care eTouchCancel anyway.
572
0
      break;
573
0
574
0
    default:
575
0
      break;
576
0
  }
577
0
578
0
  return rv;
579
0
}
580
581
nsEventStatus
582
AccessibleCaretEventHub::HandleKeyboardEvent(WidgetKeyboardEvent* aEvent)
583
0
{
584
0
  mManager->SetLastInputSource(MouseEvent_Binding::MOZ_SOURCE_KEYBOARD);
585
0
586
0
  switch (aEvent->mMessage) {
587
0
    case eKeyUp:
588
0
      AC_LOGV("eKeyUp, state: %s", mState->Name());
589
0
      mManager->OnKeyboardEvent();
590
0
      break;
591
0
592
0
    case eKeyDown:
593
0
      AC_LOGV("eKeyDown, state: %s", mState->Name());
594
0
      mManager->OnKeyboardEvent();
595
0
      break;
596
0
597
0
    case eKeyPress:
598
0
      AC_LOGV("eKeyPress, state: %s", mState->Name());
599
0
      mManager->OnKeyboardEvent();
600
0
      break;
601
0
602
0
    default:
603
0
      break;
604
0
  }
605
0
606
0
  return nsEventStatus_eIgnore;
607
0
}
608
609
bool
610
AccessibleCaretEventHub::MoveDistanceIsLarge(const nsPoint& aPoint) const
611
0
{
612
0
  nsPoint delta = aPoint - mPressPoint;
613
0
  return NS_hypot(delta.x, delta.y) >
614
0
         AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel;
615
0
}
616
617
void
618
AccessibleCaretEventHub::LaunchLongTapInjector()
619
0
{
620
0
  if (!mLongTapInjectorTimer) {
621
0
    return;
622
0
  }
623
0
624
0
  int32_t longTapDelay = gfxPrefs::UiClickHoldContextMenusDelay();
625
0
  mLongTapInjectorTimer->InitWithNamedFuncCallback(
626
0
    FireLongTap,
627
0
    this,
628
0
    longTapDelay,
629
0
    nsITimer::TYPE_ONE_SHOT,
630
0
    "AccessibleCaretEventHub::LaunchLongTapInjector");
631
0
}
632
633
void
634
AccessibleCaretEventHub::CancelLongTapInjector()
635
0
{
636
0
  if (!mLongTapInjectorTimer) {
637
0
    return;
638
0
  }
639
0
640
0
  mLongTapInjectorTimer->Cancel();
641
0
}
642
643
/* static */ void
644
AccessibleCaretEventHub::FireLongTap(nsITimer* aTimer,
645
                                     void* aAccessibleCaretEventHub)
646
0
{
647
0
  RefPtr<AccessibleCaretEventHub> self =
648
0
    static_cast<AccessibleCaretEventHub*>(aAccessibleCaretEventHub);
649
0
  self->mState->OnLongTap(self, self->mPressPoint);
650
0
}
651
652
NS_IMETHODIMP
653
AccessibleCaretEventHub::Reflow(DOMHighResTimeStamp aStart,
654
                                DOMHighResTimeStamp aEnd)
655
0
{
656
0
  if (!mInitialized) {
657
0
    return NS_OK;
658
0
  }
659
0
660
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
661
0
662
0
  if (mIsInReflowCallback) {
663
0
    return NS_OK;
664
0
  }
665
0
666
0
  AutoRestore<bool> autoRestoreIsInReflowCallback(mIsInReflowCallback);
667
0
  mIsInReflowCallback = true;
668
0
669
0
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
670
0
  mState->OnReflow(this);
671
0
  return NS_OK;
672
0
}
673
674
NS_IMETHODIMP
675
AccessibleCaretEventHub::ReflowInterruptible(DOMHighResTimeStamp aStart,
676
                                             DOMHighResTimeStamp aEnd)
677
0
{
678
0
  // Defer the error checking to Reflow().
679
0
  return Reflow(aStart, aEnd);
680
0
}
681
682
void
683
AccessibleCaretEventHub::AsyncPanZoomStarted()
684
0
{
685
0
  if (!mInitialized) {
686
0
    return;
687
0
  }
688
0
689
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
690
0
691
0
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
692
0
  mState->OnScrollStart(this);
693
0
}
694
695
void
696
AccessibleCaretEventHub::AsyncPanZoomStopped()
697
0
{
698
0
  if (!mInitialized) {
699
0
    return;
700
0
  }
701
0
702
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
703
0
704
0
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
705
0
  mState->OnScrollEnd(this);
706
0
}
707
708
void
709
AccessibleCaretEventHub::ScrollPositionChanged()
710
0
{
711
0
  if (!mInitialized) {
712
0
    return;
713
0
  }
714
0
715
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
716
0
717
0
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
718
0
  mState->OnScrollPositionChanged(this);
719
0
}
720
721
void
722
AccessibleCaretEventHub::OnSelectionChange(nsIDocument* aDoc,
723
                                           dom::Selection* aSel,
724
                                           int16_t aReason)
725
0
{
726
0
  if (!mInitialized) {
727
0
    return;
728
0
  }
729
0
730
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
731
0
732
0
  AC_LOG("%s, state: %s, reason: %d", __FUNCTION__, mState->Name(), aReason);
733
0
734
0
  // XXX Here we may be in a hot path.  So, if we could avoid this virtual call,
735
0
  //     we should do so.
736
0
  mState->OnSelectionChanged(this, aDoc, aSel, aReason);
737
0
}
738
739
void
740
AccessibleCaretEventHub::NotifyBlur(bool aIsLeavingDocument)
741
0
{
742
0
  if (!mInitialized) {
743
0
    return;
744
0
  }
745
0
746
0
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
747
0
748
0
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
749
0
  mState->OnBlur(this, aIsLeavingDocument);
750
0
}
751
752
nsPoint
753
AccessibleCaretEventHub::GetTouchEventPosition(WidgetTouchEvent* aEvent,
754
                                               int32_t aIdentifier) const
755
0
{
756
0
  for (dom::Touch* touch : aEvent->mTouches) {
757
0
    if (touch->Identifier() == aIdentifier) {
758
0
      LayoutDeviceIntPoint touchIntPoint = touch->mRefPoint;
759
0
760
0
      // Get event coordinate relative to root frame.
761
0
      nsIFrame* rootFrame = mPresShell->GetRootFrame();
762
0
      return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touchIntPoint,
763
0
                                                          rootFrame);
764
0
    }
765
0
  }
766
0
  return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
767
0
}
768
769
nsPoint
770
AccessibleCaretEventHub::GetMouseEventPosition(WidgetMouseEvent* aEvent) const
771
0
{
772
0
  LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->mRefPoint;
773
0
774
0
  // Get event coordinate relative to root frame.
775
0
  nsIFrame* rootFrame = mPresShell->GetRootFrame();
776
0
  return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mouseIntPoint,
777
0
                                                      rootFrame);
778
0
}
779
780
} // namespace mozilla