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