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 } 37 38 // This class scrolls a page from the top to the bottom once. 39 // 40 // The page is scrolled down by a single scroll gesture. 41 function ScrollAction(opt_callback, opt_distance_func) { 42 var self = this; 43 44 this.beginMeasuringHook = function() {}; 45 this.endMeasuringHook = function() {}; 46 47 this.callback_ = opt_callback; 48 this.distance_func_ = opt_distance_func; 49 } 50 51 ScrollAction.prototype.getScrollDistanceDown_ = function() { 52 var clientHeight; 53 // clientHeight is "special" for the body element. 54 if (this.element_ == document.body) 55 clientHeight = window.innerHeight; 56 else 57 clientHeight = this.element_.clientHeight; 58 59 return this.element_.scrollHeight - 60 this.element_.scrollTop - 61 clientHeight; 62 }; 63 64 ScrollAction.prototype.getScrollDistanceUp_ = function() { 65 return this.element_.scrollTop; 66 }; 67 68 ScrollAction.prototype.getScrollDistanceRight_ = function() { 69 var clientWidth; 70 // clientWidth is "special" for the body element. 71 if (this.element_ == document.body) 72 clientWidth = window.innerWidth; 73 else 74 clientWidth = this.element_.clientWidth; 75 76 return this.element_.scrollWidth - this.element_.scrollLeft - clientWidth; 77 }; 78 79 ScrollAction.prototype.getScrollDistanceLeft_ = function() { 80 return this.element_.scrollLeft; 81 }; 82 83 ScrollAction.prototype.getScrollDistance_ = function() { 84 if (this.distance_func_) 85 return this.distance_func_(); 86 87 if (this.options_.direction_ == 'down') { 88 return this.getScrollDistanceDown_(); 89 } else if (this.options_.direction_ == 'up') { 90 return this.getScrollDistanceUp_(); 91 } else if (this.options_.direction_ == 'right') { 92 return this.getScrollDistanceRight_(); 93 } else if (this.options_.direction_ == 'left') { 94 return this.getScrollDistanceLeft_(); 95 } else if (this.options_.direction_ == 'upleft') { 96 return Math.min(this.getScrollDistanceUp_(), 97 this.getScrollDistanceLeft_()); 98 } else if (this.options_.direction_ == 'upright') { 99 return Math.min(this.getScrollDistanceUp_(), 100 this.getScrollDistanceRight_()); 101 } else if (this.options_.direction_ == 'downleft') { 102 return Math.min(this.getScrollDistanceDown_(), 103 this.getScrollDistanceLeft_()); 104 } else if (this.options_.direction_ == 'downright') { 105 return Math.min(this.getScrollDistanceDown_(), 106 this.getScrollDistanceRight_()); 107 } 108 }; 109 110 ScrollAction.prototype.start = function(opt_options) { 111 this.options_ = new ScrollGestureOptions(opt_options); 112 // Assign this.element_ here instead of constructor, because the constructor 113 // ensures this method will be called after the document is loaded. 114 this.element_ = this.options_.element_; 115 requestAnimationFrame(this.startGesture_.bind(this)); 116 }; 117 118 ScrollAction.prototype.startGesture_ = function() { 119 this.beginMeasuringHook(); 120 121 var max_scroll_length_pixels = (MAX_SCROLL_LENGTH_TIME_MS / 1000) * 122 this.options_.speed_; 123 var distance = Math.min(max_scroll_length_pixels, 124 this.getScrollDistance_()); 125 126 var rect = __GestureCommon_GetBoundingVisibleRect(this.options_.element_); 127 var start_left = 128 rect.left + rect.width * this.options_.left_start_ratio_; 129 var start_top = 130 rect.top + rect.height * this.options_.top_start_ratio_; 131 chrome.gpuBenchmarking.smoothScrollBy( 132 distance, this.onGestureComplete_.bind(this), start_left, start_top, 133 this.options_.gesture_source_type_, this.options_.direction_, 134 this.options_.speed_); 135 }; 136 137 ScrollAction.prototype.onGestureComplete_ = function() { 138 this.endMeasuringHook(); 139 140 // We're done. 141 if (this.callback_) 142 this.callback_(); 143 }; 144 145 window.__ScrollAction = ScrollAction; 146 window.__ScrollAction_SupportedByBrowser = supportedByBrowser; 147})(); 148