     activatedElement ||= document.body
     return unless activatedElement
 
-    element = findScrollableElement activatedElement, direction, amount, factor
-    elementAmount = factor * getDimension element, direction, amount
-    CoreScroller.scroll element, direction, elementAmount
+    # Avoid the expensive scroll calculation if it will not be used.  This reduces costs during smooth,
+    # continuous scrolls, and is just an optimization.
+    unless CoreScroller.wouldNotInitiateScroll()
+      element = findScrollableElement activatedElement, direction, amount, factor
+      elementAmount = factor * getDimension element, direction, amount
+      CoreScroller.scroll element, direction, elementAmount
 
   scrollTo: (direction, pos) ->
     return unless document.body or activatedElement
     activatedElement ||= document.body
 
-    element = findScrollableElement activatedElement, direction, pos
+    element = findScrollableElement activatedElement, direction, pos, 1
     amount = getDimension(element,direction,pos) - element[scrollProperties[direction].axisName]
     CoreScroller.scroll element, direction, amount
 

      checkVisibility element
      return

    # We don't activate new animators on keyboard repeats.
    return if @lastEvent?.repeat

    activationTime = ++@time
    isMyKeyStillDown = => @time == activationTime and @keyIsDown

    # Store amount's sign and make amount positive; the logic is clearer when amount is positive.
    sign = Math.sign amount
    amount = Math.abs amount

    # Duration in ms. Allow a bit longer for longer scrolls.
    duration = Math.max 100, 20 * Math.log amount

    totalDelta = 0
    totalElapsed = 0.0
    calibration = 1.0
    previousTimestamp = null
    animatorId = null

    advanceAnimation = -> animatorId = requestAnimationFrame animate
    cancelAnimation = -> cancelAnimationFrame animatorId

    animate = (timestamp) =>
      previousTimestamp ?= timestamp
      return advanceAnimation() if timestamp == previousTimestamp

      # The elapsed time is typically about 16ms.
      elapsed = timestamp - previousTimestamp

# Test whether element should be scrolled.
shouldScroll = (element, direction) ->
  computedStyle = window.getComputedStyle(element)
  # Elements with `overflow: hidden` must not be scrolled.
  return false if computedStyle.getPropertyValue("overflow-#{direction}") == "hidden"
  # Elements which are not visible should not be scrolled.
  return false if computedStyle.getPropertyValue("visibility") in ["hidden", "collapse"]
  return false if computedStyle.getPropertyValue("display") == "none"
  true

# Test whether element does actually scroll in the direction required when asked to do so.  Due to chrome bug
# 110149, scrollHeight and clientHeight cannot be used to reliably determine whether an element will scroll.
# Instead, we scroll the element by 1 or -1 and see if it moved (then put it back).
# Bug verified in Chrome 38.0.2125.104.
doesScroll = (element, direction, amount, factor) ->
  # amount is treated as a relative amount, which is correct for relative scrolls. For absolute scrolls (only
  # gg, G, and friends), amount can be either 'max' or zero. In the former case, we're definitely scrolling
  # forwards, so any positive value will do for delta.  In the latter, we're definitely scrolling backwards,
  # so a delta of -1 will do.  For absolute scrolls, factor is always 1.
  delta = factor * getDimension(element, direction, amount) || -1
  delta = Math.sign delta # 1 or -1
  performScroll(element, direction, delta) and performScroll(element, direction, -delta)

# From element and its parents, find the first which we should scroll and which does scroll.
findScrollableElement = (element, direction, amount, factor) ->
  while element != document.body and
    not (doesScroll(element, direction, amount, factor) and shouldScroll(element, direction))
      element = element.parentElement || document.body
  element

checkVisibility = (element) ->
  # If the activated element has been scrolled completely offscreen, then subsequent changes in its scroll
  # position will not provide any more visual feedback to the user. Therefore, we deactivate it so that
  # subsequent scrolls affect the parent element.
  rect = activatedElement.getBoundingClientRect()
  if (rect.bottom < 0 || rect.top > window.innerHeight || rect.right < 0 || rect.left > window.innerWidth)
    activatedElement = element

# How scrolling is handled by CoreScroller.
#   - For jump scrolling, the entire scroll happens immediately.
#   - For smooth scrolling with distinct key presses, a separate animator is initiated for each key press.
#     Therefore, several animators may be active at the same time.  This ensures that two quick taps on `j`
#     scroll to the same position as two slower taps.
#   - For smooth scrolling with keyboard repeat (continuous scrolling), the most recently-activated animator
#     continues scrolling at least until its keyup event is received.  We never initiate a new animator on
#     keyboard repeat.

CoreScroller =
  init: (frontendSettings) ->
