-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/dom/particles.html b/MotionMark/tests/dom/particles.html
deleted file mode 100644
index 02b0786..0000000
--- a/MotionMark/tests/dom/particles.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/dom/resources/compositing-transforms.js b/MotionMark/tests/dom/resources/compositing-transforms.js
deleted file mode 100644
index c92fadf..0000000
--- a/MotionMark/tests/dom/resources/compositing-transforms.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-BouncingCompositedImage = Utilities.createSubclass(BouncingParticle,
- function(stage)
- {
- BouncingParticle.call(this, stage);
-
- this.element = document.createElement("img");
- this.element.style.width = this.size.x + "px";
- this.element.style.height = this.size.y + "px";
- this.element.setAttribute("src", stage.imageSrc);
-
- if (stage.useFilters)
- this.element.style.filter = "hue-rotate(" + Stage.randomAngle() + "rad)";
-
- stage.element.appendChild(this.element);
- this._move();
- }, {
-
- _move: function()
- {
- this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px, 0) " + this.rotater.rotateZ();
- },
-
- animate: function(timeDelta)
- {
- BouncingParticle.prototype.animate.call(this, timeDelta);
- this._move();
- }
-});
-
-CompositingTransformsStage = Utilities.createSubclass(BouncingParticlesStage,
- function()
- {
- BouncingParticlesStage.call(this);
- }, {
-
- initialize: function(benchmark, options)
- {
- BouncingParticlesStage.prototype.initialize.call(this, benchmark, options);
-
- this.imageSrc = options["imageSrc"] || "../resources/yin-yang.svg";
- this.useFilters = options["filters"] == "yes";
- },
-
- createParticle: function()
- {
- return new BouncingCompositedImage(this);
- },
-
- particleWillBeRemoved: function(particle)
- {
- particle.element.remove();
- }
-});
-
-CompositedTransformsBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- Benchmark.call(this, new CompositingTransformsStage(), options);
- }
-);
-
-window.benchmarkClass = CompositedTransformsBenchmark;
-
-})();
diff --git a/MotionMark/tests/dom/resources/dom-particles.js b/MotionMark/tests/dom/resources/dom-particles.js
deleted file mode 100644
index 985de3c..0000000
--- a/MotionMark/tests/dom/resources/dom-particles.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-DOMParticle = Utilities.createSubclass(Particle,
- function(stage)
- {
- this.element = document.createElement("div");
- stage.element.appendChild(this.element);
-
- Particle.call(this, stage);
- }, {
-
- reset: function()
- {
- Particle.prototype.reset.call(this);
-
- this.position = Stage.randomElementInArray(this.stage.emitLocation);
-
- var angle = Stage.randomInt(0, this.stage.emitSteps) / this.stage.emitSteps * Math.PI * 2 + Stage.dateCounterValue(100) * this.stage.emissionSpin;
- this.velocity = new Point(Math.sin(angle), Math.cos(angle))
- .multiply(Stage.random(.5, 2.5));
-
- this.element.style.width = this.size.x + "px";
- this.element.style.height = this.size.y + "px";
- this.stage.colorOffset = (this.stage.colorOffset + 1) % 360;
- this.element.style.backgroundColor = "hsl(" + this.stage.colorOffset + ", 70%, 45%)";
- },
-
- move: function()
- {
- this.element.style.transform = "translate(" + this.position.x + "px, " + this.position.y + "px)" + this.rotater.rotateZ();
- }
-});
-
-DOMParticleStage = Utilities.createSubclass(ParticlesStage,
- function()
- {
- ParticlesStage.call(this);
- }, {
-
- initialize: function(benchmark)
- {
- ParticlesStage.prototype.initialize.call(this, benchmark);
- this.emissionSpin = Stage.random(0, 3);
- this.emitSteps = Stage.randomInt(4, 6);
- this.emitLocation = [
- new Point(this.size.x * .25, this.size.y * .333),
- new Point(this.size.x * .5, this.size.y * .25),
- new Point(this.size.x * .75, this.size.y * .333)
- ];
- this.colorOffset = Stage.randomInt(0, 359);
- },
-
- createParticle: function()
- {
- return new DOMParticle(this);
- },
-
- willRemoveParticle: function(particle)
- {
- particle.element.remove();
- }
-});
-
-DOMParticleBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- Benchmark.call(this, new DOMParticleStage(), options);
- }
-);
-
-window.benchmarkClass = DOMParticleBenchmark;
-
-})();
diff --git a/MotionMark/tests/dom/resources/focus.js b/MotionMark/tests/dom/resources/focus.js
deleted file mode 100644
index c268d98..0000000
--- a/MotionMark/tests/dom/resources/focus.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-var maxVerticalOffset = 50;
-var minimumDiameter = 30;
-var centerDiameter = 90;
-var sizeVariance = 60;
-var travelDistance = 50;
-
-var opacityMultiplier = 30;
-
-var FocusElement = Utilities.createClass(
- function(stage)
- {
- var size = minimumDiameter + sizeVariance;
-
- // Size and blurring are a function of depth.
- this._depth = Pseudo.random();
- var distance = Utilities.lerp(this._depth, 0, sizeVariance);
- size -= distance;
-
- var top = Stage.random(0, stage.size.height - size) - stage.maxBlurValue * 3;
- var left = Stage.random(0, stage.size.width - size) - stage.maxBlurValue * 3;
-
- this.container = document.createElement('div');
- this.container.style.width = (size + stage.maxBlurValue * 6) + "px";
- this.container.style.height = (size + stage.maxBlurValue * 6) + "px";
- this.container.style.top = top + "px";
- this.container.style.left = left + "px";
- this.container.style.zIndex = Math.round((1 - this._depth) * 10);
-
- this.particle = Utilities.createElement("div", {}, this.container);
- this.particle.style.width = size + "px";
- this.particle.style.height = size + "px";
- this.particle.style.top = (stage.maxBlurValue * 3) + "px";
- this.particle.style.left = (stage.maxBlurValue * 3) + "px";
-
- var depthMultiplier = Utilities.lerp(1 - this._depth, 0.8, 1);
- this._sinMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
- this._cosMultiplier = Pseudo.random() * Stage.randomSign() * depthMultiplier * travelDistance;
- }, {
-
- hide: function()
- {
- this.container.style.display = "none";
- },
-
- show: function()
- {
- this.container.style.display = "block";
- },
-
- animate: function(stage, sinFactor, cosFactor)
- {
- var top = sinFactor * this._sinMultiplier;
- var left = cosFactor * this._cosMultiplier;
-
- Utilities.setElementPrefixedProperty(this.container, "filter", "blur(" + stage.getBlurValue(this._depth) + "px) opacity(" + stage.getOpacityValue(this._depth) + "%)");
- this.container.style.transform = "translate3d(" + left + "%, " + top + "%, 0)";
- }
-});
-
-var FocusStage = Utilities.createSubclass(Stage,
- function()
- {
- Stage.call(this);
- }, {
-
- movementDuration: 2500,
- focusDuration: 1000,
-
- centerObjectDepth: 0.0,
-
- minBlurValue: 1.5,
- maxBlurValue: 15,
- maxCenterObjectBlurValue: 5,
-
- initialize: function(benchmark, options)
- {
- Stage.prototype.initialize.call(this, benchmark, options);
-
- this._testElements = [];
- this._focalPoint = 0.5;
- this._offsetIndex = 0;
-
- this._centerElement = document.getElementById("center-text");
- this._centerElement.style.width = (centerDiameter + this.maxCenterObjectBlurValue * 6) + "px";
- this._centerElement.style.height = (centerDiameter + this.maxCenterObjectBlurValue * 6) + "px";
- this._centerElement.style.zIndex = Math.round(10 * this.centerObjectDepth);
-
- var particle = document.querySelector("#center-text div");
- particle.style.width = centerDiameter + "px";
- particle.style.height = centerDiameter + "px";
- particle.style.top = (this.maxCenterObjectBlurValue * 3) + "px";
- particle.style.left = (this.maxCenterObjectBlurValue * 3) + "px";
-
- var blur = this.getBlurValue(this.centerObjectDepth, true);
- Utilities.setElementPrefixedProperty(this._centerElement, "filter", "blur(" + blur + "px)");
- },
-
- complexity: function()
- {
- return 1 + this._offsetIndex;
- },
-
- tune: function(count)
- {
- if (count == 0)
- return;
-
- if (count < 0) {
- this._offsetIndex = Math.max(0, this._offsetIndex + count);
- for (var i = this._offsetIndex; i < this._testElements.length; ++i)
- this._testElements[i].hide();
- return;
- }
-
- var newIndex = this._offsetIndex + count;
- for (var i = this._testElements.length; i < newIndex; ++i) {
- var obj = new FocusElement(this);
- this._testElements.push(obj);
- this.element.appendChild(obj.container);
- }
- for (var i = this._offsetIndex; i < newIndex; ++i)
- this._testElements[i].show();
- this._offsetIndex = newIndex;
- },
-
- animate: function()
- {
- var time = this._benchmark.timestamp;
- var sinFactor = Math.sin(time / this.movementDuration);
- var cosFactor = Math.cos(time / this.movementDuration);
-
- var focusProgress = 0.5 + 0.5 * Math.sin(time / this.focusDuration);
- this._focalPoint = focusProgress;
-
- Utilities.setElementPrefixedProperty(this._centerElement, "filter", "blur(" + this.getBlurValue(this.centerObjectDepth, true) + "px)");
-
- for (var i = 0; i < this._offsetIndex; ++i)
- this._testElements[i].animate(this, sinFactor, cosFactor);
- },
-
- getBlurValue: function(depth, isCenter)
- {
- if (isCenter)
- return 1 + Math.abs(depth - this._focalPoint) * (this.maxCenterObjectBlurValue - 1);
-
- return Utilities.lerp(Math.abs(depth - this._focalPoint), this.minBlurValue, this.maxBlurValue);
- },
-
- getOpacityValue: function(depth)
- {
- return Math.max(1, opacityMultiplier * (1 - Math.abs(depth - this._focalPoint)));
- },
-});
-
-var FocusBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- Benchmark.call(this, new FocusStage(), options);
- }
-);
-
-window.benchmarkClass = FocusBenchmark;
-
-}());
diff --git a/MotionMark/tests/dom/resources/leaves.js b/MotionMark/tests/dom/resources/leaves.js
deleted file mode 100644
index a0bb633..0000000
--- a/MotionMark/tests/dom/resources/leaves.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-var SuperLeaf = window.Leaf;
-var SimpleLeaf = Utilities.createSubclass(SuperLeaf,
- function(stage)
- {
- SuperLeaf.call(this, stage);
- }, {
-
- sizeMinimum: 25,
- sizeRange: 0,
- usesOpacity: false,
-
- move: function()
- {
- this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ();
- }
-});
-
-var ScaleLeaf = Utilities.createSubclass(SuperLeaf,
- function(stage)
- {
- SuperLeaf.call(this, stage);
- }, {
-
- sizeMinimum: 20,
- sizeRange: 30,
- usesOpacity: false,
-
- move: function()
- {
- this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ();
- }
-});
-
-var OpacityLeaf = Utilities.createSubclass(SuperLeaf,
- function(stage)
- {
- SuperLeaf.call(this, stage);
- }, {
-
- sizeMinimum: 25,
- sizeRange: 0,
- usesOpacity: true,
-
- move: function()
- {
- this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ();
- this.element.style.opacity = this._opacity;
- }
-});
-
-
-var LeavesBenchmark = window.benchmarkClass;
-var LeavesDerivedBenchmark = Utilities.createSubclass(LeavesBenchmark,
- function(options)
- {
- switch (options["style"]) {
- case "simple":
- window.Leaf = SimpleLeaf;
- break;
- case "scale":
- window.Leaf = ScaleLeaf;
- break;
- case "opacity":
- window.Leaf = OpacityLeaf;
- break;
- }
- LeavesBenchmark.call(this, options);
- }
-);
-
-window.benchmarkClass = LeavesDerivedBenchmark;
-
-})();
diff --git a/MotionMark/tests/resources/main.js b/MotionMark/tests/resources/main.js
deleted file mode 100644
index ca7f2a9..0000000
--- a/MotionMark/tests/resources/main.js
+++ /dev/null
@@ -1,998 +0,0 @@
-/*
- * Copyright (C) 2015-2021 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-Sampler = Utilities.createClass(
- function(seriesCount, expectedSampleCount, processor)
- {
- this._processor = processor;
-
- this.samples = [];
- for (var i = 0; i < seriesCount; ++i) {
- var array = new Array(expectedSampleCount);
- array.fill(0);
- this.samples[i] = array;
- }
- this.sampleCount = 0;
- }, {
-
- record: function()
- {
- // Assume that arguments.length == this.samples.length
- for (var i = 0; i < arguments.length; i++) {
- this.samples[i][this.sampleCount] = arguments[i];
- }
- ++this.sampleCount;
- },
-
- processSamples: function()
- {
- var results = {};
-
- // Remove unused capacity
- this.samples = this.samples.map(function(array) {
- return array.slice(0, this.sampleCount);
- }, this);
-
- this._processor.processSamples(results);
-
- return results;
- }
-});
-
-const sampleTypeIndex = 0;
-const sampleTimeIndex = 1;
-const sampleComplexityIndex = 2;
-const sampleFrameLengthEstimateIndex = 3;
-
-Controller = Utilities.createClass(
- function(benchmark, options)
- {
- // Initialize timestamps relative to the start of the benchmark
- // In start() the timestamps are offset by the start timestamp
- this._startTimestamp = 0;
- this._endTimestamp = options["test-interval"];
- this._targetFrameRate = options["frame-rate"];
- // Default data series: timestamp, complexity, estimatedFrameLength
- var sampleSize = options["sample-capacity"] || (this._targetFrameRate * options["test-interval"] / 1000);
- this._sampler = new Sampler(options["series-count"] || 4, sampleSize, this);
- this._marks = {};
-
- this._frameLengthEstimator = new SimpleKalmanEstimator(options["kalman-process-error"], options["kalman-measurement-error"]);
- this._isFrameLengthEstimatorEnabled = true;
-
- // Length of subsequent intervals; a value of 0 means use no intervals
- this.intervalSamplingLength = 100;
-
- this.initialComplexity = 1;
- }, {
-
- set isFrameLengthEstimatorEnabled(enabled)
- {
- this._isFrameLengthEstimatorEnabled = enabled;
- },
-
- start: function(startTimestamp, stage)
- {
- this._startTimestamp = startTimestamp;
- this._endTimestamp += startTimestamp;
- this._previousTimestamp = startTimestamp;
- this._measureAndResetInterval(startTimestamp);
- this.recordFirstSample(startTimestamp, stage);
- },
-
- recordFirstSample: function(startTimestamp, stage)
- {
- this._sampler.record(Strings.json.mutationFrameType, startTimestamp, stage.complexity(), -1);
- this.mark(Strings.json.samplingStartTimeOffset, startTimestamp);
- },
-
- mark: function(comment, timestamp, data)
- {
- data = data || {};
- data.time = timestamp;
- data.index = this._sampler.sampleCount;
- this._marks[comment] = data;
- },
-
- containsMark: function(comment)
- {
- return comment in this._marks;
- },
-
- filterOutOutliers: function(array)
- {
- if (array.length == 0)
- return [];
-
- array.sort((a, b) => a - b);
- var q1 = array[Math.min(Math.round(array.length * 1 / 4), array.length - 1)];
- var q3 = array[Math.min(Math.round(array.length * 3 / 4), array.length - 1)];
- var interquartileRange = q3 - q1;
- var minimum = q1 - interquartileRange * 1.5;
- var maximum = q3 + interquartileRange * 1.5;
- return array.filter(x => x >= minimum && x <= maximum);
- },
-
- _measureAndResetInterval: function(currentTimestamp)
- {
- var sampleCount = this._sampler.sampleCount;
- var averageFrameLength = 0;
-
- if (this._intervalEndTimestamp) {
- var durations = [];
- for (var i = Math.max(this._intervalStartIndex, 1); i < sampleCount; ++i) {
- durations.push(this._sampler.samples[sampleTimeIndex][i] - this._sampler.samples[sampleTimeIndex][i - 1]);
- }
- var filteredDurations = this.filterOutOutliers(durations);
- if (filteredDurations.length > 0)
- averageFrameLength = filteredDurations.reduce((a, b) => a + b, 0) / filteredDurations.length;
- }
-
- this._intervalStartIndex = sampleCount;
- this._intervalEndTimestamp = currentTimestamp + this.intervalSamplingLength;
-
- return averageFrameLength;
- },
-
- _getFrameType: function(samples, i)
- {
- return samples[sampleTypeIndex][i];
- },
-
- _getComplexity: function(samples, i)
- {
- return samples[sampleComplexityIndex][i];
- },
-
- _getFrameLength: function(samples, i)
- {
- return samples[sampleTimeIndex][i] - samples[sampleTimeIndex][i - 1];
- },
-
- _previousFrameComplexity: function(samples, i)
- {
- if (i > 0)
- return this._getComplexity(samples, i - 1);
-
- return 0;
- },
-
- update: function(timestamp, stage)
- {
- const frameType = this._previousFrameComplexity(this._sampler.samples, this._sampler.sampleCount) != stage.complexity() ? Strings.json.mutationFrameType : Strings.json.animationFrameType
- var lastFrameLength = timestamp - this._previousTimestamp;
- this._previousTimestamp = timestamp;
-
- var frameLengthEstimate = -1, intervalAverageFrameLength = -1;
- var didFinishInterval = false;
- if (!this.intervalSamplingLength) {
- if (this._isFrameLengthEstimatorEnabled) {
- this._frameLengthEstimator.sample(lastFrameLength);
- frameLengthEstimate = this._frameLengthEstimator.estimate;
- }
- this._sampler.record(frameType, timestamp, stage.complexity(), frameLengthEstimate);
- } else {
- this.registerFrameTime(lastFrameLength);
- if (this.intervalHasConcluded(timestamp)) {
- var intervalStartTimestamp = this._sampler.samples[sampleTimeIndex][this._intervalStartIndex];
- intervalAverageFrameLength = this._measureAndResetInterval(timestamp);
- if (this._isFrameLengthEstimatorEnabled) {
- this._frameLengthEstimator.sample(intervalAverageFrameLength);
- frameLengthEstimate = this._frameLengthEstimator.estimate;
- }
- this._sampler.record(frameType, timestamp, stage.complexity(), frameLengthEstimate);
-
- didFinishInterval = true;
- this.didFinishInterval(timestamp, stage, intervalAverageFrameLength);
- this._frameLengthEstimator.reset();
- } else
- this._sampler.record(frameType, timestamp, stage.complexity(), frameLengthEstimate);
- }
-
- this.tune(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength);
- },
-
- registerFrameTime: function(lastFrameLength)
- {
- },
-
- intervalHasConcluded: function(timestamp)
- {
- return timestamp >= this._intervalEndTimestamp;
- },
-
- didFinishInterval: function(timestamp, stage, intervalAverageFrameLength)
- {
- },
-
- tune: function(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength)
- {
- },
-
- shouldStop: function(timestamp)
- {
- return timestamp > this._endTimestamp;
- },
-
- results: function()
- {
- return this._sampler.processSamples();
- },
-
- _processComplexitySamples: function(complexitySamples)
- {
- complexitySamples.sort(function(a, b) {
- return complexitySamples.getFieldInDatum(a, Strings.json.complexity) - complexitySamples.getFieldInDatum(b, Strings.json.complexity);
- });
- },
-
- _processMarks: function()
- {
- for (var markName in this._marks)
- this._marks[markName].time -= this._startTimestamp;
- return this._marks;
- },
-
- _processControllerSamples: function()
- {
- const processedSampleTypeIndex = 0;
- const processedSampleTimeIndex = 1;
- const processedSampleComplexityIndex = 2;
- const processedSampleFrameLengthIndex = 3;
- const processedSampleSmoothedFrameLengthIndex = 4;
-
- var controllerSamples = new SampleData;
- controllerSamples.addField(Strings.json.frameType, processedSampleTypeIndex);
- controllerSamples.addField(Strings.json.time, processedSampleTimeIndex);
- controllerSamples.addField(Strings.json.complexity, processedSampleComplexityIndex);
-
- controllerSamples.addField(Strings.json.frameLength, processedSampleFrameLengthIndex);
- controllerSamples.addField(Strings.json.smoothedFrameLength, processedSampleSmoothedFrameLengthIndex);
-
- var samples = this._sampler.samples;
- samples[sampleTimeIndex].forEach(function(timestamp, i) {
- var sample = controllerSamples.createDatum();
- controllerSamples.push(sample);
-
- // Represent time in milliseconds
- controllerSamples.setFieldInDatum(sample, Strings.json.frameType, samples[sampleTypeIndex][i]);
- controllerSamples.setFieldInDatum(sample, Strings.json.time, timestamp - this._startTimestamp);
- controllerSamples.setFieldInDatum(sample, Strings.json.complexity, samples[sampleComplexityIndex][i]);
-
- if (i == 0)
- controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, 1000/this._targetFrameRate);
- else
- controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, timestamp - samples[sampleTimeIndex][i - 1]);
-
- if (samples[sampleFrameLengthEstimateIndex][i] != -1)
- controllerSamples.setFieldInDatum(sample, Strings.json.smoothedFrameLength, samples[sampleFrameLengthEstimateIndex][i]);
- }, this);
-
- return controllerSamples;
- },
-
- processSamples: function(results)
- {
- results[Strings.json.marks] = this._processMarks();
-
- var controllerSamples = this._processControllerSamples();
- var complexitySamples = new SampleData(controllerSamples.fieldMap);
-
- results[Strings.json.samples] = {};
- results[Strings.json.samples][Strings.json.controller] = controllerSamples;
- results[Strings.json.samples][Strings.json.complexity] = complexitySamples;
- controllerSamples.forEach(function (sample) {
- complexitySamples.push(sample);
- });
- this._processComplexitySamples(complexitySamples);
- }
-});
-
-FixedController = Utilities.createSubclass(Controller,
- function(benchmark, options)
- {
- Controller.call(this, benchmark, options);
- this.initialComplexity = options["complexity"];
- this.intervalSamplingLength = 0;
- }
-);
-
-AdaptiveController = Utilities.createSubclass(Controller,
- function(benchmark, options)
- {
- // Data series: timestamp, complexity, estimatedIntervalFrameLength
- Controller.call(this, benchmark, options);
-
- // All tests start at 0, so we expect to see the target fps quickly.
- this._samplingTimestamp = options["test-interval"] / 2;
- this._startedSampling = false;
- this._targetFrameRate = options["frame-rate"];
- this._pid = new PIDController(this._targetFrameRate);
-
- this._intervalFrameCount = 0;
- this._numberOfFramesToMeasurePerInterval = 4;
- }, {
-
- start: function(startTimestamp, stage)
- {
- Controller.prototype.start.call(this, startTimestamp, stage);
-
- this._samplingTimestamp += startTimestamp;
- this._intervalTimestamp = startTimestamp;
- },
-
- recordFirstSample: function(startTimestamp, stage)
- {
- this._sampler.record(Strings.json.mutationFrameType, startTimestamp, stage.complexity(), -1);
- },
-
- update: function(timestamp, stage)
- {
- if (!this._startedSampling && timestamp >= this._samplingTimestamp) {
- this._startedSampling = true;
- this.mark(Strings.json.samplingStartTimeOffset, this._samplingTimestamp);
- }
-
- // Start the work for the next frame.
- ++this._intervalFrameCount;
-
- if (this._intervalFrameCount < this._numberOfFramesToMeasurePerInterval) {
- this._sampler.record(Strings.json.animationFrameType, timestamp, stage.complexity(), -1);
- return;
- }
-
- // Adjust the test to reach the desired FPS.
- var intervalLength = timestamp - this._intervalTimestamp;
- this._frameLengthEstimator.sample(intervalLength / this._numberOfFramesToMeasurePerInterval);
- var intervalEstimatedFrameRate = 1000 / this._frameLengthEstimator.estimate;
- var tuneValue = -this._pid.tune(timestamp - this._startTimestamp, intervalLength, intervalEstimatedFrameRate);
- tuneValue = tuneValue > 0 ? Math.floor(tuneValue) : Math.ceil(tuneValue);
- stage.tune(tuneValue);
-
- this._sampler.record(Strings.json.mutationFrameType, timestamp, stage.complexity(), this._frameLengthEstimator.estimate);
-
- // Start the next interval.
- this._intervalFrameCount = 0;
- this._intervalTimestamp = timestamp;
- }
-});
-
-RampController = Utilities.createSubclass(Controller,
- function(benchmark, options)
- {
- this.targetFPS = options["frame-rate"];
-
- // The tier warmup takes at most 5 seconds
- options["sample-capacity"] = (options["test-interval"] / 1000 + 5) * this.targetFPS;
- Controller.call(this, benchmark, options);
-
- // Initially start with a tier test to find the bounds
- // The number of objects in a tier test is 10^|_tier|
- this._tier = -.5;
- // The timestamp is first set after the first interval completes
- this._tierStartTimestamp = 0;
- this._minimumComplexity = 1;
- this._maximumComplexity = 1;
-
- this._testLength = options["test-interval"];
-
- // After the tier range is determined, figure out the number of ramp iterations
- var minimumRampLength = 3000;
- var totalRampIterations = Math.max(1, Math.floor(this._endTimestamp / minimumRampLength));
- // Give a little extra room to run since the ramps won't be exactly this length
- this._rampLength = Math.floor((this._endTimestamp - totalRampIterations * this.intervalSamplingLength) / totalRampIterations);
- this._rampDidWarmup = false;
- this._rampRegressions = [];
-
- this._finishedTierSampling = false;
- this._changePointEstimator = new Experiment;
- this._minimumComplexityEstimator = new Experiment;
- // Estimates all frames within an interval
- this._intervalFrameLengthEstimator = new Experiment;
-
- // Used for regression calculations in the ramps
- this.frameLengthDesired = 1000/this.targetFPS;
- // Add some tolerance; frame lengths shorter than this are considered to be @ the desired frame length
- this.frameLengthDesiredThreshold = 1000/(this.targetFPS - 2);
- // During tier sampling get at least this slow to find the right complexity range
- this.frameLengthTierThreshold = 1000/(this.targetFPS * 0.5);
- // Try to make each ramp get this slow so that we can cross the break point
- this.frameLengthRampLowerThreshold = 1000/(this.targetFPS * 0.75);
- // Do not let the regression calculation at the maximum complexity of a ramp get slower than this threshold
- this.frameLengthRampUpperThreshold = 1000/(this.targetFPS / 3);
- }, {
-
- // If the engine can handle the tier's complexity at the desired frame rate, test for a short
- // period, then move on to the next tier
- tierFastTestLength: 250,
- // If the engine is under stress, let the test run a little longer to let the measurement settle
- tierSlowTestLength: 750,
- // Tier intervals must have this number of non-outlier frames in order to end.
- numberOfFramesRequiredInInterval: 9,
-
- rampWarmupLength: 200,
-
- start: function(startTimestamp, stage)
- {
- Controller.prototype.start.call(this, startTimestamp, stage);
- this._rampStartTimestamp = 0;
- this.intervalSamplingLength = 100;
- this._frameTimeHistory = [];
- },
-
- registerFrameTime: function(lastFrameLength)
- {
- this._frameTimeHistory.push(lastFrameLength);
- },
-
- intervalHasConcluded: function(timestamp)
- {
- if (!Controller.prototype.intervalHasConcluded.call(this, timestamp))
- return false;
-
- return this._finishedTierSampling || this.filterOutOutliers(this._frameTimeHistory).length > this.numberOfFramesRequiredInInterval;
- },
-
- didFinishInterval: function(timestamp, stage, intervalAverageFrameLength)
- {
- this._frameTimeHistory = [];
- if (!this._finishedTierSampling) {
- if (this._tierStartTimestamp > 0 && timestamp < this._tierStartTimestamp + this.tierFastTestLength)
- return;
-
- var currentComplexity = stage.complexity();
- var currentFrameLength = this._frameLengthEstimator.estimate;
- if (currentFrameLength < this.frameLengthTierThreshold) {
- var isAnimatingAtTargetFPS = currentFrameLength < this.frameLengthDesiredThreshold;
- var hasFinishedSlowTierTest = timestamp > this._tierStartTimestamp + this.tierSlowTestLength;
-
- if (!isAnimatingAtTargetFPS && !hasFinishedSlowTierTest)
- return;
-
- // We're measuring at the target fps, so quickly move on to the next tier, or
- // we're slower than the target fps, but we've let this tier run long enough to
- // get an estimate
- this._lastTierComplexity = currentComplexity;
- this._lastTierFrameLength = currentFrameLength;
-
- if (currentComplexity <= 50)
- this._tier += 1/2;
- else if (currentComplexity <= 10000)
- this._tier += 1/4;
- else
- this._tier += 1/8;
- this._endTimestamp = timestamp + this._testLength;
- var nextTierComplexity = Math.max(Math.round(Math.pow(10, this._tier)), currentComplexity + 1);
- stage.tune(nextTierComplexity - currentComplexity);
-
- // Some tests may be unable to go beyond a certain capacity. If so, don't keep moving up tiers
- if (stage.complexity() - currentComplexity > 0 || nextTierComplexity == 1) {
- this._tierStartTimestamp = timestamp;
- this.mark("Complexity: " + nextTierComplexity, timestamp);
- return;
- }
- } else if (timestamp < this._tierStartTimestamp + this.tierSlowTestLength)
- return;
-
- this._finishedTierSampling = true;
- this.isFrameLengthEstimatorEnabled = false;
- this.intervalSamplingLength = 120;
-
- // Extend the test length so that the full test length is made of the ramps
- this._endTimestamp = timestamp + this._testLength;
- this.mark(Strings.json.samplingStartTimeOffset, timestamp);
-
- this._minimumComplexity = 1;
- this._possibleMinimumComplexity = this._minimumComplexity;
- this._minimumComplexityEstimator.sample(this._minimumComplexity);
-
- // Sometimes this last tier will drop the frame length well below the threshold.
- // Avoid going down that far since it means fewer measurements are taken in the target fps area.
- // Interpolate a maximum complexity that gets us around the lowest threshold.
- // Avoid doing this calculation if we never get out of the first tier (where this._lastTierComplexity is undefined).
- if (this._lastTierComplexity && this._lastTierComplexity != currentComplexity)
- this._maximumComplexity = Math.floor(Utilities.lerp(Utilities.progressValue(this.frameLengthTierThreshold, this._lastTierFrameLength, currentFrameLength), this._lastTierComplexity, currentComplexity));
- else {
- // If the browser is capable of handling the most complex version of the test, use that
- this._maximumComplexity = currentComplexity;
- }
- this._possibleMaximumComplexity = this._maximumComplexity;
-
- // If we get ourselves onto a ramp where the maximum complexity does not yield slow enough FPS,
- // We'll use this as a boundary to find a higher maximum complexity for the next ramp
- this._lastTierComplexity = currentComplexity;
- this._lastTierFrameLength = currentFrameLength;
-
- // First ramp
- stage.tune(this._maximumComplexity - currentComplexity);
- this._rampDidWarmup = false;
- // Start timestamp represents start of ramp iteration and warm up
- this._rampStartTimestamp = timestamp;
- return;
- }
-
- if ((timestamp - this._rampStartTimestamp) < this.rampWarmupLength)
- return;
-
- if (this._rampDidWarmup)
- return;
-
- this._rampDidWarmup = true;
- this._currentRampLength = this._rampStartTimestamp + this._rampLength - timestamp;
- // Start timestamp represents start of ramp down, after warm up
- this._rampStartTimestamp = timestamp;
- this._rampStartIndex = this._sampler.sampleCount;
- },
-
- tune: function(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength)
- {
- if (!this._rampDidWarmup)
- return;
-
- this._intervalFrameLengthEstimator.sample(lastFrameLength);
- if (!didFinishInterval)
- return;
-
- var currentComplexity = stage.complexity();
- var intervalFrameLengthMean = this._intervalFrameLengthEstimator.mean();
- var intervalFrameLengthStandardDeviation = this._intervalFrameLengthEstimator.standardDeviation();
-
- if (intervalFrameLengthMean < this.frameLengthDesiredThreshold && this._intervalFrameLengthEstimator.cdf(this.frameLengthDesiredThreshold) > .9) {
- this._possibleMinimumComplexity = Math.max(this._possibleMinimumComplexity, currentComplexity);
- } else if (intervalFrameLengthStandardDeviation > 2) {
- // In the case where we might have found a previous interval where the target fps was reached. We hit a significant blip,
- // so we should resample this area in the next ramp.
- this._possibleMinimumComplexity = 1;
- }
- if (intervalFrameLengthMean - intervalFrameLengthStandardDeviation > this.frameLengthRampLowerThreshold)
- this._possibleMaximumComplexity = Math.min(this._possibleMaximumComplexity, currentComplexity);
- this._intervalFrameLengthEstimator.reset();
-
- var progress = (timestamp - this._rampStartTimestamp) / this._currentRampLength;
-
- if (progress < 1) {
- // Reframe progress percentage so that the last interval of the ramp can sample at minimum complexity
- progress = (timestamp - this._rampStartTimestamp) / (this._currentRampLength - this.intervalSamplingLength);
- stage.tune(Math.max(this._minimumComplexity, Math.floor(Utilities.lerp(progress, this._maximumComplexity, this._minimumComplexity))) - currentComplexity);
- return;
- }
-
- var regressionData = [];
- for (var i = this._rampStartIndex; i < this._sampler.sampleCount; ++i) {
- if (this._getFrameType(this._sampler.samples, i) == Strings.json.mutationFrameType)
- continue;
- regressionData.push([ this._getComplexity(this._sampler.samples, i), this._getFrameLength(this._sampler.samples, i) ]);
- }
-
- var regression = new Regression(regressionData, this._sampler.sampleCount - 1, this._rampStartIndex, { desiredFrameLength: this.frameLengthDesired });
- this._rampRegressions.push(regression);
-
- var frameLengthAtMaxComplexity = regression.valueAt(this._maximumComplexity);
- if (frameLengthAtMaxComplexity < this.frameLengthRampLowerThreshold)
- this._possibleMaximumComplexity = Math.floor(Utilities.lerp(Utilities.progressValue(this.frameLengthRampLowerThreshold, frameLengthAtMaxComplexity, this._lastTierFrameLength), this._maximumComplexity, this._lastTierComplexity));
- // If the regression doesn't fit the first segment at all, keep the minimum bound at 1
- if ((timestamp - this._sampler.samples[sampleTimeIndex][this._sampler.sampleCount - regression.n1]) / this._currentRampLength < .25)
- this._possibleMinimumComplexity = 1;
-
- this._minimumComplexityEstimator.sample(this._possibleMinimumComplexity);
- this._minimumComplexity = Math.round(this._minimumComplexityEstimator.mean());
-
- if (frameLengthAtMaxComplexity < this.frameLengthRampUpperThreshold) {
- this._changePointEstimator.sample(regression.complexity);
- // Ideally we'll target the change point in the middle of the ramp. If the range of the ramp is too small, there isn't enough
- // range along the complexity (x) axis for a good regression calculation to be made, so force at least a range of 5
- // particles. Make it possible to increase the maximum complexity in case unexpected noise caps the regression too low.
- this._maximumComplexity = Math.round(this._minimumComplexity +
- Math.max(5,
- this._possibleMaximumComplexity - this._minimumComplexity,
- (this._changePointEstimator.mean() - this._minimumComplexity) * 2));
- } else {
- // The slowest samples weighed the regression too heavily
- this._maximumComplexity = Math.max(Math.round(.8 * this._maximumComplexity), this._minimumComplexity + 5);
- }
-
- // Next ramp
- stage.tune(this._maximumComplexity - stage.complexity());
- this._rampDidWarmup = false;
- // Start timestamp represents start of ramp iteration and warm up
- this._rampStartTimestamp = timestamp;
- this._possibleMinimumComplexity = 1;
- this._possibleMaximumComplexity = this._maximumComplexity;
- },
-
- processSamples: function(results)
- {
- results[Strings.json.marks] = this._processMarks();
- // Have samplingTimeOffset represent time 0
- var startTimestamp = this._marks[Strings.json.samplingStartTimeOffset].time;
- for (var markName in results[Strings.json.marks]) {
- results[Strings.json.marks][markName].time -= startTimestamp;
- }
-
- results[Strings.json.samples] = {};
-
- var controllerSamples = this._processControllerSamples();
- results[Strings.json.samples][Strings.json.controller] = controllerSamples;
- controllerSamples.forEach(function(timeSample) {
- controllerSamples.setFieldInDatum(timeSample, Strings.json.time, controllerSamples.getFieldInDatum(timeSample, Strings.json.time) - startTimestamp);
- });
-
- // Aggregate all of the ramps into one big complexity-frameLength dataset
- var complexitySamples = new SampleData(controllerSamples.fieldMap);
- results[Strings.json.samples][Strings.json.complexity] = complexitySamples;
-
- results[Strings.json.controller] = [];
- this._rampRegressions.forEach(function(ramp) {
- var startIndex = ramp.startIndex, endIndex = ramp.endIndex;
- var startTime = controllerSamples.getFieldInDatum(startIndex, Strings.json.time);
- var endTime = controllerSamples.getFieldInDatum(endIndex, Strings.json.time);
- var startComplexity = controllerSamples.getFieldInDatum(startIndex, Strings.json.complexity);
- var endComplexity = controllerSamples.getFieldInDatum(endIndex, Strings.json.complexity);
-
- var regression = {};
- results[Strings.json.controller].push(regression);
-
- var percentage = (ramp.complexity - startComplexity) / (endComplexity - startComplexity);
- var inflectionTime = startTime + percentage * (endTime - startTime);
-
- regression[Strings.json.regressions.segment1] = [
- [startTime, ramp.s2 + ramp.t2 * startComplexity],
- [inflectionTime, ramp.s2 + ramp.t2 * ramp.complexity]
- ];
- regression[Strings.json.regressions.segment2] = [
- [inflectionTime, ramp.s1 + ramp.t1 * ramp.complexity],
- [endTime, ramp.s1 + ramp.t1 * endComplexity]
- ];
- regression[Strings.json.complexity] = ramp.complexity;
- regression[Strings.json.regressions.startIndex] = startIndex;
- regression[Strings.json.regressions.endIndex] = endIndex;
- regression[Strings.json.regressions.profile] = ramp.profile;
-
- for (var j = startIndex; j <= endIndex; ++j)
- complexitySamples.push(controllerSamples.at(j));
- });
-
- this._processComplexitySamples(complexitySamples);
- }
-});
-
-Stage = Utilities.createClass(
- function()
- {
- }, {
-
- initialize: function(benchmark)
- {
- this._benchmark = benchmark;
- this._element = document.getElementById("stage");
- this._element.setAttribute("width", document.body.offsetWidth);
- this._element.setAttribute("height", document.body.offsetHeight);
- this._size = Point.elementClientSize(this._element).subtract(Insets.elementPadding(this._element).size);
- },
-
- get element()
- {
- return this._element;
- },
-
- get size()
- {
- return this._size;
- },
-
- complexity: function()
- {
- return 0;
- },
-
- tune: function()
- {
- throw "Not implemented";
- },
-
- animate: function()
- {
- throw "Not implemented";
- },
-
- clear: function()
- {
- return this.tune(-this.tune(0));
- }
-});
-
-Utilities.extendObject(Stage, {
- random: function(min, max)
- {
- return (Pseudo.random() * (max - min)) + min;
- },
-
- randomBool: function()
- {
- return !!Math.round(Pseudo.random());
- },
-
- randomSign: function()
- {
- return Pseudo.random() >= .5 ? 1 : -1;
- },
-
- randomInt: function(min, max)
- {
- return Math.floor(this.random(min, max + 1));
- },
-
- randomPosition: function(maxPosition)
- {
- return new Point(this.randomInt(0, maxPosition.x), this.randomInt(0, maxPosition.y));
- },
-
- randomSquareSize: function(min, max)
- {
- var side = this.random(min, max);
- return new Point(side, side);
- },
-
- randomVelocity: function(maxVelocity)
- {
- return this.random(maxVelocity / 8, maxVelocity);
- },
-
- randomAngle: function()
- {
- return this.random(0, Math.PI * 2);
- },
-
- randomColor: function()
- {
- var min = 32;
- var max = 256 - 32;
- return "#"
- + this.randomInt(min, max).toString(16)
- + this.randomInt(min, max).toString(16)
- + this.randomInt(min, max).toString(16);
- },
-
- randomStyleMixBlendMode: function()
- {
- var mixBlendModeList = [
- 'normal',
- 'multiply',
- 'screen',
- 'overlay',
- 'darken',
- 'lighten',
- 'color-dodge',
- 'color-burn',
- 'hard-light',
- 'soft-light',
- 'difference',
- 'exclusion',
- 'hue',
- 'saturation',
- 'color',
- 'luminosity'
- ];
-
- return mixBlendModeList[this.randomInt(0, mixBlendModeList.length)];
- },
-
- randomStyleFilter: function()
- {
- var filterList = [
- 'grayscale(50%)',
- 'sepia(50%)',
- 'saturate(50%)',
- 'hue-rotate(180)',
- 'invert(50%)',
- 'opacity(50%)',
- 'brightness(50%)',
- 'contrast(50%)',
- 'blur(10px)',
- 'drop-shadow(10px 10px 10px gray)'
- ];
-
- return filterList[this.randomInt(0, filterList.length)];
- },
-
- randomElementInArray: function(array)
- {
- return array[Stage.randomInt(0, array.length - 1)];
- },
-
- rotatingColor: function(cycleLengthMs, saturation, lightness)
- {
- return "hsl("
- + Stage.dateFractionalValue(cycleLengthMs) * 360 + ", "
- + ((saturation || .8) * 100).toFixed(0) + "%, "
- + ((lightness || .35) * 100).toFixed(0) + "%)";
- },
-
- // Returns a fractional value that wraps around within [0,1]
- dateFractionalValue: function(cycleLengthMs)
- {
- return (Date.now() / (cycleLengthMs || 2000)) % 1;
- },
-
- // Returns an increasing value slowed down by factor
- dateCounterValue: function(factor)
- {
- return Date.now() / factor;
- },
-
- randomRotater: function()
- {
- return new Rotater(this.random(1000, 10000));
- }
-});
-
-Rotater = Utilities.createClass(
- function(rotateInterval)
- {
- this._timeDelta = 0;
- this._rotateInterval = rotateInterval;
- this._isSampling = false;
- }, {
-
- get interval()
- {
- return this._rotateInterval;
- },
-
- next: function(timeDelta)
- {
- this._timeDelta = (this._timeDelta + timeDelta) % this._rotateInterval;
- },
-
- degree: function()
- {
- return (360 * this._timeDelta) / this._rotateInterval;
- },
-
- rotateZ: function()
- {
- return "rotateZ(" + Math.floor(this.degree()) + "deg)";
- },
-
- rotate: function(center)
- {
- return "rotate(" + Math.floor(this.degree()) + ", " + center.x + "," + center.y + ")";
- }
-});
-
-Benchmark = Utilities.createClass(
- function(stage, options)
- {
- this._animateLoop = this._animateLoop.bind(this);
- this._warmupLength = options["warmup-length"];
- this._frameCount = 0;
- this._warmupFrameCount = options["warmup-frame-count"];
- this._firstFrameMinimumLength = options["first-frame-minimum-length"];
-
- this._stage = stage;
- this._stage.initialize(this, options);
-
- switch (options["time-measurement"])
- {
- case "performance":
- if (window.performance && window.performance.now)
- this._getTimestamp = performance.now.bind(performance);
- else
- this._getTimestamp = null;
- break;
- case "raf":
- this._getTimestamp = null;
- break;
- case "date":
- this._getTimestamp = Date.now;
- break;
- }
-
- options["test-interval"] *= 1000;
- switch (options["controller"])
- {
- case "fixed":
- this._controller = new FixedController(this, options);
- break;
- case "adaptive":
- this._controller = new AdaptiveController(this, options);
- break;
- case "ramp":
- this._controller = new RampController(this, options);
- break;
- }
- }, {
-
- get stage()
- {
- return this._stage;
- },
-
- get timestamp()
- {
- return this._currentTimestamp - this._benchmarkStartTimestamp;
- },
-
- backgroundColor: function()
- {
- var stage = window.getComputedStyle(document.getElementById("stage"));
- return stage["background-color"];
- },
-
- run: function()
- {
- return this.waitUntilReady().then(function() {
- this._finishPromise = new SimplePromise;
- this._previousTimestamp = undefined;
- this._didWarmUp = false;
- this._stage.tune(this._controller.initialComplexity - this._stage.complexity());
- this._animateLoop();
- return this._finishPromise;
- }.bind(this));
- },
-
- // Subclasses should override this if they have setup to do prior to commencing.
- waitUntilReady: function()
- {
- var promise = new SimplePromise;
- promise.resolve();
- return promise;
- },
-
- _animateLoop: function(timestamp)
- {
- timestamp = (this._getTimestamp && this._getTimestamp()) || timestamp;
- this._currentTimestamp = timestamp;
-
- if (this._controller.shouldStop(timestamp)) {
- this._finishPromise.resolve(this._controller.results());
- return;
- }
-
- if (!this._didWarmUp) {
- if (!this._previousTimestamp) {
- this._previousTimestamp = timestamp;
- this._benchmarkStartTimestamp = timestamp;
- } else if (timestamp - this._previousTimestamp >= this._warmupLength && this._frameCount >= this._warmupFrameCount) {
- this._didWarmUp = true;
- this._benchmarkStartTimestamp = timestamp;
- this._controller.start(timestamp, this._stage);
- this._previousTimestamp = timestamp;
-
- while (this._getTimestamp && this._getTimestamp() - timestamp < this._firstFrameMinimumLength) {
- }
- }
-
- this._stage.animate(0);
- ++this._frameCount;
- requestAnimationFrame(this._animateLoop);
- return;
- }
-
- this._controller.update(timestamp, this._stage);
- this._stage.animate(timestamp - this._previousTimestamp);
- this._previousTimestamp = timestamp;
- requestAnimationFrame(this._animateLoop);
- }
-});
diff --git a/MotionMark/tests/resources/math.js b/MotionMark/tests/resources/math.js
deleted file mode 100644
index e96a517..0000000
--- a/MotionMark/tests/resources/math.js
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-SimpleKalmanEstimator = Utilities.createSubclass(Experiment,
- function(processError, measurementError) {
- Experiment.call(this, false);
- var error = .5 * (Math.sqrt(processError * processError + 4 * processError * measurementError) - processError);
- this._gain = error / (error + measurementError);
- }, {
-
- sample: function(newMeasurement)
- {
- if (!this._initialized) {
- this._initialized = true;
- this.estimate = newMeasurement;
- return;
- }
-
- this.estimate = this.estimate + this._gain * (newMeasurement - this.estimate);
- },
-
- reset: function()
- {
- Experiment.prototype.reset.call(this);
- this._initialized = false;
- this.estimate = 0;
- }
-});
-
-PIDController = Utilities.createClass(
- function(ysp)
- {
- this._ysp = ysp;
- this._out = 0;
-
- this._Kp = 0;
- this._stage = PIDController.stages.WARMING;
-
- this._eold = 0;
- this._I = 0;
- }, {
-
- // Determines whether the current y is
- // before ysp => (below ysp if ysp > y0) || (above ysp if ysp < y0)
- // after ysp => (above ysp if ysp > y0) || (below ysp if ysp < y0)
- _yPosition: function(y)
- {
- return (y < this._ysp) == (this._y0 < this._ysp)
- ? PIDController.yPositions.BEFORE_SETPOINT
- : PIDController.yPositions.AFTER_SETPOINT;
- },
-
- // Calculate the ultimate distance from y0 after time t. We want to move very
- // slowly at the beginning to see how adding few items to the test can affect
- // its output. The complexity of a single item might be big enough to keep the
- // proportional gain very small but achieves the desired progress. But if y does
- // not change significantly after adding few items, that means we need a much
- // bigger gain. So we need to move over a cubic curve which increases very
- // slowly with small t values but moves very fast with larger t values.
- // The basic formula is: y = t^3
- // Change the formula to reach y=1 after 1000 ms: y = (t/1000)^3
- // Change the formula to reach y=(ysp - y0) after 1000 ms: y = (ysp - y0) * (t/1000)^3
- _distanceUltimate: function(t)
- {
- return (this._ysp - this._y0) * Math.pow(t / 1000, 3);
- },
-
- // Calculates the distance of y relative to y0. It also ensures we do not return
- // zero by returning a epsilon value in the same direction as ultimate distance.
- _distance: function(y, du)
- {
- const epsilon = 0.0001;
- var d = y - this._y0;
- return du < 0 ? Math.min(d, -epsilon) : Math.max(d, epsilon);
- },
-
- // Decides how much the proportional gain should be increased during the manual
- // gain stage. We choose to use the ratio of the ultimate distance to the current
- // distance as an indication of how much the system is responsive. We want
- // to keep the increment under control so it does not cause the system instability
- // So we choose to take the natural logarithm of this ratio.
- _gainIncrement: function(t, y, e)
- {
- var du = this._distanceUltimate(t);
- var d = this._distance(y, du);
- return Math.log(du / d) * 0.1;
- },
-
- // Update the stage of the controller based on its current stage and the system output
- _updateStage: function(y)
- {
- var yPosition = this._yPosition(y);
-
- switch (this._stage) {
- case PIDController.stages.WARMING:
- if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
- this._stage = PIDController.stages.OVERSHOOT;
- break;
-
- case PIDController.stages.OVERSHOOT:
- if (yPosition == PIDController.yPositions.BEFORE_SETPOINT)
- this._stage = PIDController.stages.UNDERSHOOT;
- break;
-
- case PIDController.stages.UNDERSHOOT:
- if (yPosition == PIDController.yPositions.AFTER_SETPOINT)
- this._stage = PIDController.stages.SATURATE;
- break;
- }
- },
-
- // Manual tuning is used before calculating the PID controller gains.
- _tuneP: function(e)
- {
- // The output is the proportional term only.
- return this._Kp * e;
- },
-
- // PID tuning function. Kp, Ti and Td were already calculated
- _tunePID: function(h, y, e)
- {
- // Proportional term.
- var P = this._Kp * e;
-
- // Integral term is the area under the curve starting from the beginning
- // till the current time.
- this._I += (this._Kp / this._Ti) * ((e + this._eold) / 2) * h;
-
- // Derivative term is the slope of the curve at the current time.
- var D = (this._Kp * this._Td) * (e - this._eold) / h;
-
- // The ouput is a PID function.
- return P + this._I + D;
- },
-
- // Apply different strategies for the tuning based on the stage of the controller.
- _tune: function(t, h, y, e)
- {
- switch (this._stage) {
- case PIDController.stages.WARMING:
- // This is the first stage of the ZieglerâNichols method. It increments
- // the proportional gain till the system output passes the set-point value.
- if (typeof this._y0 == "undefined") {
- // This is the first time a tuning value is required. We want the test
- // to add only one item. So we need to return -1 which forces us to
- // choose the initial value of Kp to be = -1 / e
- this._y0 = y;
- this._Kp = -1 / e;
- } else {
- // Keep incrementing the Kp as long as we have not reached the
- // set-point yet
- this._Kp += this._gainIncrement(t, y, e);
- }
-
- return this._tuneP(e);
-
- case PIDController.stages.OVERSHOOT:
- // This is the second stage of the ZieglerâNichols method. It measures the
- // oscillation period.
- if (typeof this._t0 == "undefined") {
- // t is the time of the begining of the first overshot
- this._t0 = t;
- this._Kp /= 2;
- }
-
- return this._tuneP(e);
-
- case PIDController.stages.UNDERSHOOT:
- // This is the end of the ZieglerâNichols method. We need to calculate the
- // integral and derivative periods.
- if (typeof this._Ti == "undefined") {
- // t is the time of the end of the first overshot
- var Tu = t - this._t0;
-
- // Calculate the system parameters from Kp and Tu assuming
- // a "some overshoot" control type. See:
- // https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
- this._Ti = Tu / 2;
- this._Td = Tu / 3;
- this._Kp = 0.33 * this._Kp;
-
- // Calculate the tracking time.
- this._Tt = Math.sqrt(this._Ti * this._Td);
- }
-
- return this._tunePID(h, y, e);
-
- case PIDController.stages.SATURATE:
- return this._tunePID(h, y, e);
- }
-
- return 0;
- },
-
- // Ensures the system does not fluctuates.
- _saturate: function(v, e)
- {
- var u = v;
-
- switch (this._stage) {
- case PIDController.stages.OVERSHOOT:
- case PIDController.stages.UNDERSHOOT:
- // Calculate the min-max values of the saturation actuator.
- if (typeof this._min == "undefined")
- this._min = this._max = this._out;
- else {
- this._min = Math.min(this._min, this._out);
- this._max = Math.max(this._max, this._out);
- }
- break;
-
- case PIDController.stages.SATURATE:
- const limitPercentage = 0.90;
- var min = this._min > 0 ? Math.min(this._min, this._max * limitPercentage) : this._min;
- var max = this._max < 0 ? Math.max(this._max, this._min * limitPercentage) : this._max;
- var out = this._out + u;
-
- // Clip the controller output to the min-max values
- out = Math.max(Math.min(max, out), min);
- u = out - this._out;
-
- // Apply the back-calculation and tracking
- if (u != v)
- u += (this._Kp * this._Tt / this._Ti) * e;
- break;
- }
-
- this._out += u;
- return u;
- },
-
- // Called from the benchmark to tune its test. It uses Ziegler-Nichols method
- // to calculate the controller parameters. It then returns a PID tuning value.
- tune: function(t, h, y)
- {
- this._updateStage(y);
-
- // Current error.
- var e = this._ysp - y;
- var v = this._tune(t, h, y, e);
-
- // Save e for the next call.
- this._eold = e;
-
- // Apply back-calculation and tracking to avoid integrator windup
- return this._saturate(v, e);
- }
-});
-
-Utilities.extendObject(PIDController, {
- // This enum will be used to tell whether the system output (or the controller input)
- // is moving towards the set-point or away from it.
- yPositions: {
- BEFORE_SETPOINT: 0,
- AFTER_SETPOINT: 1
- },
-
- // The Ziegler-Nichols method for is used tuning the PID controller. The workflow of
- // the tuning is split into four stages. The first two stages determine the values
- // of the PID controller gains. During these two stages we return the proportional
- // term only. The third stage is used to determine the min-max values of the
- // saturation actuator. In the last stage back-calculation and tracking are applied
- // to avoid integrator windup. During the last two stages, we return a PID control
- // value.
- stages: {
- WARMING: 0, // Increase the value of the Kp until the system output reaches ysp.
- OVERSHOOT: 1, // Measure the oscillation period and the overshoot value
- UNDERSHOOT: 2, // Return PID value and measure the undershoot value
- SATURATE: 3 // Return PID value and apply back-calculation and tracking.
- }
-});
diff --git a/MotionMark/tests/resources/star.svg b/MotionMark/tests/resources/star.svg
deleted file mode 100644
index 3c46ae0..0000000
--- a/MotionMark/tests/resources/star.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/MotionMark/tests/resources/yin-yang.png b/MotionMark/tests/resources/yin-yang.png
deleted file mode 100644
index 3162f6e..0000000
Binary files a/MotionMark/tests/resources/yin-yang.png and /dev/null differ
diff --git a/MotionMark/tests/resources/yin-yang.svg b/MotionMark/tests/resources/yin-yang.svg
deleted file mode 100644
index 4412626..0000000
--- a/MotionMark/tests/resources/yin-yang.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/MotionMark/tests/simple/resources/simple-canvas-paths.js b/MotionMark/tests/simple/resources/simple-canvas-paths.js
deleted file mode 100644
index 143630d..0000000
--- a/MotionMark/tests/simple/resources/simple-canvas-paths.js
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-// === PAINT OBJECTS ===
-
-CanvasLineSegment = Utilities.createClass(
- function(stage) {
- var radius = Stage.randomInt(10, 100);
- var center = Stage.randomPosition(stage.size);
- var delta = Point.pointOnCircle(Stage.randomAngle(), radius/2);
-
- this._point1 = center.add(delta);
- this._point2 = center.subtract(delta);
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 100);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.moveTo(this._point1.x, this._point1.y);
- context.lineTo(this._point2.x, this._point2.y);
- context.stroke();
- }
-});
-
-CanvasLinePoint = Utilities.createClass(
- function(stage, coordinateMaximumFactor) {
- var pointMaximum = new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y));
- this._point = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- }, {
-
- draw: function(context) {
- context.lineTo(this._point.x, this._point.y);
- }
-})
-
-CanvasQuadraticSegment = Utilities.createClass(
- function(stage) {
- var maxSize = Stage.randomInt(20, 200);
- var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
-
- this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 50);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.moveTo(this._point1.x, this._point1.y);
- context.quadraticCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y);
- context.stroke();
- }
-});
-
-CanvasQuadraticPoint = Utilities.createClass(
- function(stage, coordinateMaximumFactor) {
- var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
- this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- }, {
-
- draw: function(context) {
- context.quadraticCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y);
- }
-});
-
-CanvasBezierSegment = Utilities.createClass(
- function(stage) {
- var maxSize = Stage.randomInt(20, 200);
- var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
-
- this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point4 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 50);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.moveTo(this._point1.x, this._point1.y);
- context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._point4.x, this._point4.y);
- context.stroke();
- }
-});
-
-CanvasBezierPoint = Utilities.createClass(
- function(stage, coordinateMaximumFactor) {
- var pointMaximum = Stage.randomPosition(new Point(Math.min(stage.size.x, coordinateMaximumFactor * stage.size.x), Math.min(stage.size.y, coordinateMaximumFactor * stage.size.y)));
- this._point1 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- this._point2 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- this._point3 = Stage.randomPosition(pointMaximum).add(new Point((stage.size.x - pointMaximum.x) / 2, (stage.size.y - pointMaximum.y) / 2));
- }, {
-
- draw: function(context) {
- context.bezierCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y, this._point3.x, this._point3.y);
- }
-});
-
-CanvasArcToSegment = Utilities.createClass(
- function(stage) {
- var maxSize = Stage.randomInt(20, 200);
- var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
-
- this._point1 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point2 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._point3 = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._radius = Stage.randomInt(20, 200);
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 50);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.moveTo(this._point1.x, this._point1.y);
- context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
- context.stroke();
- }
-});
-
-CanvasArcToSegmentFill = Utilities.createClass(
- function(stage) {
- CanvasArcToSegment.call(this, stage);
- }, {
-
- draw: function(context) {
- context.fillStyle = this._color;
- context.beginPath();
- context.moveTo(this._point1.x, this._point1.y);
- context.arcTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this._radius);
- context.fill();
- }
-});
-
-CanvasArcSegment = Utilities.createClass(
- function(stage) {
- var maxSize = Stage.randomInt(20, 200);
- var toCenter = Stage.randomPosition(stage.size).subtract(new Point(maxSize/2, maxSize/2));
-
- this._point = Stage.randomPosition(new Point(maxSize, maxSize)).add(toCenter);
- this._radius = Stage.randomInt(20, 200);
- this._startAngle = Stage.randomAngle();
- this._endAngle = Stage.randomAngle();
- this._counterclockwise = Stage.randomBool();
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 50);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
- context.stroke();
- }
-});
-
-CanvasArcSegmentFill = Utilities.createClass(
- function(stage) {
- CanvasArcSegment.call(this, stage);
- }, {
-
- draw: function(context) {
- context.fillStyle = this._color;
- context.beginPath();
- context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
- context.fill();
- }
-});
-
-CanvasRect = Utilities.createClass(
- function(stage) {
- this._width = Stage.randomInt(20, 200);
- this._height = Stage.randomInt(20, 200);
- this._point = Stage.randomPosition(stage.size).subtract(new Point(this._width/2, this._height/2));
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 20);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.rect(this._point.x, this._point.y, this._width, this._height);
- context.stroke();
- }
-});
-
-CanvasRectFill = Utilities.createClass(
- function(stage) {
- CanvasRect.call(this, stage);
- }, {
-
- draw: function(context) {
- context.fillStyle = this._color;
- context.beginPath();
- context.rect(this._point.x, this._point.y, this._width, this._height);
- context.fill();
- }
-});
-
-CanvasEllipse = Utilities.createClass(
- function(stage) {
- this._radius = new Point(Stage.randomInt(20, 200), Stage.randomInt(20, 200));
- var toCenter = Stage.randomPosition(stage.size).subtract(this._radius.multiply(.5));
-
- this._center = Stage.randomPosition(this._radius).add(toCenter);
- this._rotation = Stage.randomAngle();
- this._startAngle = Stage.randomAngle();
- this._endAngle = Stage.randomAngle();
- this._anticlockwise = Stage.randomBool();
- this._color = Stage.randomColor();
- this._lineWidth = Stage.randomInt(1, 20);
- }, {
-
- draw: function(context) {
- context.strokeStyle = this._color;
- context.lineWidth = this._lineWidth;
- context.beginPath();
- context.ellipse(this._center.x, this._center.y, this._radius.width, this._radius.height, this._rotation, this._startAngle, this._endAngle, this._anticlockwise);
- context.stroke();
- }
-});
-
-CanvasEllipseFill = Utilities.createClass(
- function(stage) {
- CanvasEllipse.call(this, stage);
- }, {
-
- draw: function(context) {
- context.fillStyle = this._color;
- context.beginPath();
- context.ellipse(this._center.x, this._center.y, this._radius.width, this._radius.height, this._rotation, this._startAngle, this._endAngle, this._anticlockwise);
- context.fill();
- }
-});
-
-CanvasStroke = Utilities.createClass(
- function (stage) {
- this._object = new (Stage.randomElementInArray(this.objectTypes))(stage);
- }, {
-
- objectTypes: [
- CanvasQuadraticSegment,
- CanvasBezierSegment,
- CanvasArcToSegment,
- CanvasArcSegment,
- CanvasRect,
- CanvasEllipse
- ],
-
- draw: function(context) {
- this._object.draw(context);
- }
-});
-
-CanvasFill = Utilities.createClass(
- function (stage) {
- this._object = new (Stage.randomElementInArray(this.objectTypes))(stage);
- }, {
-
- objectTypes: [
- CanvasArcToSegmentFill,
- CanvasArcSegmentFill,
- CanvasRectFill,
- CanvasEllipseFill
- ],
-
- draw: function(context) {
- this._object.draw(context);
- }
-});
-
-// === STAGES ===
-
-SimpleCanvasPathStrokeStage = Utilities.createSubclass(SimpleCanvasStage,
- function(canvasObject) {
- SimpleCanvasStage.call(this, canvasObject);
- }, {
-
- animate: function()
- {
- var context = this.context;
- context.clearRect(0, 0, this.size.x, this.size.y);
- context.lineWidth = Stage.randomInt(1, 20);
- context.strokeStyle = Stage.rotatingColor();
- context.beginPath();
- context.moveTo(this.size.x / 2, this.size.y / 2);
- for (var i = 0, length = this.offsetIndex; i < length; ++i)
- this.objects[i].draw(context);
- context.stroke();
- }
-});
-
-SimpleCanvasPathFillStage = Utilities.createSubclass(SimpleCanvasStage,
- function(canvasObject) {
- SimpleCanvasStage.call(this, canvasObject);
- }, {
-
- animate: function()
- {
- var context = this.context;
- context.clearRect(0, 0, this.size.x, this.size.y);
- context.fillStyle = Stage.rotatingColor();
- context.beginPath();
- context.moveTo(this.size.x / 2, this.size.y / 2);
- for (var i = 0, length = this.offsetIndex; i < length; ++i)
- this.objects[i].draw(context);
- context.fill();
- }
-});
-
-CanvasLineSegmentStage = Utilities.createSubclass(SimpleCanvasStage,
- function()
- {
- SimpleCanvasStage.call(this, CanvasLineSegment);
- }, {
-
- initialize: function(benchmark, options)
- {
- SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
- this.context.lineCap = options["lineCap"] || "butt";
- }
-});
-
-CanvasLinePathStage = Utilities.createSubclass(SimpleCanvasPathStrokeStage,
- function()
- {
- SimpleCanvasPathStrokeStage.call(this, CanvasLinePoint);
- }, {
-
- initialize: function(benchmark, options)
- {
- SimpleCanvasPathStrokeStage.prototype.initialize.call(this, benchmark, options);
- this.context.lineJoin = options["lineJoin"] || "bevel";
- }
-});
-
-CanvasLineDashStage = Utilities.createSubclass(SimpleCanvasStage,
- function()
- {
- SimpleCanvasStage.call(this, CanvasLinePoint);
- this._step = 0;
- }, {
-
- initialize: function(benchmark, options)
- {
- SimpleCanvasStage.prototype.initialize.call(this, benchmark, options);
- this.context.setLineDash([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
- this.context.lineWidth = 1;
- this.context.strokeStyle = "#000";
- },
-
- animate: function()
- {
- var context = this.context;
- context.clearRect(0, 0, this.size.x, this.size.y);
- context.lineDashOffset = this._step++;
- context.beginPath();
- context.moveTo(this.size.x / 2, this.size.y / 2);
- for (var i = 0, length = this.offsetIndex; i < length; ++i)
- this.objects[i].draw(context);
- context.stroke();
- }
-});
-
-// === BENCHMARK ===
-
-CanvasPathBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- var stage;
- switch (options["pathType"]) {
- case "line":
- stage = new CanvasLineSegmentStage();
- break;
- case "linePath": {
- if ("lineJoin" in options)
- stage = new CanvasLinePathStage();
- if ("lineDash" in options)
- stage = new CanvasLineDashStage();
- break;
- }
- case "quadratic":
- stage = new SimpleCanvasStage(CanvasQuadraticSegment);
- break;
- case "quadraticPath":
- stage = new SimpleCanvasPathStrokeStage(CanvasQuadraticPoint);
- break;
- case "bezier":
- stage = new SimpleCanvasStage(CanvasBezierSegment);
- break;
- case "bezierPath":
- stage = new SimpleCanvasPathStrokeStage(CanvasBezierPoint);
- break;
- case "arcTo":
- stage = new SimpleCanvasStage(CanvasArcToSegment);
- break;
- case "arc":
- stage = new SimpleCanvasStage(CanvasArcSegment);
- break;
- case "rect":
- stage = new SimpleCanvasStage(CanvasRect);
- break;
- case "ellipse":
- stage = new SimpleCanvasStage(CanvasEllipse);
- break;
- case "lineFill":
- stage = new SimpleCanvasPathFillStage(CanvasLinePoint);
- break;
- case "quadraticFill":
- stage = new SimpleCanvasPathFillStage(CanvasQuadraticPoint);
- break;
- case "bezierFill":
- stage = new SimpleCanvasPathFillStage(CanvasBezierPoint);
- break;
- case "arcToFill":
- stage = new SimpleCanvasStage(CanvasArcToSegmentFill);
- break;
- case "arcFill":
- stage = new SimpleCanvasStage(CanvasArcSegmentFill);
- break;
- case "rectFill":
- stage = new SimpleCanvasStage(CanvasRectFill);
- break;
- case "ellipseFill":
- stage = new SimpleCanvasStage(CanvasEllipseFill);
- break;
- case "strokes":
- stage = new SimpleCanvasStage(CanvasStroke);
- break;
- case "fills":
- stage = new SimpleCanvasStage(CanvasFill);
- break;
- }
-
- Benchmark.call(this, stage, options);
- }
-);
-
-window.benchmarkClass = CanvasPathBenchmark;
-
-})();
\ No newline at end of file
diff --git a/MotionMark/tests/simple/resources/tiled-canvas-image.js b/MotionMark/tests/simple/resources/tiled-canvas-image.js
deleted file mode 100644
index 3f0700c..0000000
--- a/MotionMark/tests/simple/resources/tiled-canvas-image.js
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-CanvasImageTile = Utilities.createClass(
- function(stage, source)
- {
- this._context = stage.context;
- this._size = stage.tileSize;
- this.source = source;
- }, {
-
- getImageData: function()
- {
- this._imagedata = this._context.getImageData(this.source.x, this.source.y, this._size.width, this._size.height);
- },
-
- putImageData: function(destination)
- {
- this._context.putImageData(this._imagedata, destination.x, destination.y);
- }
-});
-
-TiledCanvasImageStage = Utilities.createSubclass(Stage,
- function(element, options)
- {
- Stage.call(this);
- }, {
-
- initialize: function(benchmark, options)
- {
- Stage.prototype.initialize.call(this, benchmark, options);
- this.context = this.element.getContext("2d");
- this._setupTiles();
- },
-
- _setupTiles: function()
- {
- const maxTilesPerRow = 50;
- const maxTilesPerCol = 50;
-
- this.tileSize = this.size.multiply(new Point(1 / maxTilesPerRow, 1 / maxTilesPerCol));
-
- this._tiles = new Array(maxTilesPerRow * maxTilesPerCol);
-
- var source = Point.zero;
- for (var index = 0; index < this._tiles.length; ++index) {
- this._tiles[index] = new CanvasImageTile(this, source);
- source = this._nextTilePosition(source);
- }
-
- this._ctiles = 0;
- },
-
- _nextTilePosition: function(destination)
- {
- var next = destination.add(this.tileSize);
-
- if (next.x >= this._size.width)
- return new Point(0, next.y >= this._size.height ? 0 : next.y);
-
- return new Point(next.x, destination.y);
- },
-
- tune: function(count)
- {
- this._ctiles += count;
-
- this._ctiles = Math.max(this._ctiles, 0);
- this._ctiles = Math.min(this._ctiles, this._tiles.length);
- },
-
- _drawBackground: function()
- {
- var size = this._benchmark._stage.size;
- var gradient = this.context.createLinearGradient(0, 0, size.width, 0);
- gradient.addColorStop(0, "red");
- gradient.addColorStop(1, "white");
- this.context.save();
- this.context.fillStyle = gradient;
- this.context.fillRect(0, 0, size.width, size.height);
- this.context.restore();
- },
-
- animate: function(timeDelta)
- {
- this._drawBackground();
-
- if (!this._ctiles)
- return;
-
- this._tiles.shuffle();
-
- var destinations = new Array(this._ctiles);
- for (var index = 0; index < this._ctiles; ++index) {
- this._tiles[index].getImageData();
- destinations[index] = this._tiles[index].source;
- }
-
- destinations.shuffle();
-
- for (var index = 0; index < this._ctiles; ++index)
- this._tiles[index].putImageData(destinations[index]);
- },
-
- complexity: function()
- {
- return this._ctiles;
- }
-});
-
-TiledCanvasImageBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- Benchmark.call(this, new TiledCanvasImageStage(), options);
- }
-);
-
-window.benchmarkClass = TiledCanvasImageBenchmark;
-
-})();
diff --git a/MotionMark/tests/simple/simple-canvas-paths.html b/MotionMark/tests/simple/simple-canvas-paths.html
deleted file mode 100644
index a914548..0000000
--- a/MotionMark/tests/simple/simple-canvas-paths.html
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/simple/tiled-canvas-image.html b/MotionMark/tests/simple/tiled-canvas-image.html
deleted file mode 100644
index 237aeac..0000000
--- a/MotionMark/tests/simple/tiled-canvas-image.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/svg/suits.html b/MotionMark/tests/svg/suits.html
deleted file mode 100644
index a39d1d8..0000000
--- a/MotionMark/tests/svg/suits.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/svg/suits.js b/MotionMark/tests/svg/suits.js
deleted file mode 100644
index 9916755..0000000
--- a/MotionMark/tests/svg/suits.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-(function() {
-
-var SuperSuitsParticle = window.SuitsParticle;
-ClipSuit = Utilities.createSubclass(SuperSuitsParticle,
- function(stage)
- {
- this.initialize(stage);
- }, {
-
- isClipPath: true,
- hasGradient: false,
- move: function()
- {
- this.element.setAttribute("transform", "translate(" + (this.position.x - this.size.center.x) + "," + (this.position.y - this.size.center.x) + ")");
- }
-});
-
-ShapeSuit = Utilities.createSubclass(SuperSuitsParticle,
- function(stage)
- {
- this.initialize(stage);
- }, {
-
- isClipPath: false,
- hasGradient: false,
- move: function()
- {
- this.element.setAttribute("transform", "translate(" + this.position.x + "," + this.position.y + ") " + this.transformSuffix);
- }
-});
-
-RotationSuit = Utilities.createSubclass(SuperSuitsParticle,
- function(stage)
- {
- this.isClipPath = stage.particleCounter % 2;
- this.initialize(stage);
- }, {
-
- hasGradient: false,
-});
-
-GradientSuit = Utilities.createSubclass(SuperSuitsParticle,
- function(stage)
- {
- this.isClipPath = stage.particleCounter % 2;
- this.initialize(stage);
- }, {
-
- hasGradient: true,
- move: function()
- {
- this.element.setAttribute("transform", "translate(" + this.position.x + "," + this.position.y + ") " + this.transformSuffix);
- }
-});
-
-StaticSuit = Utilities.createSubclass(SuperSuitsParticle,
- function(stage)
- {
- this.isClipPath = stage.particleCounter % 2;
- this.initialize(stage);
- }, {
-
- hasGradient: true,
- reset: function()
- {
- SuperSuitsParticle.prototype.reset.call(this);
- this.originalPosition = Stage.randomPosition(this.stage.size);
- this.transformSuffix = " rotate(" + Math.floor(Stage.randomAngle() * 180 / Math.PI) + ",0,0)" + this.transformSuffix;
- },
-
- move: function()
- {
- this.element.setAttribute("transform", "translate(" + this.originalPosition.x + "," + this.originalPosition.y + ") " + this.transformSuffix);
- }
-});
-
-var SuitsBenchmark = window.benchmarkClass;
-var SuitsDerivedBenchmark = Utilities.createSubclass(SuitsBenchmark,
- function(options)
- {
- switch (options["style"]) {
- case "clip":
- window.SuitsParticle = ClipSuit;
- break;
- case "shape":
- window.SuitsParticle = ShapeSuit;
- break;
- case "rotation":
- window.SuitsParticle = RotationSuit;
- break;
- case "gradient":
- window.SuitsParticle = GradientSuit;
- break;
- case "static":
- window.SuitsParticle = StaticSuit;
- break;
- }
- SuitsBenchmark.call(this, options);
- }
-);
-
-window.benchmarkClass = SuitsDerivedBenchmark;
-
-})();
diff --git a/MotionMark/tests/template/resources/template-canvas.js b/MotionMark/tests/template/resources/template-canvas.js
deleted file mode 100644
index 9a0c727..0000000
--- a/MotionMark/tests/template/resources/template-canvas.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-function TemplateCanvasObject(stage)
-{
- // For the canvas stage, most likely you will need to create your
- // animated object since it's only draw time thing.
-
- // Fill in your object data.
-}
-
-TemplateCanvasObject.prototype = {
- _draw: function()
- {
- // Draw your object.
- },
-
- animate: function(timeDelta)
- {
- // Redraw the animated object. The last time this animated
- // item was drawn before 'timeDelta'.
-
- // Move your object.
-
- // Redraw your object.
- this._draw();
- }
-};
-
-TemplateCanvasStage = Utilities.createSubclass(Stage,
- function()
- {
- Stage.call(this);
- }, {
-
- initialize: function(benchmark, options)
- {
- Stage.prototype.initialize.call(this, benchmark, options);
- this.context = this.element.getContext("2d");
-
- // Define a collection for your objects.
- },
-
- tune: function(count)
- {
- // If count is -ve, -count elements need to be removed form the
- // stage. If count is +ve, +count elements need to be added to
- // the stage.
-
- // Change objects in the stage.
- },
-
- animate: function(timeDelta)
- {
- // Animate the elements such that all of them are redrawn. Most
- // likely you will need to call TemplateCanvasObject.animate()
- // for all your animated objects here.
-
- // Most likely you will need to clear the canvas with every redraw.
- this.context.clearRect(0, 0, this.size.x, this.size.y);
-
- // Loop through all your objects and ask them to animate.
- }
-});
-
-TemplateCanvasBenchmark = Utilities.createSubclass(Benchmark,
- function(options)
- {
- Benchmark.call(this, new TemplateCanvasStage(), options);
- }, {
-
- // Override this function if the benchmark needs to wait for resources to be
- // loaded.
- //
- // Default implementation returns a resolved promise, so that the benchmark
- // benchmark starts right away. Here's an example where we're waiting 5
- // seconds before starting the benchmark.
- waitUntilReady: function()
- {
- var promise = new SimplePromise;
- window.setTimeout(function() {
- promise.resolve();
- }, 5000);
- return promise;
- }
-});
-
-window.benchmarkClass = TemplateCanvasBenchmark;
-
-})();
\ No newline at end of file
diff --git a/MotionMark/tests/template/template-canvas.html b/MotionMark/tests/template/template-canvas.html
deleted file mode 100644
index bdcab6f..0000000
--- a/MotionMark/tests/template/template-canvas.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/template/template-css.html b/MotionMark/tests/template/template-css.html
deleted file mode 100644
index ed6b6ca..0000000
--- a/MotionMark/tests/template/template-css.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/template/template-svg.html b/MotionMark/tests/template/template-svg.html
deleted file mode 100644
index eb7a034..0000000
--- a/MotionMark/tests/template/template-svg.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/text/design-6.html b/MotionMark/tests/text/design-6.html
deleted file mode 100644
index decbdd2..0000000
--- a/MotionMark/tests/text/design-6.html
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/text/design-6.js b/MotionMark/tests/text/design-6.js
deleted file mode 100644
index 9401657..0000000
--- a/MotionMark/tests/text/design-6.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-// The MotionMark-based TextBenchmark should already be set to |window.benchmarkClass|
-var TextBenchmark = window.benchmarkClass;
-var TextTemplateBenchmark = Utilities.createSubclass(TextBenchmark,
- function(options)
- {
- var dataset;
- switch (options["corpus"]) {
- case "latin":
- dataset = [
- "σχέδιο",
- "umění",
- "design",
- "искусство",
- "conception",
- "diseño"
- ];
- break;
- case "cjk":
- dataset = [
- "设计",
- "디자인",
- "デザイン",
- "예술",
- "使吃惊",
- "がいねん",
- ];
- break;
- case "arabic":
- dataset = [
- {text: "تصميم", direction: "rtl"},
- "வடிவமைப்பு",
- "योजना",
- {text: "לְעַצֵב", direction: "rtl"},
- {text: "خلاق", direction: "rtl"},
- "ศิลปะ",
- ];
- break;
- }
-
- dataset.forEach(function(entry, i) {
- var td = document.getElementById("cell" + i);
- if (typeof entry === 'string') {
- td.innerText = entry;
- } else {
- td.innerText = entry.text;
- td.classList.add("rtl");
- }
- })
-
- TextBenchmark.call(this, options);
- }
-);
-
-window.benchmarkClass = TextTemplateBenchmark;
-
-})();
\ No newline at end of file
diff --git a/MotionMark/tests/text/design.html b/MotionMark/tests/text/design.html
deleted file mode 100644
index 2de4977..0000000
--- a/MotionMark/tests/text/design.html
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MotionMark/tests/text/design.js b/MotionMark/tests/text/design.js
deleted file mode 100644
index 9ec8a80..0000000
--- a/MotionMark/tests/text/design.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function() {
-
-// The MotionMark-based TextBenchmark should already be set to |window.benchmarkClass|
-var TextBenchmark = window.benchmarkClass;
-var TextTemplateBenchmark = Utilities.createSubclass(TextBenchmark,
- function(options)
- {
- var dataset;
- switch (options["corpus"]) {
- case "latin":
- dataset = [
- "σχέδιο",
- "umění",
- "suunnittelu",
- "design",
- "deseń",
- "искусство",
- "дизайн",
- "conception",
- "kunst",
- "konstruktion",
- "τέχνη",
- "diseño"
- ];
- break;
- case "cjk":
- dataset = [
- "设计",
- "디자인",
- "デザイン",
- "がいねん",
- "藝術",
- "养殖",
- "예술",
- "展開する",
- "발달",
- "技術",
- "驚き",
- "使吃惊",
- ];
- break;
- case "arabic":
- dataset = [
- {text: "تصميم", direction: "rtl"},
- "வடிவமைப்பு",
- "योजना",
- {text: "לְעַצֵב", direction: "rtl"},
- {text: "خلاق", direction: "rtl"},
- "ศิลปะ",
- "कौशल",
- {text: "אָמָנוּת", direction: "rtl"},
- "கலை",
- "ดีไซน์",
- "পরিকল্পনা",
- {text: "ډیزاین", direction: "rtl"},
- ];
- break;
- }
-
- dataset.forEach(function(entry, i) {
- var td = document.getElementById("cell" + i);
- if (typeof entry === 'string') {
- td.innerText = entry;
- } else {
- td.innerText = entry.text;
- td.classList.add("rtl");
- }
- })
-
- TextBenchmark.call(this, options);
- }
-);
-
-window.benchmarkClass = TextTemplateBenchmark;
-
-})();
\ No newline at end of file
diff --git a/MotionMark/unit-tests/resources/js-test.js b/MotionMark/unit-tests/resources/js-test.js
new file mode 100644
index 0000000..2becb06
--- /dev/null
+++ b/MotionMark/unit-tests/resources/js-test.js
@@ -0,0 +1,968 @@
+// Copyright 2014 Google Inc. All rights reserved.
+// Copyright 2023 Apple Inc. All rights reserved.
+
+if (self.testRunner) {
+ // svg/dynamic-updates tests set enablePixelTesting=true, as we want to dump text + pixel results
+ if (self.enablePixelTesting)
+ testRunner.dumpAsTextWithPixelResults();
+ else
+ testRunner.dumpAsText();
+}
+
+var description, debug, didFailSomeTests, successfullyParsed;
+
+didFailSomeTests = false;
+
+var expectingError; // set by shouldHaveError()
+var expectedErrorMessage; // set by onerror when expectingError is true
+var unexpectedErrorMessage; // set by onerror when expectingError is not true
+
+(function() {
+
+ function createHTMLElement(tagName)
+ {
+ // FIXME: In an XML document, document.createElement() creates an element with a null namespace URI.
+ // So, we need use document.createElementNS() to explicitly create an element with the specified
+ // tag name in the HTML namespace. We can remove this function and use document.createElement()
+ // directly once we fix .
+ if (document.createElementNS)
+ return document.createElementNS("http://www.w3.org/1999/xhtml", tagName);
+ return document.createElement(tagName);
+ }
+
+ var rootElement = null;
+ function ensureRootElement()
+ {
+ if (!rootElement || !rootElement.isConnected) {
+ rootElement = document.body || document.documentElement;
+ if (document.documentElement.namespaceURI == 'http://www.w3.org/2000/svg') {
+ // FIXME: Make the test harness use SVG elements naively.
+ var foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
+ foreignObject.setAttribute('x', '0px');
+ foreignObject.setAttribute('y', '0px');
+ foreignObject.setAttribute('width', '100%');
+ foreignObject.setAttribute('height', '100%');
+ foreignObject.setAttribute('style', 'padding: 10px; background-color: rgba(255, 255, 255, 0.5)');
+ document.documentElement.appendChild(foreignObject);
+ rootElement = foreignObject;
+ }
+ }
+ return rootElement;
+ }
+
+ moveForeignObjectToTopIfNeeded = function () {
+ if (rootElement && rootElement.localName == 'foreignObject')
+ document.documentElement.appendChild(rootElement);
+ }
+
+ getOrCreate = function getOrCreate(id, tagName)
+ {
+ var element = document.getElementById(id);
+ if (element)
+ return element;
+
+ element = createHTMLElement(tagName);
+ element.id = id;
+ var refNode;
+ var parent = ensureRootElement();
+
+ if (id == "description")
+ refNode = getOrCreate("console", "div");
+ else
+ refNode = parent.firstChild;
+
+ parent.insertBefore(element, refNode);
+ return element;
+ }
+
+ description = function description(msg, quiet)
+ {
+ // For MSIE 6 compatibility
+ var span = createHTMLElement("span");
+ if (quiet)
+ span.innerHTML = '
' + msg + '
On success, you will see no "FAIL" messages, followed by "TEST COMPLETE".
';
+ else
+ span.innerHTML = '
' + msg + '
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
';
+
+ var description = getOrCreate("description", "p");
+ if (description.firstChild)
+ description.replaceChild(span, description.firstChild);
+ else
+ description.appendChild(span);
+ };
+
+ debug = function debug(msg)
+ {
+ var span = createHTMLElement("span");
+ span.innerHTML = msg + ' ';
+ getOrCreate("console", "div").appendChild(span);
+ };
+
+ var css =
+ ".pass {" +
+ "font-weight: bold;" +
+ "color: green;" +
+ "}" +
+ ".fail {" +
+ "font-weight: bold;" +
+ "color: red;" +
+ "}" +
+ "#console {" +
+ "white-space: pre-wrap;" +
+ "font-family: monospace;" +
+ "}";
+
+ function insertStyleSheet()
+ {
+ var styleElement = createHTMLElement("style");
+ styleElement.textContent = css;
+ (document.head || ensureRootElement()).appendChild(styleElement);
+ }
+
+ function handleTestFinished()
+ {
+ // FIXME: Get rid of this boolean.
+ wasPostTestScriptParsed = true;
+ if (window.jsTestIsAsync) {
+ if (window.testRunner)
+ testRunner.waitUntilDone();
+ if (window.wasFinishJSTestCalled)
+ finishJSTest();
+ } else
+ finishJSTest();
+ }
+
+ if (!isWorker()) {
+ window.addEventListener('DOMContentLoaded', function() {
+ // Call waitUntilDone() as early as possible otherwise some tests may complete before
+ // the load event has fired.
+ if (window.jsTestIsAsync && window.testRunner)
+ testRunner.waitUntilDone();
+
+ // Some tests set jsTestIsAsync in load event handler. Adding the listener late
+ // makes handleTestFinished() run after the test handles load events.
+ window.addEventListener("load", handleTestFinished, false);
+ }, false);
+ insertStyleSheet();
+ }
+
+ if (!self.isOnErrorTest) {
+ self.onerror = function(message)
+ {
+ if (self.expectingError) {
+ self.expectedErrorMessage = message;
+ self.expectingError = false;
+ return;
+ }
+ self.unexpectedErrorMessage = message;
+ if (self.jsTestIsAsync) {
+ self.testFailed("Unexpected error: " + message);
+ finishJSTest();
+ }
+ };
+ }
+})();
+
+function isWorker()
+{
+ // It's conceivable that someone would stub out 'document' in a worker so
+ // also check for childNodes, an arbitrary DOM-related object that is
+ // meaningless in a WorkerContext.
+ return (typeof document === 'undefined' || typeof document.childNodes === 'undefined') && !!self.importScripts;
+}
+
+function descriptionQuiet(msg) { description(msg, true); }
+
+function escapeHTML(text)
+{
+ return text.replace(/&/g, "&").replace(/PASS ' + escapeHTML(msg) + '');
+}
+
+function testFailed(msg)
+{
+ didFailSomeTests = true;
+ debug('FAIL ' + escapeHTML(msg) + '');
+}
+
+function areArraysEqual(a, b)
+{
+ try {
+ if (a.length !== b.length)
+ return false;
+ for (var i = 0; i < a.length; i++)
+ if (a[i] !== b[i])
+ return false;
+ } catch (ex) {
+ return false;
+ }
+ return true;
+}
+
+function isMinusZero(n)
+{
+ // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+ // -Infinity instead of Infinity
+ return n === 0 && 1/n < 0;
+}
+
+function isNewSVGTearOffType(v)
+{
+ return ['[object SVGLength]', '[object SVGLengthList]', '[object SVGPoint]', '[object SVGPointList]', '[object SVGNumber]'].indexOf(""+v) != -1;
+}
+
+function isResultCorrect(actual, expected)
+{
+ if (expected === 0)
+ return actual === expected && (1/actual) === (1/expected);
+ if (actual === expected)
+ return true;
+ // http://crbug.com/308818 : The new implementation of SVGListProperties do not necessary return the same wrapper object, so === operator would not work. We compare for their string representation instead.
+ if (isNewSVGTearOffType(expected) && typeof(expected) == typeof(actual) && actual.valueAsString == expected.valueAsString)
+ return true;
+ if (typeof(expected) == "number" && isNaN(expected))
+ return typeof(actual) == "number" && isNaN(actual);
+ if (expected && (Object.prototype.toString.call(expected) == Object.prototype.toString.call([])))
+ return areArraysEqual(actual, expected);
+ return false;
+}
+
+function stringify(v)
+{
+ if (isNewSVGTearOffType(v))
+ return v.valueAsString;
+ if (v === 0 && 1/v < 0)
+ return "-0";
+ else return "" + v;
+}
+
+function evalAndLog(_a, _quiet)
+{
+ if (typeof _a != "string")
+ debug("WARN: tryAndLog() expects a string argument");
+
+ // Log first in case things go horribly wrong or this causes a sync event.
+ if (!_quiet)
+ debug(_a);
+
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ testFailed(_a + " threw exception " + e);
+ }
+ return _av;
+}
+
+function shouldBe(_a, _b, _quiet)
+{
+ if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
+ debug("WARN: shouldBe() expects function or string arguments");
+ var _exception;
+ var _av;
+ try {
+ _av = (typeof _a == "function" ? _a() : eval(_a));
+ } catch (e) {
+ _exception = e;
+ }
+ var _bv = (typeof _b == "function" ? _b() : eval(_b));
+
+ if (_exception)
+ testFailed(_a + " should be " + stringify(_bv) + ". Threw exception " + _exception);
+ else if (isResultCorrect(_av, _bv)) {
+ if (!_quiet) {
+ testPassed(_a + " is " + (typeof _b == "function" ? _bv : _b));
+ }
+ } else if (typeof(_av) == typeof(_bv))
+ testFailed(_a + " should be " + stringify(_bv) + ". Was " + stringify(_av) + ".");
+ else
+ testFailed(_a + " should be " + stringify(_bv) + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldBeOneOfValues(_a, _values)
+{
+ if ((typeof _a != "function" && typeof _a != "string"))
+ debug("WARN: shouldBeOneOfValues() expects the first argument to be a function or a string");
+ if (!Array.isArray(_values)) {
+ testFailed("The second argument to shouldBeOneOfValues() must be an array of values");
+ return;
+ }
+
+ var _exception;
+ var _av;
+ try {
+ _av = (typeof _a == "function" ? _a() : eval(_a));
+ } catch (e) {
+ _exception = e;
+ }
+
+ var stringifiedValues = '';
+ for (var i = 0; i < _values.length; ++i) {
+ if (i) {
+ if (i + 1 == _values.length)
+ stringifiedValues += ', and ';
+ else
+ stringifiedValues += ','
+ }
+ stringifiedValues += "`" + stringify(_values[i]) + "`";
+ }
+ if (_exception)
+ testFailed(_a + " should be one of " + stringifiedValues + ". Threw exception " + _exception);
+ else {
+ var matchedValue = _values.find(function (value) { return isResultCorrect(_av, value); });
+ if (matchedValue !== undefined) {
+ testPassed(_a + " is one of " + stringifiedValues);
+ } else {
+ testFailed(_a + " should be one of " + stringifiedValues + ". Was " + stringify(_av) + ".");
+ }
+ }
+}
+
+// Execute condition every 5 milliseconds until it succeeds.
+function _waitForCondition(condition, completionHandler)
+{
+ if (condition())
+ completionHandler();
+ else
+ setTimeout(_waitForCondition, 5, condition, completionHandler);
+}
+
+function shouldBecomeEqual(_a, _b, completionHandler)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBecomeEqual() expects string arguments");
+
+ function condition() {
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+ if (exception)
+ testFailed(_a + " should become " + _bv + ". Threw exception " + exception);
+ if (isResultCorrect(_av, _bv)) {
+ testPassed(_a + " became " + _b);
+ return true;
+ }
+ return false;
+ }
+
+ if (!completionHandler)
+ return new Promise(resolve => setTimeout(_waitForCondition, 0, condition, resolve));
+
+ setTimeout(_waitForCondition, 0, condition, completionHandler);
+}
+
+function shouldBecomeEqualToString(value, reference, completionHandler)
+{
+ if (typeof value !== "string" || typeof reference !== "string")
+ debug("WARN: shouldBecomeEqualToString() expects string arguments");
+ var unevaledString = JSON.stringify(reference);
+ shouldBecomeEqual(value, unevaledString, completionHandler);
+}
+
+function shouldBeType(_a, _type) {
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ var _typev = eval(_type);
+ if (_av instanceof _typev) {
+ testPassed(_a + " is an instance of " + _type);
+ } else {
+ testFailed(_a + " is not an instance of " + _type);
+ }
+}
+
+// Variant of shouldBe()--confirms that result of eval(_to_eval) is within
+// numeric _tolerance of numeric _target.
+function shouldBeCloseTo(_to_eval, _target, _tolerance, _quiet)
+{
+ if (typeof _to_eval != "string") {
+ testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
+ return;
+ }
+ if (typeof _target != "number") {
+ testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
+ return;
+ }
+ if (typeof _tolerance != "number") {
+ testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
+ return;
+ }
+
+ var _result;
+ try {
+ _result = eval(_to_eval);
+ } catch (e) {
+ testFailed(_to_eval + " should be within " + _tolerance + " of "
+ + _target + ". Threw exception " + e);
+ return;
+ }
+
+ if (typeof(_result) != typeof(_target)) {
+ testFailed(_to_eval + " should be of type " + typeof _target
+ + " but was of type " + typeof _result);
+ } else if (Math.abs(_result - _target) <= _tolerance) {
+ if (!_quiet) {
+ testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
+ }
+ } else {
+ testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
+ + ". Was " + _result + ".");
+ }
+}
+
+function shouldNotBe(_a, _b, _quiet)
+{
+ if ((typeof _a != "function" && typeof _a != "string") || (typeof _b != "function" && typeof _b != "string"))
+ debug("WARN: shouldNotBe() expects function or string arguments");
+ var _exception;
+ var _av;
+ try {
+ _av = (typeof _a == "function" ? _a() : eval(_a));
+ } catch (e) {
+ _exception = e;
+ }
+ var _bv = (typeof _b == "function" ? _b() : eval(_b));
+
+ if (_exception)
+ testFailed(_a + " should not be " + _bv + ". Threw exception " + _exception);
+ else if (!isResultCorrect(_av, _bv)) {
+ if (!_quiet) {
+ testPassed(_a + " is not " + (typeof _b == "function" ? _bv : _b));
+ }
+ } else
+ testFailed(_a + " should not be " + _bv + ".");
+}
+
+function shouldBecomeDifferent(_a, _b, completionHandler)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBecomeDifferent() expects string arguments");
+
+ function condition() {
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+ if (exception)
+ testFailed(_a + " should became not equal to " + _bv + ". Threw exception " + exception);
+ if (!isResultCorrect(_av, _bv)) {
+ testPassed(_a + " became different from " + _b);
+ return true;
+ }
+ return false;
+ }
+
+ if (!completionHandler)
+ return new Promise(resolve => setTimeout(_waitForCondition, 0, condition, resolve));
+
+ setTimeout(_waitForCondition, 0, condition, completionHandler);
+}
+
+function shouldBeTrue(a, quiet) { shouldBe(a, "true", quiet); }
+function shouldBeTrueQuiet(a) { shouldBe(a, "true", true); }
+function shouldBeFalse(a, quiet) { shouldBe(a, "false", quiet); }
+function shouldBeNaN(a, quiet) { shouldBe(a, "NaN", quiet); }
+function shouldBeNull(a, quiet) { shouldBe(a, "null", quiet); }
+function shouldBeZero(a, quiet) { shouldBe(a, "0", quiet); }
+
+function shouldBeEqualToString(a, b)
+{
+ if (typeof a !== "string" || typeof b !== "string")
+ debug("WARN: shouldBeEqualToString() expects string arguments");
+ var unevaledString = JSON.stringify(b);
+ shouldBe(a, unevaledString);
+}
+
+function shouldBeEqualToNumber(a, b)
+{
+ if (typeof a !== "string" || typeof b !== "number")
+ debug("WARN: shouldBeEqualToNumber() expects a string and a number arguments");
+ var unevaledString = JSON.stringify(b);
+ shouldBe(a, unevaledString);
+}
+
+function shouldBeEmptyString(a) { shouldBeEqualToString(a, ""); }
+
+function shouldEvaluateTo(actual, expected) {
+ // A general-purpose comparator. 'actual' should be a string to be
+ // evaluated, as for shouldBe(). 'expected' may be any type and will be
+ // used without being eval'ed.
+ if (expected == null) {
+ // Do this before the object test, since null is of type 'object'.
+ shouldBeNull(actual);
+ } else if (typeof expected == "undefined") {
+ shouldBeUndefined(actual);
+ } else if (typeof expected == "function") {
+ // All this fuss is to avoid the string-arg warning from shouldBe().
+ try {
+ var actualValue = eval(actual);
+ } catch (e) {
+ testFailed("Evaluating " + actual + ": Threw exception " + e);
+ return;
+ }
+ shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
+ "'" + expected.toString().replace(/\n/g, "") + "'");
+ } else if (typeof expected == "object") {
+ shouldBeTrue(actual + " == '" + expected + "'");
+ } else if (typeof expected == "string") {
+ shouldBe(actual, expected);
+ } else if (typeof expected == "boolean") {
+ shouldBe("typeof " + actual, "'boolean'");
+ if (expected)
+ shouldBeTrue(actual);
+ else
+ shouldBeFalse(actual);
+ } else if (typeof expected == "number") {
+ shouldBe(actual, stringify(expected));
+ } else {
+ debug(expected + " is unknown type " + typeof expected);
+ shouldBeTrue(actual, "'" +expected.toString() + "'");
+ }
+}
+
+function shouldBeNonZero(_a)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ if (_exception)
+ testFailed(_a + " should be non-zero. Threw exception " + _exception);
+ else if (_av != 0)
+ testPassed(_a + " is non-zero.");
+ else
+ testFailed(_a + " should be non-zero. Was " + _av);
+}
+
+function shouldBeNonNull(_a)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ if (_exception)
+ testFailed(_a + " should be non-null. Threw exception " + _exception);
+ else if (_av != null)
+ testPassed(_a + " is non-null.");
+ else
+ testFailed(_a + " should be non-null. Was " + _av);
+}
+
+function shouldBeUndefined(_a)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ if (_exception)
+ testFailed(_a + " should be undefined. Threw exception " + _exception);
+ else if (typeof _av == "undefined")
+ testPassed(_a + " is undefined.");
+ else
+ testFailed(_a + " should be undefined. Was " + _av);
+}
+
+function shouldBeDefined(_a)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ if (_exception)
+ testFailed(_a + " should be defined. Threw exception " + _exception);
+ else if (_av !== undefined)
+ testPassed(_a + " is defined.");
+ else
+ testFailed(_a + " should be defined. Was " + _av);
+}
+
+function shouldBeGreaterThan(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeGreaterThan expects string arguments");
+
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (_exception)
+ testFailed(_a + " should be > " + _b + ". Threw exception " + _exception);
+ else if (typeof _av == "undefined" || _av <= _bv)
+ testFailed(_a + " should be > " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is > " + _b);
+}
+
+function shouldBeGreaterThanOrEqual(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
+
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (_exception)
+ testFailed(_a + " should be >= " + _b + ". Threw exception " + _exception);
+ else if (typeof _av == "undefined" || _av < _bv)
+ testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is >= " + _b);
+}
+
+function shouldBeLessThanOrEqual(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeLessThanOrEqual expects string arguments");
+
+ var _exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (_exception)
+ testFailed(_a + " should be <= " + _b + ". Threw exception " + _exception);
+ else if (typeof _av == "undefined" || _av > _bv)
+ testFailed(_a + " should be <= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is <= " + _b);
+}
+
+function expectTrue(v, msg) {
+ if (v) {
+ testPassed(msg);
+ } else {
+ testFailed(msg);
+ }
+}
+
+function shouldNotThrow(_a, _message) {
+ try {
+ typeof _a == "function" ? _a() : eval(_a);
+ testPassed((_message ? _message : _a) + " did not throw exception.");
+ } catch (e) {
+ testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
+ }
+}
+
+function shouldThrow(_a, _e, _message)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = typeof _a == "function" ? _a() : eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ var _ev;
+ if (_e)
+ _ev = eval(_e);
+
+ if (_exception) {
+ if (typeof _e == "undefined" || _exception == _ev)
+ testPassed((_message ? _message : _a) + " threw exception " + _exception + ".");
+ else
+ testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + _exception + ".");
+ } else if (typeof _av == "undefined")
+ testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+ else
+ testFailed((_message ? _message : _a) + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
+
+function shouldBeNow(a, delta)
+{
+ // Right now, V8 and Chromium / Blink use two different clock
+ // implementations. On Windows, the implementations are non-trivial and can
+ // be slightly out of sync. The delta is intended to compensate for that.
+ //
+ // FIXME: reconsider this when the V8 and Blink clocks get unified, see http://crbug.com/324110
+ if (delta === undefined)
+ delta = 1000;
+
+ for (var i = 0; i < 1000; ++i) {
+ var startDate = Date.now();
+ var av = eval(a);
+ var date = av.valueOf();
+ var endDate = Date.now();
+
+ // On some occasions such as NTP updates, the current time can go
+ // backwards. This should only happen rarely, so we can get away with
+ // retrying the test a few times if we detect the time going backwards.
+ if (startDate > endDate)
+ continue;
+
+ if (typeof date !== "number") {
+ testFailed(a + " is not a number or a Date. Got " + av);
+ return;
+ }
+ if (date < startDate - delta) {
+ testFailed(a + " is not the curent time. Got " + av + " which is " + (startDate - date) / 1000 + " seconds in the past.");
+ return;
+ }
+ if (date > endDate + delta) {
+ testFailed(a + " is not the current time. Got " + av + " which is " + (date - endDate) / 1000 + " seconds in the future.");
+ return;
+ }
+
+ testPassed(a + " is equivalent to Date.now().");
+ return;
+ }
+ testFailed(a + " cannot be tested against the current time. The clock is going backwards too often.");
+}
+
+function expectError()
+{
+ if (expectingError) {
+ testFailed("shouldHaveError() called twice before an error occurred!");
+ }
+ expectingError = true;
+}
+
+function shouldReject(_a, _message)
+{
+ return shouldRejectWithErrorName(_a, undefined, _message);
+}
+
+function shouldRejectWithErrorName(_a, _name, _message)
+{
+ var _exception;
+ var _av;
+ try {
+ _av = typeof _a == "function" ? _a() : eval(_a);
+ } catch (e) {
+ testFailed((_message ? _message : _a) + " should not throw exception. Threw exception " + e + ".");
+ return Promise.resolve();
+ }
+
+ return _av.then(function(result) {
+ testFailed((_message ? _message : _a) + " should reject promise. Resolved with " + result + ".");
+ }, function(error) {
+ if (_name === undefined) {
+ testPassed((_message ? _message : _a) + " rejected promise.");
+ } else if (error['name'] === _name) {
+ // FIXME: Remove the extra space and '.' (DOMException descriptions already end with periods) then rebase tests.
+ testPassed((_message ? _message : _a) + " rejected promise with " + error + ".");
+ } else
+ testFailed((_message ? _message : _a) + " should reject promise with " + _name + ". Rejected with " + error['name'] + " instead.");
+ });
+}
+
+function shouldThrowErrorName(_a, _name)
+{
+ var _exception;
+ try {
+ typeof _a == "function" ? _a() : eval(_a);
+ } catch (e) {
+ _exception = e;
+ }
+
+ if (_exception) {
+ if (_exception.name == _name)
+ testPassed(_a + " threw exception " + _exception + ".");
+ else
+ testFailed(_a + " should throw a " + _name + ". Threw a " + _exception.name + ".");
+ } else
+ testFailed(_a + " should throw a " + _name + ". Did not throw.");
+}
+
+function shouldHaveHadError(message)
+{
+ if (expectingError) {
+ testFailed("No error thrown between expectError() and shouldHaveHadError()");
+ return;
+ }
+
+ if (expectedErrorMessage) {
+ if (!message)
+ testPassed("Got expected error");
+ else if (expectedErrorMessage.indexOf(message) !== -1)
+ testPassed("Got expected error: '" + message + "'");
+ else
+ testFailed("Unexpected error '" + message + "'");
+ expectedErrorMessage = undefined;
+ return;
+ }
+
+ testFailed("expectError() not called before shouldHaveHadError()");
+}
+
+function gc() {
+ if (typeof GCController !== "undefined")
+ GCController.collect();
+ else {
+ var gcRec = function (n) {
+ if (n < 1)
+ return {};
+ var temp = {i: "ab" + i + (i / 100000)};
+ temp += "foo";
+ gcRec(n-1);
+ };
+ for (var i = 0; i < 1000; i++)
+ gcRec(10);
+ }
+}
+
+function minorGC() {
+ if (typeof GCController !== "undefined")
+ GCController.minorCollect();
+ else
+ testFailed("Minor GC is available only when you enable the --expose-gc option in V8.");
+}
+
+function isSuccessfullyParsed()
+{
+ // FIXME: Remove this and only report unexpected syntax errors.
+ successfullyParsed = !unexpectedErrorMessage;
+ shouldBeTrue("successfullyParsed");
+ if (didFailSomeTests)
+ debug("Some tests failed.");
+ debug(' TEST COMPLETE');
+}
+
+// It's possible for an async test to call finishJSTest() before js-test-post.js
+// has been parsed.
+function finishJSTest()
+{
+ wasFinishJSTestCalled = true;
+ if (!self.wasPostTestScriptParsed)
+ return;
+ isSuccessfullyParsed();
+ moveForeignObjectToTopIfNeeded();
+ if (self.jsTestIsAsync && self.testRunner)
+ testRunner.notifyDone();
+}
+
+function areObjectsEqual(a, b) {
+ for (var property in a) {
+ if (!b.hasOwnProperty(property))
+ return false;
+
+ switch (typeof (a[property])) {
+ case 'function':
+ if (typeof b[property] == 'undefined' || a[property].toString() != b[property].toString())
+ return false;
+ break;
+ case 'object':
+ if (!areObjectsEqual(a, b))
+ return false;
+ break;
+ default:
+ if (a[property] != b[property])
+ return false;
+ }
+ }
+
+ for (var property in b) {
+ if (!a.hasOwnProperty(property))
+ return false;
+ }
+
+ return true;
+};
+
+function startWorker(testScriptURL)
+{
+ self.jsTestIsAsync = true;
+ debug('Starting worker: ' + testScriptURL);
+ var worker = new Worker(testScriptURL);
+ worker.onmessage = function(event)
+ {
+ var workerPrefix = "[Worker] ";
+ if (event.data.length < 5 || event.data.charAt(4) != ':') {
+ debug(workerPrefix + event.data);
+ return;
+ }
+ var code = event.data.substring(0, 4);
+ var payload = workerPrefix + event.data.substring(5);
+ if (code == "PASS")
+ testPassed(payload);
+ else if (code == "FAIL")
+ testFailed(payload);
+ else if (code == "DESC")
+ description(payload);
+ else if (code == "DONE")
+ finishJSTest();
+ else
+ debug(workerPrefix + event.data);
+ };
+
+ worker.onerror = function(event)
+ {
+ debug('Got error from worker: ' + event.message);
+ finishJSTest();
+ };
+
+ return worker;
+}
+
+if (isWorker()) {
+ var workerPort = self;
+ description = function(msg, quiet) {
+ workerPort.postMessage('DESC:' + msg);
+ };
+ testFailed = function(msg) {
+ workerPort.postMessage('FAIL:' + msg);
+ };
+ testPassed = function(msg) {
+ workerPort.postMessage('PASS:' + msg);
+ };
+ finishJSTest = function() {
+ workerPort.postMessage('DONE:');
+ };
+ debug = function(msg) {
+ workerPort.postMessage(msg);
+ };
+}
+
+function downgradeReferrerCallback(policy, host) {
+ let scriptElement = document.createElement("script");
+ scriptElement.src = "http://".concat(host, ":8000/referrer-policy/resources/script.py");
+ scriptElement.referrerPolicy = policy;
+ document.body.appendChild(scriptElement);
+}
diff --git a/MotionMark/unit-tests/test-animator.html b/MotionMark/unit-tests/test-animator.html
new file mode 100644
index 0000000..59091db
--- /dev/null
+++ b/MotionMark/unit-tests/test-animator.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
diff --git a/MotionMark/unit-tests/test-fixed-controller.html b/MotionMark/unit-tests/test-fixed-controller.html
new file mode 100644
index 0000000..aa5dfe2
--- /dev/null
+++ b/MotionMark/unit-tests/test-fixed-controller.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
diff --git a/MotionMark/unit-tests/test-ramp-controller.html b/MotionMark/unit-tests/test-ramp-controller.html
new file mode 100644
index 0000000..6ae7933
--- /dev/null
+++ b/MotionMark/unit-tests/test-ramp-controller.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/MotionMark/unit-tests/test-regression.html b/MotionMark/unit-tests/test-regression.html
new file mode 100644
index 0000000..0e1bef4
--- /dev/null
+++ b/MotionMark/unit-tests/test-regression.html
@@ -0,0 +1,272 @@
+
+
+
+
+
+
+
diff --git a/MotionMark/unit-tests/test-spiral-iterator.html b/MotionMark/unit-tests/test-spiral-iterator.html
new file mode 100644
index 0000000..c9bb47f
--- /dev/null
+++ b/MotionMark/unit-tests/test-spiral-iterator.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+