summaryrefslogtreecommitdiff
path: root/gfx/layers/apz/public/IAPZCTreeManager.cpp
blob: 372257ae4576bc18b08423129275968c9f5b53c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/layers/IAPZCTreeManager.h"

#include "gfxPrefs.h"                       // for gfxPrefs
#include "InputData.h"                      // for InputData, etc
#include "mozilla/EventStateManager.h"      // for WheelPrefs
#include "mozilla/layers/APZThreadUtils.h"  // for AssertOnCompositorThread, etc
#include "mozilla/MouseEvents.h"            // for WidgetMouseEvent
#include "mozilla/TouchEvents.h"            // for WidgetTouchEvent

namespace mozilla {
namespace layers {

static bool
WillHandleMouseEvent(const WidgetMouseEventBase& aEvent)
{
  return aEvent.mMessage == eMouseMove ||
         aEvent.mMessage == eMouseDown ||
         aEvent.mMessage == eMouseUp ||
         aEvent.mMessage == eDragEnd;
}

// Returns whether or not a wheel event action will be (or was) performed by
// APZ. If this returns true, the event must not perform a synchronous
// scroll.
//
// Even if this returns false, all wheel events in APZ-aware widgets must
// be sent through APZ so they are transformed correctly for TabParent.
static bool
WillHandleWheelEvent(WidgetWheelEvent* aEvent)
{
  return EventStateManager::WheelEventIsScrollAction(aEvent) &&
         (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE ||
          aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL ||
          aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
}

nsEventStatus
IAPZCTreeManager::ReceiveInputEvent(
    WidgetInputEvent& aEvent,
    ScrollableLayerGuid* aOutTargetGuid,
    uint64_t* aOutInputBlockId)
{
  APZThreadUtils::AssertOnControllerThread();

  // Initialize aOutInputBlockId to a sane value, and then later we overwrite
  // it if the input event goes into a block.
  if (aOutInputBlockId) {
    *aOutInputBlockId = 0;
  }

  switch (aEvent.mClass) {
    case eMouseEventClass:
    case eDragEventClass: {

      WidgetMouseEvent& mouseEvent = *aEvent.AsMouseEvent();

      // Note, we call this before having transformed the reference point.
      if (mouseEvent.IsReal()) {
        UpdateWheelTransaction(mouseEvent.mRefPoint, mouseEvent.mMessage);
      }

      if (WillHandleMouseEvent(mouseEvent)) {

        MouseInput input(mouseEvent);
        input.mOrigin = ScreenPoint(mouseEvent.mRefPoint.x, mouseEvent.mRefPoint.y);

        nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);

        mouseEvent.mRefPoint.x = input.mOrigin.x;
        mouseEvent.mRefPoint.y = input.mOrigin.y;
        mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
        return status;

      }

      TransformEventRefPoint(&mouseEvent.mRefPoint, aOutTargetGuid);
      return nsEventStatus_eIgnore;
    }
    case eTouchEventClass: {

      WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
      MultiTouchInput touchInput(touchEvent);
      nsEventStatus result = ReceiveInputEvent(touchInput, aOutTargetGuid, aOutInputBlockId);
      // touchInput was modified in-place to possibly remove some
      // touch points (if we are overscrolled), and the coordinates were
      // modified using the APZ untransform. We need to copy these changes
      // back into the WidgetInputEvent.
      touchEvent.mTouches.Clear();
      touchEvent.mTouches.SetCapacity(touchInput.mTouches.Length());
      for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
        *touchEvent.mTouches.AppendElement() =
          touchInput.mTouches[i].ToNewDOMTouch();
      }
      touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
      return result;

    }
    case eWheelEventClass: {
      WidgetWheelEvent& wheelEvent = *aEvent.AsWheelEvent();

      if (WillHandleWheelEvent(&wheelEvent)) {

        ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
        if (gfxPrefs::SmoothScrollEnabled() &&
            ((wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
              gfxPrefs::WheelSmoothScrollEnabled()) ||
             (wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE &&
              gfxPrefs::PageSmoothScrollEnabled())))
        {
          scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
        }

        ScreenPoint origin(wheelEvent.mRefPoint.x, wheelEvent.mRefPoint.y);
        ScrollWheelInput input(wheelEvent.mTime, wheelEvent.mTimeStamp, 0,
                               scrollMode,
                               ScrollWheelInput::DeltaTypeForDeltaMode(
                                                   wheelEvent.mDeltaMode),
                               origin,
                               wheelEvent.mDeltaX, wheelEvent.mDeltaY,
                               wheelEvent.mAllowToOverrideSystemScrollSpeed);

        // We add the user multiplier as a separate field, rather than premultiplying
        // it, because if the input is converted back to a WidgetWheelEvent, then
        // EventStateManager would apply the delta a second time. We could in theory
        // work around this by asking ESM to customize the event much sooner, and
        // then save the "mCustomizedByUserPrefs" bit on ScrollWheelInput - but for
        // now, this seems easier.
        EventStateManager::GetUserPrefsForWheelEvent(&wheelEvent,
          &input.mUserDeltaMultiplierX,
          &input.mUserDeltaMultiplierY);

        nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
        wheelEvent.mRefPoint.x = input.mOrigin.x;
        wheelEvent.mRefPoint.y = input.mOrigin.y;
        wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
        return status;
      }

      UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
      TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid);
      return nsEventStatus_eIgnore;

    }
    default: {

      UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
      TransformEventRefPoint(&aEvent.mRefPoint, aOutTargetGuid);
      return nsEventStatus_eIgnore;

    }
  }

  MOZ_ASSERT_UNREACHABLE("Invalid WidgetInputEvent type.");
  return nsEventStatus_eConsumeNoDefault;
}

} // namespace layers
} // namespace mozilla