1 // Copyright (c) 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.
5 // This file provides the ScrollAction object, which scrolls a page
7 // 1. var action = new __ScrollAction(callback)
8 // 2. action.start(scroll_options)
12 var MAX_SCROLL_LENGTH_PIXELS = 5000;
14 function ScrollGestureOptions(opt_options) {
16 this.element_ = opt_options.element;
17 this.left_start_percentage_ = opt_options.left_start_percentage;
18 this.top_start_percentage_ = opt_options.top_start_percentage;
20 this.element_ = document.body;
21 this.left_start_percentage_ = 0.5;
22 this.top_start_percentage_ = 0.5;
26 function supportedByBrowser() {
27 return !!(window.chrome &&
28 chrome.gpuBenchmarking &&
29 chrome.gpuBenchmarking.smoothScrollBy);
33 * Scrolls a given element down a certain amount to emulate user scroll.
34 * Uses smooth scroll capabilities provided by the platform, if available.
37 function SmoothScrollDownGesture(options) {
38 this.options_ = options;
48 function getBoundingVisibleRect(el) {
49 var bound = el.getBoundingClientRect();
50 var rect = { top: bound.top,
53 height: bound.height };
54 var outsideHeight = (rect.top + rect.height) - window.innerHeight;
55 var outsideWidth = (rect.left + rect.width) - window.innerWidth;
57 if (outsideHeight > 0) {
58 rect.height -= outsideHeight;
60 if (outsideWidth > 0) {
61 rect.width -= outsideWidth;
66 SmoothScrollDownGesture.prototype.start = function(distance, callback) {
67 this.callback_ = callback;
69 var rect = getBoundingVisibleRect(this.options_.element_);
71 rect.left + rect.width * this.options_.left_start_percentage_;
73 rect.top + rect.height * this.options_.top_start_percentage_;
74 chrome.gpuBenchmarking.smoothScrollBy(distance, function() {
76 }, start_left, start_top);
79 // This class scrolls a page from the top to the bottom once.
81 // The page is scrolled down by a single scroll gesture.
82 function ScrollAction(opt_callback, opt_remaining_distance_func) {
85 this.beginMeasuringHook = function() {}
86 this.endMeasuringHook = function() {}
88 this.callback_ = opt_callback;
89 this.remaining_distance_func_ = opt_remaining_distance_func;
92 ScrollAction.prototype.getRemainingScrollDistance_ = function() {
93 if (this.remaining_distance_func_)
94 return this.remaining_distance_func_();
97 // clientHeight is "special" for the body element.
98 if (this.element_ == document.body)
99 clientHeight = window.innerHeight;
101 clientHeight = this.element_.clientHeight;
103 return this.scrollHeight_ - this.element_.scrollTop - clientHeight;
106 ScrollAction.prototype.start = function(opt_options) {
107 this.options_ = new ScrollGestureOptions(opt_options);
108 // Assign this.element_ here instead of constructor, because the constructor
109 // ensures this method will be called after the document is loaded.
110 this.element_ = this.options_.element_;
111 // Some pages load more content when you scroll to the bottom. Record
112 // the original element height here and only scroll to that point.
113 // -1 to allow for rounding errors on scaled viewports (like mobile).
114 this.scrollHeight_ = Math.min(MAX_SCROLL_LENGTH_PIXELS,
115 this.element_.scrollHeight - 1);
116 requestAnimationFrame(this.startPass_.bind(this));
119 ScrollAction.prototype.startPass_ = function() {
120 this.element_.scrollTop = 0;
122 this.beginMeasuringHook();
124 this.gesture_ = new SmoothScrollDownGesture(this.options_);
125 this.gesture_.start(this.getRemainingScrollDistance_(),
126 this.onGestureComplete_.bind(this));
129 ScrollAction.prototype.onGestureComplete_ = function() {
130 this.endMeasuringHook();
137 window.__ScrollAction = ScrollAction;
138 window.__ScrollAction_GetBoundingVisibleRect = getBoundingVisibleRect;
139 window.__ScrollAction_SupportedByBrowser = supportedByBrowser;