- add sources.
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / page / actions / scroll.js
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.
4
5 // This file provides the ScrollAction object, which scrolls a page
6 // from top to bottom:
7 //   1. var action = new __ScrollAction(callback)
8 //   2. action.start(scroll_options)
9 'use strict';
10
11 (function() {
12   var MAX_SCROLL_LENGTH_PIXELS = 5000;
13
14   function ScrollGestureOptions(opt_options) {
15     if (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;
19     } else {
20       this.element_ = document.body;
21       this.left_start_percentage_ = 0.5;
22       this.top_start_percentage_ = 0.5;
23     }
24   }
25
26   function supportedByBrowser() {
27     return !!(window.chrome &&
28               chrome.gpuBenchmarking &&
29               chrome.gpuBenchmarking.smoothScrollBy);
30   }
31
32   /**
33    * Scrolls a given element down a certain amount to emulate user scroll.
34    * Uses smooth scroll capabilities provided by the platform, if available.
35    * @constructor
36    */
37   function SmoothScrollDownGesture(options) {
38     this.options_ = options;
39   };
40
41   function min(a, b) {
42     if (a > b) {
43       return b;
44     }
45     return a;
46   };
47
48   function getBoundingVisibleRect(el) {
49     var bound = el.getBoundingClientRect();
50     var rect = { top: bound.top,
51                  left: bound.left,
52                  width: bound.width,
53                  height: bound.height };
54     var outsideHeight = (rect.top + rect.height) - window.innerHeight;
55     var outsideWidth = (rect.left + rect.width) - window.innerWidth;
56
57     if (outsideHeight > 0) {
58       rect.height -= outsideHeight;
59     }
60     if (outsideWidth > 0) {
61       rect.width -= outsideWidth;
62     }
63     return rect;
64   };
65
66   SmoothScrollDownGesture.prototype.start = function(distance, callback) {
67     this.callback_ = callback;
68
69     var rect = getBoundingVisibleRect(this.options_.element_);
70     var start_left =
71         rect.left + rect.width * this.options_.left_start_percentage_;
72     var start_top =
73         rect.top + rect.height * this.options_.top_start_percentage_;
74     chrome.gpuBenchmarking.smoothScrollBy(distance, function() {
75       callback();
76     }, start_left, start_top);
77   };
78
79   // This class scrolls a page from the top to the bottom once.
80   //
81   // The page is scrolled down by a single scroll gesture.
82   function ScrollAction(opt_callback, opt_remaining_distance_func) {
83     var self = this;
84
85     this.beginMeasuringHook = function() {}
86     this.endMeasuringHook = function() {}
87
88     this.callback_ = opt_callback;
89     this.remaining_distance_func_ = opt_remaining_distance_func;
90   }
91
92   ScrollAction.prototype.getRemainingScrollDistance_ = function() {
93     if (this.remaining_distance_func_)
94       return this.remaining_distance_func_();
95
96     var clientHeight;
97     // clientHeight is "special" for the body element.
98     if (this.element_ == document.body)
99       clientHeight = window.innerHeight;
100     else
101       clientHeight = this.element_.clientHeight;
102
103     return this.scrollHeight_ - this.element_.scrollTop - clientHeight;
104   }
105
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));
117   };
118
119   ScrollAction.prototype.startPass_ = function() {
120     this.element_.scrollTop = 0;
121
122     this.beginMeasuringHook();
123
124     this.gesture_ = new SmoothScrollDownGesture(this.options_);
125     this.gesture_.start(this.getRemainingScrollDistance_(),
126                         this.onGestureComplete_.bind(this));
127   };
128
129   ScrollAction.prototype.onGestureComplete_ = function() {
130     this.endMeasuringHook();
131
132     // We're done.
133     if (this.callback_)
134       this.callback_();
135   };
136
137   window.__ScrollAction = ScrollAction;
138   window.__ScrollAction_GetBoundingVisibleRect = getBoundingVisibleRect;
139   window.__ScrollAction_SupportedByBrowser = supportedByBrowser;
140 })();