• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file provides the ScrollAction object, which scrolls a page
6// to the bottom or for a specified distance:
7//   1. var action = new __ScrollAction(callback, opt_distance_func)
8//   2. action.start(scroll_options)
9'use strict';
10
11(function() {
12  var MAX_SCROLL_LENGTH_TIME_MS = 6250;
13
14  function ScrollGestureOptions(opt_options) {
15    if (opt_options) {
16      this.element_ = opt_options.element;
17      this.left_start_ratio_ = opt_options.left_start_ratio;
18      this.top_start_ratio_ = opt_options.top_start_ratio;
19      this.direction_ = opt_options.direction;
20      this.speed_ = opt_options.speed;
21      this.gesture_source_type_ = opt_options.gesture_source_type;
22    } else {
23      this.element_ = document.scrollingElement || document.body;
24      this.left_start_ratio_ = 0.5;
25      this.top_start_ratio_ = 0.5;
26      this.direction_ = 'down';
27      this.speed_ = 800;
28      this.gesture_source_type_ = chrome.gpuBenchmarking.DEFAULT_INPUT;
29    }
30  }
31
32  function supportedByBrowser() {
33    return !!(window.chrome &&
34              chrome.gpuBenchmarking &&
35              chrome.gpuBenchmarking.smoothScrollBy &&
36              chrome.gpuBenchmarking.visualViewportHeight &&
37              chrome.gpuBenchmarking.visualViewportWidth);
38  }
39
40  // This class scrolls a page from the top to the bottom once.
41  //
42  // The page is scrolled down by a single scroll gesture.
43  function ScrollAction(opt_callback, opt_distance_func) {
44    var self = this;
45
46    this.beginMeasuringHook = function() {};
47    this.endMeasuringHook = function() {};
48
49    this.callback_ = opt_callback;
50    this.distance_func_ = opt_distance_func;
51  }
52
53  ScrollAction.prototype.getScrollDistanceDown_ = function() {
54    var clientHeight;
55    // clientHeight is "special" for the body element.
56    if (this.element_ == document.body)
57      clientHeight = __GestureCommon_GetWindowHeight();
58    else
59      clientHeight = this.element_.clientHeight;
60
61    return this.element_.scrollHeight -
62           this.element_.scrollTop -
63           clientHeight;
64  };
65
66  ScrollAction.prototype.getScrollDistanceUp_ = function() {
67    return this.element_.scrollTop;
68  };
69
70  ScrollAction.prototype.getScrollDistanceRight_ = function() {
71    var clientWidth;
72    // clientWidth is "special" for the body element.
73    if (this.element_ == document.body)
74      clientWidth = __GestureCommon_GetWindowWidth();
75    else
76      clientWidth = this.element_.clientWidth;
77
78    return this.element_.scrollWidth - this.element_.scrollLeft - clientWidth;
79  };
80
81  ScrollAction.prototype.getScrollDistanceLeft_ = function() {
82    return this.element_.scrollLeft;
83  };
84
85  ScrollAction.prototype.getScrollDistance_ = function() {
86    if (this.distance_func_)
87      return this.distance_func_();
88
89    if (this.options_.direction_ == 'down') {
90      return this.getScrollDistanceDown_();
91    } else if (this.options_.direction_ == 'up') {
92      return this.getScrollDistanceUp_();
93    } else if (this.options_.direction_ == 'right') {
94      return this.getScrollDistanceRight_();
95    } else if (this.options_.direction_ == 'left') {
96      return this.getScrollDistanceLeft_();
97    } else if (this.options_.direction_ == 'upleft') {
98      return Math.min(this.getScrollDistanceUp_(),
99                      this.getScrollDistanceLeft_());
100    } else if (this.options_.direction_ == 'upright') {
101      return Math.min(this.getScrollDistanceUp_(),
102                      this.getScrollDistanceRight_());
103    } else if (this.options_.direction_ == 'downleft') {
104      return Math.min(this.getScrollDistanceDown_(),
105                      this.getScrollDistanceLeft_());
106    } else if (this.options_.direction_ == 'downright') {
107      return Math.min(this.getScrollDistanceDown_(),
108                      this.getScrollDistanceRight_());
109    }
110  };
111
112  ScrollAction.prototype.start = function(opt_options) {
113    this.options_ = new ScrollGestureOptions(opt_options);
114    // Assign this.element_ here instead of constructor, because the constructor
115    // ensures this method will be called after the document is loaded.
116    this.element_ = this.options_.element_;
117    requestAnimationFrame(this.startGesture_.bind(this));
118  };
119
120  ScrollAction.prototype.startGesture_ = function() {
121    this.beginMeasuringHook();
122
123    var max_scroll_length_pixels = (MAX_SCROLL_LENGTH_TIME_MS / 1000) *
124        this.options_.speed_;
125    var distance = Math.min(max_scroll_length_pixels,
126                            this.getScrollDistance_());
127
128    var rect = __GestureCommon_GetBoundingVisibleRect(this.options_.element_);
129    var start_left =
130        rect.left + rect.width * this.options_.left_start_ratio_;
131    var start_top =
132        rect.top + rect.height * this.options_.top_start_ratio_;
133    chrome.gpuBenchmarking.smoothScrollBy(
134        distance, this.onGestureComplete_.bind(this), start_left, start_top,
135        this.options_.gesture_source_type_, this.options_.direction_,
136        this.options_.speed_);
137  };
138
139  ScrollAction.prototype.onGestureComplete_ = function() {
140    this.endMeasuringHook();
141
142    // We're done.
143    if (this.callback_)
144      this.callback_();
145  };
146
147  window.__ScrollAction = ScrollAction;
148  window.__ScrollAction_SupportedByBrowser = supportedByBrowser;
149})();
150