--- /dev/null
+//
+// To use this script, the HTML has to have only one element and this element's className
+// should be equal to "Benchmark".
+//
+// This script forces rendering the HTML element many times by changing its position and its
+// size. The size can be very big to test the case of displaying only a small portion of the
+// element and measure how fast the display will be in this case.
+//
+
+function Point(x, y) {
+ this.x = x;
+ this.y = y;
+}
+
+Point.prototype = {
+ scale : function(other) {
+ return new Point(this.x * other.x, this.y * other.y);
+ },
+ add : function(other) {
+ return new Point(this.x + other.x, this.y + other.y);
+ },
+ subtract : function(other) {
+ return new Point(this.x - other.x, this.y - other.y);
+ },
+ isAlmostEqual : function(other, threshold) {
+ return Math.abs(this.x - other.x) < threshold && Math.abs(this.y - other.y) < threshold;
+ }
+}
+
+function Rectangle(position, size) {
+ this.position = position;
+ this.size = size;
+}
+
+Rectangle.prototype = {
+ left : function() {
+ return this.position.x;
+ },
+ top : function() {
+ return this.position.y;
+ },
+ width : function() {
+ return this.size.x;
+ },
+ height : function() {
+ return this.size.y;
+ },
+ isAlmostEqual : function(other, threshold) {
+ return this.position.isAlmostEqual(other.position, threshold) && this.size.isAlmostEqual(other.size, threshold);
+ }
+}
+
+function ElapsedTime() {
+ this._startTime = PerfTestRunner.now();
+ this._stopTime = this._startTime;
+}
+
+ElapsedTime.prototype = {
+
+ start : function() {
+ this._startTime = this._stopTime = PerfTestRunner.now();
+ },
+
+ stop : function() {
+ this._stopTime = PerfTestRunner.now();
+ },
+
+ isActive : function() {
+ return this._startTime == this._stopTime;
+ },
+
+ elapsed : function() {
+ return (this.isActive() ? PerfTestRunner.now() : this._stopTime) - this._startTime;
+ },
+
+ elapsedString : function() {
+ var tenths = this.elapsed() / 1000;
+ return tenths.toFixed(2) + " Seconds";
+ }
+}
+
+function AnimateMove(offset, zoomFactor, animateFactor) {
+ this.offset = offset;
+ this.zoomFactor = zoomFactor;
+ this.animateFactor = animateFactor;
+}
+
+AnimateMove.centerFactor = new Point(0.5, 0.5);
+
+AnimateMove.prototype = {
+
+ targetRect : function(windowSize, sourceSize) {
+ var offset = this.offset.scale(this.zoomFactor);
+ var size = sourceSize.scale(this.zoomFactor);
+ var position = windowSize.subtract(size).scale(AnimateMove.centerFactor).subtract(offset);
+ return new Rectangle(position, size);
+ },
+
+ nextAnimateRect : function(targetRect, animateRect) {
+ var deltaPosition = targetRect.position.subtract(animateRect.position).scale(this.animateFactor);
+ var deltaSize = targetRect.size.subtract(animateRect.size).scale(this.animateFactor);
+ return new Rectangle(animateRect.position.add(deltaPosition), animateRect.size.add(deltaSize));
+ }
+}
+
+function ElementAnimator(element, windowSize, sourceSize) {
+ this._element = element;
+ this._windowSize = windowSize;
+ this._sourceSize = sourceSize;
+
+ this._animateMoves = [
+ new AnimateMove(new Point( 0, 0), new Point( 0.7, 0.7), new Point(1.00, 1.00)),
+ new AnimateMove(new Point(-500, -300), new Point(12.0, 12.0), new Point(0.50, 0.50)),
+ new AnimateMove(new Point( 100, -200), new Point( 0.1, 0.1), new Point(0.50, 0.50)),
+ new AnimateMove(new Point(-100, -300), new Point( 5.0, 5.0), new Point(0.20, 0.20)),
+ new AnimateMove(new Point( 0, 0), new Point( 0.7, 0.7), new Point(0.50, 0.50))
+ ];
+
+ this._animateMoveIndex = 0;
+ this.nextTargetRect();
+ this._animateRect = this._targetRect;
+ this.moveToAnimateRect();
+}
+
+ElementAnimator.prototype = {
+
+ nextTargetRect : function() {
+ if (this._animateMoveIndex >= this._animateMoves.length)
+ return false;
+
+ this._targetRect = this._animateMoves[this._animateMoveIndex++].targetRect(this._windowSize, this._sourceSize);
+ return true;
+ },
+
+ nextAnimateRect : function() {
+ if (this._animateRect.isAlmostEqual(this._targetRect, 0.1))
+ return false;
+
+ this._animateRect = this._animateMoves[this._animateMoveIndex - 1].nextAnimateRect(this._targetRect, this._animateRect);
+ return true;
+ },
+
+ moveToAnimateRect : function() {
+ this._element.style.width = this._animateRect.width() + "px";
+ this._element.style.left = this._animateRect.left() + "px";
+ this._element.style.top = this._animateRect.top() + "px";
+ }
+}
+
+function RenderAnimator() {
+ this.element = document.getElementsByClassName("Benchmark")[0];
+ this.sourceSize = new Point(this.element.width, this.element.height);
+
+ // Tiling causes the rendering to slow down when the window width > 2000
+ this.windowSize = new Point(3000, 1500);
+
+ this.timer = document.createElement("span");
+ this.timer.className = "Timer";
+ document.body.appendChild(this.timer);
+
+ this.timeoutDelay = window.testRunner ? 0 : 500;
+ this.elapsedTime = new ElapsedTime();
+ this.elementAnimator = null;
+}
+
+RenderAnimator.prototype = {
+
+ nextRun : function() {
+ this.showElements(true);
+ this.elementAnimator = new ElementAnimator(this.element, this.windowSize, this.sourceSize);
+
+ var self = this;
+ setTimeout(function () {
+ self.elapsedTime.start();
+ self.moveToNextTargetRect();
+ }, this.timeoutDelay);
+ },
+
+ moveToNextTargetRect : function() {
+ if (this.elementAnimator.nextTargetRect())
+ setTimeout(this.moveToNextAnimateRect.bind(this), 0);
+ else {
+ this.elapsedTime.stop();
+ setTimeout(this.finishRun.bind(this), this.timeoutDelay);
+ }
+ },
+
+ moveToNextAnimateRect : function() {
+ this.timer.innerHTML = this.elapsedTime.elapsedString();
+
+ if (this.elementAnimator.nextAnimateRect())
+ window.requestAnimationFrame(this.moveToNextAnimateRect.bind(this));
+ else
+ this.moveToNextTargetRect();
+
+ this.elementAnimator.moveToAnimateRect();
+ },
+
+ finishRun : function() {
+ this.showElements(false);
+
+ var finishedTest = !PerfTestRunner.measureValueAsync(this.elapsedTime.elapsed());
+ PerfTestRunner.gc();
+
+ if (!finishedTest)
+ setTimeout(this.nextRun.bind(this), this.timeoutDelay * 2);
+ },
+
+ showElements : function(show) {
+ this.element.style.visibility = "visible";
+ this.element.style.opacity = show ? 1 : 0;
+ this.timer.style.opacity = show ? 1 : 0;
+ },
+
+ removeElements : function() {
+ this.element.parentNode.removeChild(this.element);
+ this.timer.parentNode.removeChild(this.timer);
+ this.element = null;
+ this.timer = null;
+ }
+}
+
+window.addEventListener("load", function() {
+ window.renderAnimator = new RenderAnimator();
+ window.renderAnimator.nextRun();
+});
+
+PerfTestRunner.prepareToMeasureValuesAsync({
+ unit: 'ms',
+ done: function () {
+ window.renderAnimator.removeElements();
+ }
+});