Blame dom/events/WheelHandlingHelper.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "WheelHandlingHelper.h"
Packit f0b94e
Packit f0b94e
#include "mozilla/EventDispatcher.h"
Packit f0b94e
#include "mozilla/EventStateManager.h"
Packit f0b94e
#include "mozilla/MouseEvents.h"
Packit f0b94e
#include "mozilla/Preferences.h"
Packit f0b94e
#include "nsCOMPtr.h"
Packit f0b94e
#include "nsContentUtils.h"
Packit f0b94e
#include "nsIContent.h"
Packit f0b94e
#include "nsIDocument.h"
Packit f0b94e
#include "nsIPresShell.h"
Packit f0b94e
#include "nsIScrollableFrame.h"
Packit f0b94e
#include "nsITextControlElement.h"
Packit f0b94e
#include "nsITimer.h"
Packit f0b94e
#include "nsPluginFrame.h"
Packit f0b94e
#include "nsPresContext.h"
Packit f0b94e
#include "prtime.h"
Packit f0b94e
#include "Units.h"
Packit f0b94e
#include "ScrollAnimationPhysics.h"
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::DeltaValues                                           */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
DeltaValues::DeltaValues(WidgetWheelEvent* aEvent)
Packit f0b94e
    : deltaX(aEvent->mDeltaX), deltaY(aEvent->mDeltaY) {}
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::WheelHandlingUtils                                    */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
/* static */ bool WheelHandlingUtils::CanScrollInRange(nscoord aMin,
Packit f0b94e
                                                       nscoord aValue,
Packit f0b94e
                                                       nscoord aMax,
Packit f0b94e
                                                       double aDirection) {
Packit f0b94e
  return aDirection > 0.0 ? aValue < static_cast<double>(aMax)
Packit f0b94e
                          : static_cast<double>(aMin) < aValue;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ bool WheelHandlingUtils::CanScrollOn(nsIFrame* aFrame,
Packit f0b94e
                                                  double aDirectionX,
Packit f0b94e
                                                  double aDirectionY) {
Packit f0b94e
  nsIScrollableFrame* scrollableFrame = do_QueryFrame(aFrame);
Packit f0b94e
  if (scrollableFrame) {
Packit f0b94e
    return CanScrollOn(scrollableFrame, aDirectionX, aDirectionY);
Packit f0b94e
  }
Packit f0b94e
  nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
Packit f0b94e
  return pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ bool WheelHandlingUtils::CanScrollOn(
Packit f0b94e
    nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY) {
Packit f0b94e
  MOZ_ASSERT(aScrollFrame);
Packit f0b94e
  NS_ASSERTION(aDirectionX || aDirectionY,
Packit f0b94e
               "One of the delta values must be non-zero at least");
Packit f0b94e
Packit f0b94e
  nsPoint scrollPt = aScrollFrame->GetScrollPosition();
Packit f0b94e
  nsRect scrollRange = aScrollFrame->GetScrollRange();
Packit f0b94e
  uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
Packit f0b94e
Packit f0b94e
  return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
Packit f0b94e
          CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(),
Packit f0b94e
                           aDirectionX)) ||
Packit f0b94e
         (aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
Packit f0b94e
          CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(),
Packit f0b94e
                           aDirectionY));
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/*static*/ Maybe<layers::ScrollDirection>
Packit f0b94e
WheelHandlingUtils::GetDisregardedWheelScrollDirection(const nsIFrame* aFrame) {
Packit f0b94e
  nsIContent* content = aFrame->GetContent();
Packit f0b94e
  if (!content) {
Packit f0b94e
    return Nothing();
Packit f0b94e
  }
Packit f0b94e
  nsCOMPtr<nsITextControlElement> ctrl = do_QueryInterface(
Packit f0b94e
      content->IsInAnonymousSubtree() ? content->GetBindingParent() : content);
Packit f0b94e
  if (!ctrl || !ctrl->IsSingleLineTextControl()) {
Packit f0b94e
    return Nothing();
Packit f0b94e
  }
Packit f0b94e
  // Disregard scroll in the block-flow direction by mouse wheel on a
Packit f0b94e
  // single-line text control. For instance, in tranditional Chinese writing
Packit f0b94e
  // system, a single-line text control cannot be scrolled horizontally with
Packit f0b94e
  // mouse wheel even if they overflow at the right and left edges; Whereas in
Packit f0b94e
  // latin-based writing system, a single-line text control cannot be scrolled
Packit f0b94e
  // vertically with mouse wheel even if they overflow at the top and bottom
Packit f0b94e
  // edges
Packit f0b94e
  return Some(aFrame->GetWritingMode().IsVertical()
Packit f0b94e
                  ? layers::ScrollDirection::eHorizontal
Packit f0b94e
                  : layers::ScrollDirection::eVertical);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::WheelTransaction                                      */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
AutoWeakFrame WheelTransaction::sTargetFrame(nullptr);
Packit f0b94e
uint32_t WheelTransaction::sTime = 0;
Packit f0b94e
uint32_t WheelTransaction::sMouseMoved = 0;
Packit f0b94e
nsITimer* WheelTransaction::sTimer = nullptr;
Packit f0b94e
int32_t WheelTransaction::sScrollSeriesCounter = 0;
Packit f0b94e
bool WheelTransaction::sOwnScrollbars = false;
Packit f0b94e
Packit f0b94e
/* static */ bool WheelTransaction::OutOfTime(uint32_t aBaseTime,
Packit f0b94e
                                              uint32_t aThreshold) {
Packit f0b94e
  uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
Packit f0b94e
  return (now - aBaseTime > aThreshold);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::OwnScrollbars(bool aOwn) {
Packit f0b94e
  sOwnScrollbars = aOwn;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::BeginTransaction(
Packit f0b94e
    nsIFrame* aTargetFrame, const WidgetWheelEvent* aEvent) {
Packit f0b94e
  NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
Packit f0b94e
  MOZ_ASSERT(aEvent->mMessage == eWheel,
Packit f0b94e
             "Transaction must be started with a wheel event");
Packit f0b94e
  ScrollbarsForWheel::OwnWheelTransaction(false);
Packit f0b94e
  sTargetFrame = aTargetFrame;
Packit f0b94e
  sScrollSeriesCounter = 0;
Packit f0b94e
  if (!UpdateTransaction(aEvent)) {
Packit f0b94e
    NS_ERROR("BeginTransaction is called even cannot scroll the frame");
Packit f0b94e
    EndTransaction();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ bool WheelTransaction::UpdateTransaction(
Packit f0b94e
    const WidgetWheelEvent* aEvent) {
Packit f0b94e
  nsIFrame* scrollToFrame = GetTargetFrame();
Packit f0b94e
  nsIScrollableFrame* scrollableFrame = scrollToFrame->GetScrollTargetFrame();
Packit f0b94e
  if (scrollableFrame) {
Packit f0b94e
    scrollToFrame = do_QueryFrame(scrollableFrame);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!WheelHandlingUtils::CanScrollOn(scrollToFrame, aEvent->mDeltaX,
Packit f0b94e
                                       aEvent->mDeltaY)) {
Packit f0b94e
    OnFailToScrollTarget();
Packit f0b94e
    // We should not modify the transaction state when the view will not be
Packit f0b94e
    // scrolled actually.
Packit f0b94e
    return false;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  SetTimeout();
Packit f0b94e
Packit f0b94e
  if (sScrollSeriesCounter != 0 && OutOfTime(sTime, kScrollSeriesTimeoutMs)) {
Packit f0b94e
    sScrollSeriesCounter = 0;
Packit f0b94e
  }
Packit f0b94e
  sScrollSeriesCounter++;
Packit f0b94e
Packit f0b94e
  // We should use current time instead of WidgetEvent.time.
Packit f0b94e
  // 1. Some events doesn't have the correct creation time.
Packit f0b94e
  // 2. If the computer runs slowly by other processes eating the CPU resource,
Packit f0b94e
  //    the event creation time doesn't keep real time.
Packit f0b94e
  sTime = PR_IntervalToMilliseconds(PR_IntervalNow());
Packit f0b94e
  sMouseMoved = 0;
Packit f0b94e
  return true;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::MayEndTransaction() {
Packit f0b94e
  if (!sOwnScrollbars && ScrollbarsForWheel::IsActive()) {
Packit f0b94e
    ScrollbarsForWheel::OwnWheelTransaction(true);
Packit f0b94e
  } else {
Packit f0b94e
    EndTransaction();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::EndTransaction() {
Packit f0b94e
  if (sTimer) {
Packit f0b94e
    sTimer->Cancel();
Packit f0b94e
  }
Packit f0b94e
  sTargetFrame = nullptr;
Packit f0b94e
  sScrollSeriesCounter = 0;
Packit f0b94e
  if (sOwnScrollbars) {
Packit f0b94e
    sOwnScrollbars = false;
Packit f0b94e
    ScrollbarsForWheel::OwnWheelTransaction(false);
Packit f0b94e
    ScrollbarsForWheel::Inactivate();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ bool WheelTransaction::WillHandleDefaultAction(
Packit f0b94e
    WidgetWheelEvent* aWheelEvent, AutoWeakFrame& aTargetWeakFrame) {
Packit f0b94e
  nsIFrame* lastTargetFrame = GetTargetFrame();
Packit f0b94e
  if (!lastTargetFrame) {
Packit f0b94e
    BeginTransaction(aTargetWeakFrame.GetFrame(), aWheelEvent);
Packit f0b94e
  } else if (lastTargetFrame != aTargetWeakFrame.GetFrame()) {
Packit f0b94e
    EndTransaction();
Packit f0b94e
    BeginTransaction(aTargetWeakFrame.GetFrame(), aWheelEvent);
Packit f0b94e
  } else {
Packit f0b94e
    UpdateTransaction(aWheelEvent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // When the wheel event will not be handled with any frames,
Packit f0b94e
  // UpdateTransaction() fires MozMouseScrollFailed event which is for
Packit f0b94e
  // automated testing.  In the event handler, the target frame might be
Packit f0b94e
  // destroyed.  Then, the caller shouldn't try to handle the default action.
Packit f0b94e
  if (!aTargetWeakFrame.IsAlive()) {
Packit f0b94e
    EndTransaction();
Packit f0b94e
    return false;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return true;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::OnEvent(WidgetEvent* aEvent) {
Packit f0b94e
  if (!sTargetFrame) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (OutOfTime(sTime, GetTimeoutTime())) {
Packit f0b94e
    // Even if the scroll event which is handled after timeout, but onTimeout
Packit f0b94e
    // was not fired by timer, then the scroll event will scroll old frame,
Packit f0b94e
    // therefore, we should call OnTimeout here and ensure to finish the old
Packit f0b94e
    // transaction.
Packit f0b94e
    OnTimeout(nullptr, nullptr);
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  switch (aEvent->mMessage) {
Packit f0b94e
    case eWheel:
Packit f0b94e
      if (sMouseMoved != 0 &&
Packit f0b94e
          OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
Packit f0b94e
        // Terminate the current mousewheel transaction if the mouse moved more
Packit f0b94e
        // than ignoremovedelay milliseconds ago
Packit f0b94e
        EndTransaction();
Packit f0b94e
      }
Packit f0b94e
      return;
Packit f0b94e
    case eMouseMove:
Packit f0b94e
    case eDragOver: {
Packit f0b94e
      WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
Packit f0b94e
      if (mouseEvent->IsReal()) {
Packit f0b94e
        // If the cursor is moving to be outside the frame,
Packit f0b94e
        // terminate the scrollwheel transaction.
Packit f0b94e
        LayoutDeviceIntPoint pt = GetScreenPoint(mouseEvent);
Packit f0b94e
        auto r = LayoutDeviceIntRect::FromAppUnitsToNearest(
Packit f0b94e
            sTargetFrame->GetScreenRectInAppUnits(),
Packit f0b94e
            sTargetFrame->PresContext()->AppUnitsPerDevPixel());
Packit f0b94e
        if (!r.Contains(pt)) {
Packit f0b94e
          EndTransaction();
Packit f0b94e
          return;
Packit f0b94e
        }
Packit f0b94e
Packit f0b94e
        // If the cursor is moving inside the frame, and it is less than
Packit f0b94e
        // ignoremovedelay milliseconds since the last scroll operation, ignore
Packit f0b94e
        // the mouse move; otherwise, record the current mouse move time to be
Packit f0b94e
        // checked later
Packit f0b94e
        if (!sMouseMoved && OutOfTime(sTime, GetIgnoreMoveDelayTime())) {
Packit f0b94e
          sMouseMoved = PR_IntervalToMilliseconds(PR_IntervalNow());
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      return;
Packit f0b94e
    }
Packit f0b94e
    case eKeyPress:
Packit f0b94e
    case eKeyUp:
Packit f0b94e
    case eKeyDown:
Packit f0b94e
    case eMouseUp:
Packit f0b94e
    case eMouseDown:
Packit f0b94e
    case eMouseDoubleClick:
Packit f0b94e
    case eMouseAuxClick:
Packit f0b94e
    case eMouseClick:
Packit f0b94e
    case eContextMenu:
Packit f0b94e
    case eDrop:
Packit f0b94e
      EndTransaction();
Packit f0b94e
      return;
Packit f0b94e
    default:
Packit f0b94e
      break;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::Shutdown() { NS_IF_RELEASE(sTimer); }
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::OnFailToScrollTarget() {
Packit f0b94e
  NS_PRECONDITION(sTargetFrame, "We don't have mouse scrolling transaction");
Packit f0b94e
Packit f0b94e
  if (Prefs::sTestMouseScroll) {
Packit f0b94e
    // This event is used for automated tests, see bug 442774.
Packit f0b94e
    nsContentUtils::DispatchTrustedEvent(
Packit f0b94e
        sTargetFrame->GetContent()->OwnerDoc(), sTargetFrame->GetContent(),
Packit f0b94e
        NS_LITERAL_STRING("MozMouseScrollFailed"), true, true);
Packit f0b94e
  }
Packit f0b94e
  // The target frame might be destroyed in the event handler, at that time,
Packit f0b94e
  // we need to finish the current transaction
Packit f0b94e
  if (!sTargetFrame) {
Packit f0b94e
    EndTransaction();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::OnTimeout(nsITimer* aTimer,
Packit f0b94e
                                              void* aClosure) {
Packit f0b94e
  if (!sTargetFrame) {
Packit f0b94e
    // The transaction target was destroyed already
Packit f0b94e
    EndTransaction();
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
  // Store the sTargetFrame, the variable becomes null in EndTransaction.
Packit f0b94e
  nsIFrame* frame = sTargetFrame;
Packit f0b94e
  // We need to finish current transaction before DOM event firing. Because
Packit f0b94e
  // the next DOM event might create strange situation for us.
Packit f0b94e
  MayEndTransaction();
Packit f0b94e
Packit f0b94e
  if (Prefs::sTestMouseScroll) {
Packit f0b94e
    // This event is used for automated tests, see bug 442774.
Packit f0b94e
    nsContentUtils::DispatchTrustedEvent(
Packit f0b94e
        frame->GetContent()->OwnerDoc(), frame->GetContent(),
Packit f0b94e
        NS_LITERAL_STRING("MozMouseScrollTransactionTimeout"), true, true);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::SetTimeout() {
Packit f0b94e
  if (!sTimer) {
Packit f0b94e
    sTimer = NS_NewTimer().take();
Packit f0b94e
    if (!sTimer) {
Packit f0b94e
      return;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  sTimer->Cancel();
Packit f0b94e
  DebugOnly<nsresult> rv = sTimer->InitWithNamedFuncCallback(
Packit f0b94e
      OnTimeout, nullptr, GetTimeoutTime(), nsITimer::TYPE_ONE_SHOT,
Packit f0b94e
      "WheelTransaction::SetTimeout");
Packit f0b94e
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
Packit f0b94e
                       "nsITimer::InitWithFuncCallback failed");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ LayoutDeviceIntPoint WheelTransaction::GetScreenPoint(
Packit f0b94e
    WidgetGUIEvent* aEvent) {
Packit f0b94e
  NS_ASSERTION(aEvent, "aEvent is null");
Packit f0b94e
  NS_ASSERTION(aEvent->mWidget, "aEvent-mWidget is null");
Packit f0b94e
  return aEvent->mRefPoint + aEvent->mWidget->WidgetToScreenOffset();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ DeltaValues WheelTransaction::AccelerateWheelDelta(
Packit f0b94e
    WidgetWheelEvent* aEvent, bool aAllowScrollSpeedOverride) {
Packit f0b94e
  DeltaValues result(aEvent);
Packit f0b94e
Packit f0b94e
  // Don't accelerate the delta values if the event isn't line scrolling.
Packit f0b94e
  if (aEvent->mDeltaMode != nsIDOMWheelEvent::DOM_DELTA_LINE) {
Packit f0b94e
    return result;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (aAllowScrollSpeedOverride) {
Packit f0b94e
    result = OverrideSystemScrollSpeed(aEvent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Accelerate by the sScrollSeriesCounter
Packit f0b94e
  int32_t start = GetAccelerationStart();
Packit f0b94e
  if (start >= 0 && sScrollSeriesCounter >= start) {
Packit f0b94e
    int32_t factor = GetAccelerationFactor();
Packit f0b94e
    if (factor > 0) {
Packit f0b94e
      result.deltaX = ComputeAcceleratedWheelDelta(result.deltaX, factor);
Packit f0b94e
      result.deltaY = ComputeAcceleratedWheelDelta(result.deltaY, factor);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return result;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ double WheelTransaction::ComputeAcceleratedWheelDelta(
Packit f0b94e
    double aDelta, int32_t aFactor) {
Packit f0b94e
  return mozilla::ComputeAcceleratedWheelDelta(aDelta, sScrollSeriesCounter,
Packit f0b94e
                                               aFactor);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ DeltaValues WheelTransaction::OverrideSystemScrollSpeed(
Packit f0b94e
    WidgetWheelEvent* aEvent) {
Packit f0b94e
  MOZ_ASSERT(sTargetFrame, "We don't have mouse scrolling transaction");
Packit f0b94e
  MOZ_ASSERT(aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
Packit f0b94e
Packit f0b94e
  // If the event doesn't scroll to both X and Y, we don't need to do anything
Packit f0b94e
  // here.
Packit f0b94e
  if (!aEvent->mDeltaX && !aEvent->mDeltaY) {
Packit f0b94e
    return DeltaValues(aEvent);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return DeltaValues(aEvent->OverriddenDeltaX(), aEvent->OverriddenDeltaY());
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::ScrollbarsForWheel                                    */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
const DeltaValues ScrollbarsForWheel::directions[kNumberOfTargets] = {
Packit f0b94e
    DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1),
Packit f0b94e
    DeltaValues(0, +1)};
Packit f0b94e
Packit f0b94e
AutoWeakFrame ScrollbarsForWheel::sActiveOwner = nullptr;
Packit f0b94e
AutoWeakFrame ScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
Packit f0b94e
    nullptr, nullptr, nullptr, nullptr};
Packit f0b94e
Packit f0b94e
bool ScrollbarsForWheel::sHadWheelStart = false;
Packit f0b94e
bool ScrollbarsForWheel::sOwnWheelTransaction = false;
Packit f0b94e
Packit f0b94e
/* static */ void ScrollbarsForWheel::PrepareToScrollText(
Packit f0b94e
    EventStateManager* aESM, nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent) {
Packit f0b94e
  if (aEvent->mMessage == eWheelOperationStart) {
Packit f0b94e
    WheelTransaction::OwnScrollbars(false);
Packit f0b94e
    if (!IsActive()) {
Packit f0b94e
      TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
Packit f0b94e
      sHadWheelStart = true;
Packit f0b94e
    }
Packit f0b94e
  } else {
Packit f0b94e
    DeactivateAllTemporarilyActivatedScrollTargets();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ScrollbarsForWheel::SetActiveScrollTarget(
Packit f0b94e
    nsIScrollableFrame* aScrollTarget) {
Packit f0b94e
  if (!sHadWheelStart) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
  nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(aScrollTarget);
Packit f0b94e
  if (!scrollbarMediator) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
  sHadWheelStart = false;
Packit f0b94e
  sActiveOwner = do_QueryFrame(aScrollTarget);
Packit f0b94e
  scrollbarMediator->ScrollbarActivityStarted();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ScrollbarsForWheel::MayInactivate() {
Packit f0b94e
  if (!sOwnWheelTransaction && WheelTransaction::GetTargetFrame()) {
Packit f0b94e
    WheelTransaction::OwnScrollbars(true);
Packit f0b94e
  } else {
Packit f0b94e
    Inactivate();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ScrollbarsForWheel::Inactivate() {
Packit f0b94e
  nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sActiveOwner);
Packit f0b94e
  if (scrollbarMediator) {
Packit f0b94e
    scrollbarMediator->ScrollbarActivityStopped();
Packit f0b94e
  }
Packit f0b94e
  sActiveOwner = nullptr;
Packit f0b94e
  DeactivateAllTemporarilyActivatedScrollTargets();
Packit f0b94e
  if (sOwnWheelTransaction) {
Packit f0b94e
    sOwnWheelTransaction = false;
Packit f0b94e
    WheelTransaction::OwnScrollbars(false);
Packit f0b94e
    WheelTransaction::EndTransaction();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ bool ScrollbarsForWheel::IsActive() {
Packit f0b94e
  if (sActiveOwner) {
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
  for (size_t i = 0; i < kNumberOfTargets; ++i) {
Packit f0b94e
    if (sActivatedScrollTargets[i]) {
Packit f0b94e
      return true;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void ScrollbarsForWheel::OwnWheelTransaction(bool aOwn) {
Packit f0b94e
  sOwnWheelTransaction = aOwn;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void
Packit f0b94e
ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
Packit f0b94e
    EventStateManager* aESM, nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent) {
Packit f0b94e
  for (size_t i = 0; i < kNumberOfTargets; i++) {
Packit f0b94e
    const DeltaValues* dir = &directions[i];
Packit f0b94e
    AutoWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
Packit f0b94e
    MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
Packit f0b94e
    nsIScrollableFrame* target = do_QueryFrame(aESM->ComputeScrollTarget(
Packit f0b94e
        aTargetFrame, dir->deltaX, dir->deltaY, aEvent,
Packit f0b94e
        EventStateManager::COMPUTE_DEFAULT_ACTION_TARGET));
Packit f0b94e
    nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(target);
Packit f0b94e
    if (scrollbarMediator) {
Packit f0b94e
      nsIFrame* targetFrame = do_QueryFrame(target);
Packit f0b94e
      *scrollTarget = targetFrame;
Packit f0b94e
      scrollbarMediator->ScrollbarActivityStarted();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void
Packit f0b94e
ScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets() {
Packit f0b94e
  for (size_t i = 0; i < kNumberOfTargets; i++) {
Packit f0b94e
    AutoWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
Packit f0b94e
    if (*scrollTarget) {
Packit f0b94e
      nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(*scrollTarget);
Packit f0b94e
      if (scrollbarMediator) {
Packit f0b94e
        scrollbarMediator->ScrollbarActivityStopped();
Packit f0b94e
      }
Packit f0b94e
      *scrollTarget = nullptr;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::WheelTransaction::Prefs                               */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
int32_t WheelTransaction::Prefs::sMouseWheelAccelerationStart = -1;
Packit f0b94e
int32_t WheelTransaction::Prefs::sMouseWheelAccelerationFactor = -1;
Packit f0b94e
uint32_t WheelTransaction::Prefs::sMouseWheelTransactionTimeout = 1500;
Packit f0b94e
uint32_t WheelTransaction::Prefs::sMouseWheelTransactionIgnoreMoveDelay = 100;
Packit f0b94e
bool WheelTransaction::Prefs::sTestMouseScroll = false;
Packit f0b94e
Packit f0b94e
/* static */ void WheelTransaction::Prefs::InitializeStatics() {
Packit f0b94e
  static bool sIsInitialized = false;
Packit f0b94e
  if (!sIsInitialized) {
Packit f0b94e
    Preferences::AddIntVarCache(&sMouseWheelAccelerationStart,
Packit f0b94e
                                "mousewheel.acceleration.start", -1);
Packit f0b94e
    Preferences::AddIntVarCache(&sMouseWheelAccelerationFactor,
Packit f0b94e
                                "mousewheel.acceleration.factor", -1);
Packit f0b94e
    Preferences::AddUintVarCache(&sMouseWheelTransactionTimeout,
Packit f0b94e
                                 "mousewheel.transaction.timeout", 1500);
Packit f0b94e
    Preferences::AddUintVarCache(&sMouseWheelTransactionIgnoreMoveDelay,
Packit f0b94e
                                 "mousewheel.transaction.ignoremovedelay", 100);
Packit f0b94e
    Preferences::AddBoolVarCache(&sTestMouseScroll, "test.mousescroll", false);
Packit f0b94e
    sIsInitialized = true;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************/
Packit f0b94e
/* mozilla::AutoWheelDeltaAdjuster                                */
Packit f0b94e
/******************************************************************/
Packit f0b94e
Packit f0b94e
AutoWheelDeltaAdjuster::AutoWheelDeltaAdjuster(WidgetWheelEvent& aWheelEvent)
Packit f0b94e
    : mWheelEvent(aWheelEvent),
Packit f0b94e
      mOldDeltaX(aWheelEvent.mDeltaX),
Packit f0b94e
      mOldDeltaZ(aWheelEvent.mDeltaZ),
Packit f0b94e
      mOldOverflowDeltaX(aWheelEvent.mOverflowDeltaX),
Packit f0b94e
      mOldLineOrPageDeltaX(aWheelEvent.mLineOrPageDeltaX),
Packit f0b94e
      mTreatedVerticalWheelAsHorizontalScroll(false) {
Packit f0b94e
  MOZ_ASSERT(!aWheelEvent.mDeltaValuesAdjustedForDefaultHandler);
Packit f0b94e
Packit f0b94e
  if (EventStateManager::WheelEventIsHorizontalScrollAction(&aWheelEvent)) {
Packit f0b94e
    // Move deltaY values to deltaX and set both deltaY and deltaZ to 0.
Packit f0b94e
    mWheelEvent.mDeltaX = mWheelEvent.mDeltaY;
Packit f0b94e
    mWheelEvent.mDeltaY = 0.0;
Packit f0b94e
    mWheelEvent.mDeltaZ = 0.0;
Packit f0b94e
    mWheelEvent.mOverflowDeltaX = mWheelEvent.mOverflowDeltaY;
Packit f0b94e
    mWheelEvent.mOverflowDeltaY = 0.0;
Packit f0b94e
    mWheelEvent.mLineOrPageDeltaX = mWheelEvent.mLineOrPageDeltaY;
Packit f0b94e
    mWheelEvent.mLineOrPageDeltaY = 0;
Packit f0b94e
    mWheelEvent.mDeltaValuesAdjustedForDefaultHandler = true;
Packit f0b94e
    mTreatedVerticalWheelAsHorizontalScroll = true;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
AutoWheelDeltaAdjuster::~AutoWheelDeltaAdjuster() {
Packit f0b94e
  if (mTreatedVerticalWheelAsHorizontalScroll &&
Packit f0b94e
      mWheelEvent.mDeltaValuesAdjustedForDefaultHandler) {
Packit f0b94e
    mWheelEvent.mDeltaY = mWheelEvent.mDeltaX;
Packit f0b94e
    mWheelEvent.mDeltaX = mOldDeltaX;
Packit f0b94e
    mWheelEvent.mDeltaZ = mOldDeltaZ;
Packit f0b94e
    mWheelEvent.mOverflowDeltaY = mWheelEvent.mOverflowDeltaX;
Packit f0b94e
    mWheelEvent.mOverflowDeltaX = mOldOverflowDeltaX;
Packit f0b94e
    mWheelEvent.mLineOrPageDeltaY = mWheelEvent.mLineOrPageDeltaX;
Packit f0b94e
    mWheelEvent.mLineOrPageDeltaX = mOldLineOrPageDeltaX;
Packit f0b94e
    mWheelEvent.mDeltaValuesAdjustedForDefaultHandler = false;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace mozilla