| // |
| // 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(); |
| } |
| }); |