// Starts the fling animation. Called both as a response to a fling gesture and as via the
  // public WebView#flingScroll(int, int) API.
  public void flingScroll(int velocityX, int velocityY) {
    final int scrollX = mDelegate.getContainerViewScrollX();
    final int scrollY = mDelegate.getContainerViewScrollY();
    final int rangeX = computeMaximumHorizontalScrollOffset();
    final int rangeY = computeMaximumVerticalScrollOffset();

    mScroller.fling(scrollX, scrollY, velocityX, velocityY, 0, rangeX, 0, rangeY);
    mDelegate.invalidate();
  }
  // Called by the View system as a response to the mDelegate.overScrollContainerViewBy call.
  public void onContainerViewOverScrolled(
      int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    // Clamp the scroll offset at (0, max).
    scrollX = clampHorizontalScroll(scrollX);
    scrollY = clampVerticalScroll(scrollY);

    mDelegate.scrollContainerViewTo(scrollX, scrollY);

    // This is only necessary if the containerView scroll offset ends up being different
    // than the one set from native in which case we want the value stored on the native side
    // to reflect the value stored in the containerView (and not the other way around).
    scrollNativeTo(mDelegate.getContainerViewScrollX(), mDelegate.getContainerViewScrollY());
  }
  private void scrollBy(int deltaX, int deltaY) {
    if (deltaX == 0 && deltaY == 0) return;

    final int scrollX = mDelegate.getContainerViewScrollX();
    final int scrollY = mDelegate.getContainerViewScrollY();
    final int scrollRangeX = computeMaximumHorizontalScrollOffset();
    final int scrollRangeY = computeMaximumVerticalScrollOffset();

    // The android.view.View.overScrollBy method is used for both scrolling and over-scrolling
    // which is why we use it here.
    mDelegate.overScrollContainerViewBy(
        deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mProcessingTouchEvent);
  }
  // Called by the native side to attempt to scroll the container view.
  public void scrollContainerViewTo(int x, int y) {
    mNativeScrollX = x;
    mNativeScrollY = y;

    final int scrollX = mDelegate.getContainerViewScrollX();
    final int scrollY = mDelegate.getContainerViewScrollY();
    final int deltaX = x - scrollX;
    final int deltaY = y - scrollY;
    final int scrollRangeX = computeMaximumHorizontalScrollOffset();
    final int scrollRangeY = computeMaximumVerticalScrollOffset();

    // We use overScrollContainerViewBy to be compatible with WebViewClassic which used this
    // method for handling both over-scroll as well as in-bounds scroll.
    mDelegate.overScrollContainerViewBy(
        deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mProcessingTouchEvent);
  }
  // Called immediately before the draw to update the scroll offset.
  public void computeScrollAndAbsorbGlow(OverScrollGlow overScrollGlow) {
    final boolean stillAnimating = mScroller.computeScrollOffset();
    if (!stillAnimating) return;

    final int oldX = mDelegate.getContainerViewScrollX();
    final int oldY = mDelegate.getContainerViewScrollY();
    int x = mScroller.getCurrX();
    int y = mScroller.getCurrY();

    int rangeX = computeMaximumHorizontalScrollOffset();
    int rangeY = computeMaximumVerticalScrollOffset();

    if (overScrollGlow != null) {
      overScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY, mScroller.getCurrVelocity());
    }

    // The mScroller is configured not to go outside of the scrollable range, so this call
    // should never result in attempting to scroll outside of the scrollable region.
    scrollBy(x - oldX, y - oldY);

    mDelegate.invalidate();
  }
 public int computeHorizontalScrollOffset() {
   return mDelegate.getContainerViewScrollX();
 }
 public void syncScrollOffsetFromOnDraw() {
   // Unfortunately apps override onScrollChanged without calling super which is why we need
   // to sync the scroll offset on every onDraw.
   onContainerViewScrollChanged(
       mDelegate.getContainerViewScrollX(), mDelegate.getContainerViewScrollY());
 }