Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Perform various "gestures" and calculate average frame rate. | 6 * @fileoverview Perform various "gestures" and calculate average frame rate. |
| 7 * "Gestures" are recorded scrolling behaviors in terms of time (ms) and | 7 * "Gestures" are recorded scrolling behaviors in terms of time (ms) and |
| 8 * absolute positions. | 8 * absolute positions. |
| 9 * | 9 * |
| 10 * How to run a single gesture: | 10 * How to run a single gesture: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 * new_gesture_name: [ | 31 * new_gesture_name: [ |
| 32 * {"time_ms":1, "y":0}, | 32 * {"time_ms":1, "y":0}, |
| 33 * ... pasted output ... | 33 * ... pasted output ... |
| 34 * ], | 34 * ], |
| 35 */ | 35 */ |
| 36 | 36 |
| 37 var __running = false; | 37 var __running = false; |
| 38 var __running_all = false; | 38 var __running_all = false; |
| 39 var __old_title = ""; | 39 var __old_title = ""; |
| 40 var __raf_is_live = false; | 40 var __raf_is_live = false; |
| 41 var __platform_raf; | |
| 41 var __raf; | 42 var __raf; |
| 42 | 43 |
| 43 var __t_last; | 44 var __t_last; |
| 44 var __t_est; | 45 var __t_est; |
| 45 var __t_est_total; | 46 var __t_est_total; |
| 46 var __t_est_squared_total; | 47 var __t_est_squared_total; |
| 47 var __t_count; | 48 var __t_count; |
| 48 var __t_start; | 49 var __t_start; |
| 49 | 50 |
| 50 var __queued_gesture_functions; | 51 var __queued_gesture_functions; |
| 51 var __results; | 52 var __results; |
| 52 | 53 |
| 53 var __recording = []; | 54 var __recording = []; |
| 54 var __advance_gesture; | 55 var __advance_gesture; |
| 55 var __gestures = { | 56 var __animation = function() {return false;} |
| 56 none: [ | 57 |
| 58 var __gesture_library = { | |
| 59 init: [ | |
| 60 {"time_ms":1, "y":0}, | |
| 61 {"time_ms":5, "y":10} | |
| 62 ], | |
| 63 stationary: [ | |
| 57 {"time_ms":1, "y":0}, | 64 {"time_ms":1, "y":0}, |
| 58 {"time_ms":5000, "y":0} | 65 {"time_ms":5000, "y":0} |
| 59 ], | 66 ], |
| 60 steady: [ | |
| 61 {"time_ms":1, "y":0}, | |
| 62 {"time_ms":5, "y":10} | |
| 63 ], | |
| 64 reading: [ | 67 reading: [ |
| 65 {"time_ms":1, "y":0}, | 68 {"time_ms":1, "y":0}, |
| 66 {"time_ms":842, "y":40}, | 69 {"time_ms":842, "y":40}, |
| 67 {"time_ms":858, "y":67}, | 70 {"time_ms":858, "y":67}, |
| 68 {"time_ms":874, "y":94}, | 71 {"time_ms":874, "y":94}, |
| 69 {"time_ms":890, "y":149}, | 72 {"time_ms":890, "y":149}, |
| 70 {"time_ms":907, "y":203}, | 73 {"time_ms":907, "y":203}, |
| 71 {"time_ms":923, "y":257}, | 74 {"time_ms":923, "y":257}, |
| 72 {"time_ms":939, "y":311}, | 75 {"time_ms":939, "y":311}, |
| 73 {"time_ms":955, "y":393}, | 76 {"time_ms":955, "y":393}, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 {"time_ms":911, "y":1273}, | 157 {"time_ms":911, "y":1273}, |
| 155 {"time_ms":941, "y":1275}, | 158 {"time_ms":941, "y":1275}, |
| 156 {"time_ms":958, "y":1282}, | 159 {"time_ms":958, "y":1282}, |
| 157 {"time_ms":976, "y":1288}, | 160 {"time_ms":976, "y":1288}, |
| 158 {"time_ms":993, "y":1291}, | 161 {"time_ms":993, "y":1291}, |
| 159 {"time_ms":1022, "y":1294}, | 162 {"time_ms":1022, "y":1294}, |
| 160 {"time_ms":1055, "y":1302} | 163 {"time_ms":1055, "y":1302} |
| 161 ], | 164 ], |
| 162 }; | 165 }; |
| 163 | 166 |
| 167 // Creat an alternate version of a gesture that | |
| 168 // runs without using requestAnimationFrame | |
| 169 function __gesture_disable_raf(gesture) { | |
| 170 // clone the gesture | |
| 171 var new_gesture = JSON.parse(JSON.stringify(gesture)); | |
| 172 new_gesture[0].raf = false; | |
| 173 return new_gesture; | |
| 174 } | |
| 175 | |
| 176 // Stretch the duration of a gesture by a given factor | |
| 177 function __gesture_stretch(gesture, stretch_factor) { | |
| 178 // clone the gesture | |
| 179 var new_gesture = JSON.parse(JSON.stringify(gesture)); | |
| 180 for (var i = 0; i < new_gesture.length; ++i) { | |
| 181 new_gesture[i].time_ms *= stretch_factor; | |
| 182 } | |
| 183 return new_gesture; | |
| 184 } | |
| 185 | |
| 186 | |
| 187 // Gesture set to use for testing, initialized with default gesture set. | |
| 188 // Redefine in test file to use a different set of gestures. | |
| 189 var __gestures = { | |
| 190 none: __gesture_library["stationary"], | |
| 191 steady: __gesture_library["init"], | |
| 192 reading: __gesture_library["reading"], | |
| 193 mouse_wheel: __gesture_library["mouse_wheel"], | |
| 194 mac_fling: __gesture_library["mac_fling"], | |
| 195 }; | |
| 196 | |
| 164 function __init_stats() { | 197 function __init_stats() { |
| 165 __t_last = undefined; | 198 __t_last = undefined; |
| 166 __t_est = undefined; | 199 __t_est = undefined; |
| 167 __t_est_total = 0; | 200 __t_est_total = 0; |
| 168 __t_est_squared_total = 0; | 201 __t_est_squared_total = 0; |
| 169 __t_count = 0; | 202 __t_count = 0; |
| 170 } | 203 } |
| 171 __init_stats(); | 204 __init_stats(); |
| 172 | 205 |
| 206 function __init_raf(use_raf) { | |
| 207 if (use_raf) { | |
| 208 if (!__platform_raf) { | |
| 209 if ("requestAnimationFrame" in window) | |
|
nduca
2011/10/10 23:11:19
Nice!
| |
| 210 __platform_raf = requestAnimationFrame; | |
| 211 else if ("webkitRequestAnimationFrame" in window) | |
| 212 __platform_raf = webkitRequestAnimationFrame; | |
| 213 else if ("mozRequestAnimationFrame" in window) | |
| 214 __platform_raf = mozRequestAnimationFrame; | |
| 215 else if ("oRequestAnimationFrame" in window) | |
| 216 __platform_raf = oRequestAnimationFrame; | |
| 217 else if ("msRequestAnimationFrame" in window) | |
| 218 __platform_raf = msRequestAnimationFrame; | |
| 219 else | |
| 220 // No raf implementation available, fake it with 16ms timeouts | |
| 221 __platform_raf = function(callback, element) { | |
| 222 setTimeout(callback, 16); | |
| 223 } | |
| 224 } | |
| 225 __raf = __platform_raf; | |
| 226 } | |
| 227 else { | |
| 228 // raf disabled: Using a 0ms timeout to render as fast as possible | |
| 229 __raf = function(callback, element) { | |
| 230 setTimeout(callback,0); | |
| 231 } | |
| 232 } | |
| 233 } | |
| 234 __init_raf(true); | |
|
nduca
2011/10/10 23:11:19
Init raf here? Really?
| |
| 235 | |
| 173 function __calc_results() { | 236 function __calc_results() { |
| 174 var M = __t_est_total / __t_count; | 237 var M = __t_est_total / __t_count; |
| 175 var X = __t_est_squared_total / __t_count; | 238 var X = __t_est_squared_total / __t_count; |
| 176 var V = X - M * M; | 239 var V = X - M * M; |
| 177 var S = Math.sqrt(V); | 240 var S = Math.sqrt(V); |
| 178 | 241 |
| 179 var R = new Object(); | 242 var R = new Object(); |
| 180 R.mean = 1000.0 / M; | 243 R.mean = 1000.0 / M; |
| 181 R.sigma = R.mean - 1000.0 / (M + S); | 244 R.sigma = R.mean - 1000.0 / (M + S); |
| 182 return R; | 245 return R; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 if (delta == 0) | 325 if (delta == 0) |
| 263 return false; | 326 return false; |
| 264 window.scrollBy(0, delta); | 327 window.scrollBy(0, delta); |
| 265 window.__scrolledTo = yfloor; | 328 window.__scrolledTo = yfloor; |
| 266 return true; | 329 return true; |
| 267 } | 330 } |
| 268 | 331 |
| 269 // Returns true if a gesture movement occured. | 332 // Returns true if a gesture movement occured. |
| 270 function __create_gesture_function(gestures) { | 333 function __create_gesture_function(gestures) { |
| 271 var i0 = 0; | 334 var i0 = 0; |
| 335 var use_raf = true; | |
|
nduca
2011/10/10 23:11:19
Did you consider doing this feature outside of the
| |
| 272 return function() { | 336 return function() { |
| 273 if (i0 >= gestures.length) { | 337 if (i0 >= gestures.length) { |
| 274 __stop(); | 338 __stop(); |
| 275 return false; | 339 return false; |
| 276 } | 340 } |
| 277 var time_cur = new Date().getTime() - __t_start; | 341 var time_cur = new Date().getTime() - __t_start; |
| 278 if (time_cur <= gestures[i0].time_ms) | 342 if (time_cur <= gestures[i0].time_ms) |
| 279 return false; | 343 return false; |
| 280 | 344 |
| 281 // Skip any keyframes that we missed | 345 // Skip any keyframes that we missed and track changes to raf state |
| 282 for (i0; i0 < gestures.length && gestures[i0].time_ms < time_cur; ++i0); | 346 var new_use_raf = use_raf; |
| 347 for (i0; i0 < gestures.length && gestures[i0].time_ms < time_cur; ++i0) { | |
| 348 if ("raf" in gestures[i0]) { | |
| 349 new_use_raf = gestures[i0].raf; | |
| 350 } | |
| 351 } | |
| 283 | 352 |
| 284 // This loop overshoots by 1, so move back in time by 1 | 353 // This loop overshoots by 1, so move back in time by 1 |
| 285 i0--; | 354 i0--; |
| 286 var i1 = i0 + 1; | 355 var i1 = i0 + 1; |
| 287 | 356 |
| 357 // Toggle usage of request animantion frame | |
|
nduca
2011/10/10 23:11:19
I'm struggling to understand this code... and the
| |
| 358 if (new_use_raf != use_raf){ | |
| 359 use_raf = new_use_raf; | |
| 360 __init_raf(use_raf); | |
| 361 } | |
| 362 | |
| 288 if (i1 < gestures.length) { | 363 if (i1 < gestures.length) { |
| 289 // If i1 exists, interpolate between i0 and i1 y based on time_cur - | 364 // If i1 exists, interpolate between i0 and i1 y based on time_cur - |
| 290 // gestures[i0].time_ms | 365 // gestures[i0].time_ms |
| 291 var time_since_i0_start = time_cur - gestures[i0].time_ms; | 366 var time_since_i0_start = time_cur - gestures[i0].time_ms; |
| 292 var time_between_i0_and_i1 = gestures[i1].time_ms - | 367 var time_between_i0_and_i1 = gestures[i1].time_ms - |
| 293 gestures[i0].time_ms; | 368 gestures[i0].time_ms; |
| 294 var percent_into_frame = time_since_i0_start / time_between_i0_and_i1; | 369 var percent_into_frame = time_since_i0_start / time_between_i0_and_i1; |
| 295 var y_diff_between_i0_and_i1 = gestures[i1].y - gestures[i0].y; | 370 var y_diff_between_i0_and_i1 = gestures[i1].y - gestures[i0].y; |
| 296 var interpolated_y = gestures[i0].y + | 371 var interpolated_y = gestures[i0].y + |
| 297 (percent_into_frame * y_diff_between_i0_and_i1); | 372 (percent_into_frame * y_diff_between_i0_and_i1); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 321 y = gestures[i].y + dy; | 396 y = gestures[i].y + dy; |
| 322 gestures.push({ | 397 gestures.push({ |
| 323 time_ms: gestures[i].time_ms + dtime_ms, | 398 time_ms: gestures[i].time_ms + dtime_ms, |
| 324 y: y, | 399 y: y, |
| 325 }); | 400 }); |
| 326 } | 401 } |
| 327 return __create_gesture_function(gestures); | 402 return __create_gesture_function(gestures); |
| 328 } | 403 } |
| 329 | 404 |
| 330 function __sched_update() { | 405 function __sched_update() { |
| 331 if (!__raf) { | |
| 332 if ("webkitRequestAnimationFrame" in window) | |
| 333 __raf = webkitRequestAnimationFrame; | |
| 334 else if ("mozRequestAnimationFrame" in window) | |
| 335 __raf = mozRequestAnimationFrame; | |
| 336 } | |
| 337 __raf(function() { | 406 __raf(function() { |
| 338 __raf_is_live = true; | 407 __raf_is_live = true; |
| 408 // In case __raf falls back to using setTimeout, we must schedule the next | |
| 409 // update before rendering the current update to help maintain the | |
| 410 // regularity of update intervals. | |
| 411 __sched_update(); | |
| 339 if (__running) { | 412 if (__running) { |
| 340 // Only update the FPS if a gesture movement occurs. Otherwise, the frame | 413 // Only update the FPS if a gesture movement or animation occurs. |
| 341 // rate average becomes inaccurate after any pause. | 414 // Otherwise, the frame rate average becomes inaccurate after any pause. |
| 342 if (__advance_gesture()) | 415 var animated = __animation(); |
|
nduca
2011/10/10 23:11:19
Is there any merit to this rather than just having
| |
| 416 if (__advance_gesture() || animated) | |
| 343 __update_fps(); | 417 __update_fps(); |
| 344 else | 418 else |
| 345 __t_last = new Date().getTime(); | 419 __t_last = new Date().getTime(); |
| 346 } | 420 } |
| 347 __sched_update(); | |
| 348 }, document.body); | 421 }, document.body); |
| 349 } | 422 } |
| 350 | 423 |
| 351 function __start_recording() { | 424 function __start_recording() { |
| 352 __start(__advance_gesture_recording); | 425 __start(__advance_gesture_recording); |
| 353 } | 426 } |
| 354 | 427 |
| 355 function __make_body_composited() { | 428 function __make_body_composited() { |
| 356 document.body.style.webkitTransform = "translateZ(0)"; | 429 document.body.style.webkitTransform = "translateZ(0)"; |
| 357 } | 430 } |
| 358 | 431 |
| 359 function __start(gesture_function) { | 432 function __start(gesture_function) { |
| 360 if (__running) | 433 if (__running) |
| 361 return; | 434 return; |
| 435 | |
| 436 // By default, all gestures start with raf enabled | |
| 437 __init_raf(true); | |
|
nduca
2011/10/10 23:11:19
We init_raf at the global scope too? Is that one r
| |
| 438 | |
| 362 // Attempt to create a gesture function from a string name. | 439 // Attempt to create a gesture function from a string name. |
| 363 if (typeof gesture_function == "string") { | 440 if (typeof gesture_function == "string") { |
| 364 if (!__gestures[gesture_function]) | 441 if (!__gestures[gesture_function]) { |
| 365 throw new Error("Unrecognized gesture name"); | 442 if (!__gesture_library[gesture_function]) |
| 443 throw new Error("Unrecognized gesture name"); | |
| 444 else | |
| 445 gesture_function = __create_repeating_gesture_function( | |
| 446 __gesture_library[gesture_function]); | |
| 447 } | |
| 366 else | 448 else |
| 367 gesture_function = __create_repeating_gesture_function( | 449 gesture_function = __create_repeating_gesture_function( |
| 368 __gestures[gesture_function]); | 450 __gestures[gesture_function]); |
| 369 } | 451 } |
| 370 else if (typeof gesture_function != "function") | 452 else if (typeof gesture_function != "function") |
| 371 throw new Error("Argument is not a function or gesture name"); | 453 throw new Error("Argument is not a function or gesture name"); |
| 372 | 454 |
| 373 __old_title = document.title; | 455 __old_title = document.title; |
| 374 __advance_gesture = gesture_function; | 456 __advance_gesture = gesture_function; |
| 375 __t_start = new Date().getTime(); | 457 __t_start = new Date().getTime(); |
| 376 __running = true; | 458 __running = true; |
| 377 if (!__raf_is_live) { | 459 if (!__raf_is_live) { |
| 378 __sched_update(); | 460 __sched_update(); |
| 379 } | 461 } |
| 380 } | 462 } |
| 381 | 463 |
| 382 function __start_all() { | 464 function __start_all() { |
| 383 __queued_gesture_functions = []; | 465 __queued_gesture_functions = []; |
| 384 __results = { | 466 __results = { |
| 385 gestures: [], | 467 gestures: [], |
| 386 means: [], | 468 means: [], |
| 387 sigmas: [], | 469 sigmas: [], |
| 388 }; | 470 }; |
| 389 | 471 |
| 390 for (var gesture in __gestures) { | 472 for (var gesture in __gestures) { |
| 391 __results.gestures.push(gesture); | 473 __results.gestures.push(gesture); |
| 392 __queued_gesture_functions.push(gesture); | 474 __queued_gesture_functions.push(gesture); |
| 393 } | 475 } |
| 394 __running_all = true; | 476 __running_all = true; |
| 395 // Run steady gesture once to cache the webpage layout for subsequent tests. | 477 // Run init gesture once to cache the webpage layout for subsequent tests. |
| 396 __start("steady"); | 478 __start("init"); |
|
nduca
2011/10/10 23:11:19
Not that this is your fault, but since we're here,
| |
| 397 } | 479 } |
| 398 | 480 |
| 399 function __stop() { | 481 function __stop() { |
| 400 __running = false; | 482 __running = false; |
| 401 document.title = __old_title; | 483 document.title = __old_title; |
| 402 window.__scrolledTo = undefined; | 484 window.__scrolledTo = undefined; |
| 403 | 485 |
| 404 if (__running_all) { | 486 if (__running_all) { |
| 405 var results = __calc_results(); | 487 var results = __calc_results(); |
| 406 __results.means.push(results.mean); | 488 __results.means.push(results.mean); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 420 __running = false; | 502 __running = false; |
| 421 __running_all = false; | 503 __running_all = false; |
| 422 document.title = __old_title; | 504 document.title = __old_title; |
| 423 document.body.scrollTop = 0; | 505 document.body.scrollTop = 0; |
| 424 __init_stats(); | 506 __init_stats(); |
| 425 } | 507 } |
| 426 | 508 |
| 427 function __force_compositor() { | 509 function __force_compositor() { |
| 428 document.body.style.webkitTransform = "translateZ(0)"; | 510 document.body.style.webkitTransform = "translateZ(0)"; |
| 429 } | 511 } |
| OLD | NEW |