Add a convenience function for creating a class.
authorjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 7 Feb 2016 00:27:12 +0000 (00:27 +0000)
committerjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 7 Feb 2016 00:27:12 +0000 (00:27 +0000)
The pattern for creating a class is common enough to add as a Utilities
helper function. It also makes it easy to collapse class definitions when
editing.

* Animometer/resources/debug-runner/animometer.js: Move ProgressBar definition,
since it is only used here.
* Animometer/resources/runner/animometer.js: Move ResultsDashboard and
ResultsTable definition, since it is only used here.
* Animometer/resources/extensions.js: Move Utilities definition to the top. Convert
Point, Insets, SimplePromise.
(ProgressBar): Moved to animometer.js.
(ResultsDashboard): Moved to animometer.js.
(ResultsTable): Moved to animometer.js.
* Animometer/resources/runner/benchmark-runner.js: Convert BenchmarkRunnerState,
BenchmarkRunner.
* Animometer/tests/resources/main.js: Convert Rotater, Stage, Animator, Benchmark.
* Animometer/tests/resources/sampler.js: Convert Experiment, Sampler.

Convert test primitives.
* Animometer/tests/master/resources/canvas-tests.js: Convert CanvasLineSegment,
CanvasArc, CanvasLinePoint.
* Animometer/tests/simple/resources/simple-canvas-paths.js: Convert CanvasLineSegment,
CanvasLinePoint, CanvasQuadraticSegment, CanvasQuadraticPoint, CanvasBezierSegment,
CanvasBezierPoint, CanvasArcToSegment, CanvasArcToSegmentFill, CanvasArcSegment,
CanvasArcSegmentFill, CanvasRect, CanvasRectFill.
* Animometer/tests/simple/resources/tiled-canvas-image.js: Convert CanvasImageTile.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@196228 268f45cc-cd09-0410-ab3c-d52691b4dbfc

PerformanceTests/Animometer/resources/debug-runner/animometer.js
PerformanceTests/Animometer/resources/extensions.js
PerformanceTests/Animometer/resources/runner/animometer.js
PerformanceTests/Animometer/resources/runner/benchmark-runner.js
PerformanceTests/Animometer/tests/master/resources/canvas-tests.js
PerformanceTests/Animometer/tests/resources/main.js
PerformanceTests/Animometer/tests/resources/sampler.js
PerformanceTests/Animometer/tests/simple/resources/simple-canvas-paths.js
PerformanceTests/Animometer/tests/simple/resources/tiled-canvas-image.js
PerformanceTests/ChangeLog

index 0e80cd3..564f993 100644 (file)
@@ -1,3 +1,24 @@
+ProgressBar = Utilities.createClass(
+    function(element, ranges)
+    {
+        this._element = element;
+        this._ranges = ranges;
+        this._currentRange = 0;
+        this._updateElement();
+    }, {
+
+    _updateElement: function()
+    {
+        this._element.style.width = (this._currentRange * (100 / this._ranges)) + "%";
+    },
+
+    incrementRange: function()
+    {
+        ++this._currentRange;
+        this._updateElement();
+    }
+});
+
 Utilities.extendObject(window.benchmarkRunnerClient, {
     testsCount: null,
     progressBar: null,
index 6d9ebe5..cc3ec9d 100644 (file)
@@ -1,3 +1,62 @@
+Utilities =
+{
+    _parse: function(str, sep)
+    {
+        var output = {};
+        str.split(sep).forEach(function(part) {
+            var item = part.split("=");
+            var value = decodeURIComponent(item[1]);
+            if (value[0] == "'" )
+                output[item[0]] = value.substr(1, value.length - 2);
+            else
+                output[item[0]] = value;
+          });
+        return output;
+    },
+
+    parseParameters: function()
+    {
+        return this._parse(window.location.search.substr(1), "&");
+    },
+
+    parseArguments: function(str)
+    {
+        return this._parse(str, " ");
+    },
+
+    extendObject: function(obj1, obj2)
+    {
+        for (var attrname in obj2)
+            obj1[attrname] = obj2[attrname];
+        return obj1;
+    },
+
+    copyObject: function(obj)
+    {
+        return this.extendObject({}, obj);
+    },
+
+    mergeObjects: function(obj1, obj2)
+    {
+        return this.extendObject(this.copyObject(obj1), obj2);
+    },
+
+    createClass: function(classConstructor, classMethods)
+    {
+        classConstructor.prototype = classMethods;
+        return classConstructor;
+    },
+
+    createSubclass: function(superclass, classConstructor, classMethods)
+    {
+        classConstructor.prototype = Object.create(superclass.prototype);
+        classConstructor.prototype.constructor = classConstructor;
+        if (classMethods)
+            Utilities.extendObject(classConstructor.prototype, classMethods);
+        return classConstructor;
+    }
+};
+
 Array.prototype.swap = function(i, j)
 {
     var t = this[i];
@@ -57,35 +116,13 @@ Array.prototype.shuffle = function()
     return this;
 }
 
-function Point(x, y)
-{
-    this.x = x;
-    this.y = y;
-}
-
-Point.zero = function()
-{
-    return new Point(0, 0);
-}
-
-Point.pointOnCircle = function(angle, radius)
-{
-    return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
-}
-
-Point.pointOnEllipse = function(angle, radiuses)
-{
-    return new Point(radiuses.x * Math.cos(angle), radiuses.y * Math.sin(angle));
-}
-
-Point.elementClientSize = function(element)
-{
-    var rect = element.getBoundingClientRect();
-    return new Point(rect.width, rect.height);
-}
+Point = Utilities.createClass(
+    function(x, y)
+    {
+        this.x = x;
+        this.y = y;
+    }, {
 
-Point.prototype =
-{
     // Used when the point object is used as a size object.
     get width()
     {
@@ -145,28 +182,40 @@ Point.prototype =
         this.y /= l;
         return this;
     }
-};
+});
 
-function Insets(top, right, bottom, left)
-{
-    this.top = top;
-    this.right = right;
-    this.bottom = bottom;
-    this.left = left;
-}
+Utilities.extendObject(Point, {
+    zero: function()
+    {
+        return new Point(0, 0);
+    },
 
-Insets.elementPadding = function(element)
-{
-    var styles = window.getComputedStyle(element);
-    return new Insets(
-        parseFloat(styles.paddingTop),
-        parseFloat(styles.paddingRight),
-        parseFloat(styles.paddingBottom),
-        parseFloat(styles.paddingTop));
-}
+    pointOnCircle: function(angle, radius)
+    {
+        return new Point(radius * Math.cos(angle), radius * Math.sin(angle));
+    },
+
+    pointOnEllipse: function(angle, radiuses)
+    {
+        return new Point(radiuses.x * Math.cos(angle), radiuses.y * Math.sin(angle));
+    },
+
+    elementClientSize: function(element)
+    {
+        var rect = element.getBoundingClientRect();
+        return new Point(rect.width, rect.height);
+    }
+});
+
+Insets = Utilities.createClass(
+    function(top, right, bottom, left)
+    {
+        this.top = top;
+        this.right = right;
+        this.bottom = bottom;
+        this.left = left;
+    }, {
 
-Insets.prototype =
-{
     get width()
     {
         return this.left + this.right;
@@ -181,45 +230,57 @@ Insets.prototype =
     {
         return new Point(this.width, this.height);
     }
-}
+});
 
-function SimplePromise()
+Insets.elementPadding = function(element)
 {
-    this._chainedPromise = null;
-    this._callback = null;
+    var styles = window.getComputedStyle(element);
+    return new Insets(
+        parseFloat(styles.paddingTop),
+        parseFloat(styles.paddingRight),
+        parseFloat(styles.paddingBottom),
+        parseFloat(styles.paddingTop));
 }
 
-SimplePromise.prototype.then = function (callback)
-{
-    if (this._callback)
-        throw "SimplePromise doesn't support multiple calls to then";
+SimplePromise = Utilities.createClass(
+    function()
+    {
+        this._chainedPromise = null;
+        this._callback = null;
+    }, {
 
-    this._callback = callback;
-    this._chainedPromise = new SimplePromise;
+    then: function (callback)
+    {
+        if (this._callback)
+            throw "SimplePromise doesn't support multiple calls to then";
 
-    if (this._resolved)
-        this.resolve(this._resolvedValue);
+        this._callback = callback;
+        this._chainedPromise = new SimplePromise;
 
-    return this._chainedPromise;
-}
+        if (this._resolved)
+            this.resolve(this._resolvedValue);
 
-SimplePromise.prototype.resolve = function (value)
-{
-    if (!this._callback) {
-        this._resolved = true;
-        this._resolvedValue = value;
-        return;
-    }
+        return this._chainedPromise;
+    },
 
-    var result = this._callback(value);
-    if (result instanceof SimplePromise) {
-        var chainedPromise = this._chainedPromise;
-        result.then(function (result) { chainedPromise.resolve(result); });
-    } else
-        this._chainedPromise.resolve(result);
-}
+    resolve: function (value)
+    {
+        if (!this._callback) {
+            this._resolved = true;
+            this._resolvedValue = value;
+            return;
+        }
 
-var Statistics =
+        var result = this._callback(value);
+        if (result instanceof SimplePromise) {
+            var chainedPromise = this._chainedPromise;
+            result.then(function (result) { chainedPromise.resolve(result); });
+        } else
+            this._chainedPromise.resolve(result);
+    }
+});
+
+Statistics =
 {
     sampleMean: function(numberOfSamples, sum)
     {
@@ -246,7 +307,7 @@ var Statistics =
     }
 };
 
-window.DocumentExtension =
+DocumentExtension =
 {
     createElement: function(name, attrs, parentElement)
     {
@@ -275,315 +336,4 @@ window.DocumentExtension =
         parentElement.appendChild(element);
         return element;
     }
-}
-
-function ProgressBar(element, ranges)
-{
-    this._element = element;
-    this._ranges = ranges;
-    this._currentRange = 0;
-    this._updateElement();
-}
-
-ProgressBar.prototype =
-{
-    _updateElement: function()
-    {
-        this._element.style.width = (this._currentRange * (100 / this._ranges)) + "%";
-    },
-
-    incrementRange: function()
-    {
-        ++this._currentRange;
-        this._updateElement();
-    }
-}
-
-function ResultsDashboard()
-{
-    this._iterationsSamplers = [];
-    this._processedData = undefined;
-}
-
-ResultsDashboard.prototype =
-{
-    push: function(suitesSamplers)
-    {
-        this._iterationsSamplers.push(suitesSamplers);
-    },
-
-    _processData: function()
-    {
-        var iterationsResults = [];
-        var iterationsScores = [];
-
-        this._iterationsSamplers.forEach(function(iterationSamplers, index) {
-            var suitesResults = {};
-            var suitesScores = [];
-
-            for (var suiteName in iterationSamplers) {
-                var suite = suiteFromName(suiteName);
-                var suiteSamplerData = iterationSamplers[suiteName];
-
-                var testsResults = {};
-                var testsScores = [];
-
-                for (var testName in suiteSamplerData) {
-                    testsResults[testName] = suiteSamplerData[testName];
-                    testsScores.push(testsResults[testName][Strings.json.score]);
-                }
-
-                suitesResults[suiteName] =  {};
-                suitesResults[suiteName][Strings.json.score] = Statistics.geometricMean(testsScores);
-                suitesResults[suiteName][Strings.json.results.tests] = testsResults;
-                suitesScores.push(suitesResults[suiteName][Strings.json.score]);
-            }
-
-            iterationsResults[index] = {};
-            iterationsResults[index][Strings.json.score] = Statistics.geometricMean(suitesScores);
-            iterationsResults[index][Strings.json.results.suites] = suitesResults;
-            iterationsScores.push(iterationsResults[index][Strings.json.score]);
-        });
-
-        this._processedData = {};
-        this._processedData[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a * b; }));
-        this._processedData[Strings.json.results.iterations] = iterationsResults;
-    },
-
-    get data()
-    {
-        if (this._processedData)
-            return this._processedData;
-        this._processData();
-        return this._processedData;
-    },
-
-    get score()
-    {
-        return this.data[Strings.json.score];
-    }
-}
-
-function ResultsTable(element, headers)
-{
-    this.element = element;
-    this._headers = headers;
-
-    this._flattenedHeaders = [];
-    this._headers.forEach(function(header) {
-        if (header.children)
-            this._flattenedHeaders = this._flattenedHeaders.concat(header.children);
-        else
-            this._flattenedHeaders.push(header);
-    }, this);
-
-    this.clear();
-}
-
-ResultsTable.prototype =
-{
-    clear: function()
-    {
-        this.element.innerHTML = "";
-    },
-
-    _addHeader: function()
-    {
-        var thead = DocumentExtension.createElement("thead", {}, this.element);
-        var row = DocumentExtension.createElement("tr", {}, thead);
-
-        this._headers.forEach(function (header) {
-            var th = DocumentExtension.createElement("th", {}, row);
-            if (header.title != Strings.text.results.graph)
-                th.textContent = header.title;
-            if (header.children)
-                th.colSpan = header.children.length;
-        });
-    },
-
-    _addGraphButton: function(td, testName, testResults)
-    {
-        var data = testResults[Strings.json.samples];
-        if (!data)
-            return;
-
-        var button = DocumentExtension.createElement("button", { class: "small-button" }, td);
-
-        button.addEventListener("click", function() {
-            var score = testResults[Strings.json.score].toFixed(2);
-            var complexity = testResults[Strings.json.experiments.complexity];
-            var mean = [
-                "mean: ",
-                complexity[Strings.json.measurements.average].toFixed(2),
-                " ± ",
-                complexity[Strings.json.measurements.stdev].toFixed(2),
-                " (",
-                complexity[Strings.json.measurements.percent].toFixed(2),
-                "%), worst 5%: ",
-                complexity[Strings.json.measurements.concern].toFixed(2)].join("");
-
-            var graphData = {
-                axes: [Strings.text.experiments.complexity, Strings.text.experiments.frameRate],
-                mean: [
-                    testResults[Strings.json.experiments.complexity][Strings.json.measurements.average],
-                    testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
-                ],
-                samples: data,
-                samplingTimeOffset: testResults[Strings.json.samplingTimeOffset]
-            }
-            if (testResults[Strings.json.targetFPS])
-                graphData.targetFPS = testResults[Strings.json.targetFPS];
-            benchmarkController.showTestGraph(testName, score, mean, graphData);
-        });
-
-        button.textContent = Strings.text.results.graph + "...";
-    },
-
-    _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
-    {
-        const percentThreshold = 10;
-        const averageThreshold = 2;
-
-        if (measurement == Strings.json.measurements.percent)
-            return data[Strings.json.measurements.percent] >= percentThreshold;
-
-        if (jsonExperiment == Strings.json.experiments.frameRate && measurement == Strings.json.measurements.average)
-            return Math.abs(data[Strings.json.measurements.average] - options["frame-rate"]) >= averageThreshold;
-
-        return false;
-    },
-
-    _addEmptyRow: function()
-    {
-        var row = DocumentExtension.createElement("tr", {}, this.element);
-        this._flattenedHeaders.forEach(function (header) {
-            return DocumentExtension.createElement("td", { class: "suites-separator" }, row);
-        });
-    },
-
-    _addTest: function(testName, testResults, options)
-    {
-        var row = DocumentExtension.createElement("tr", {}, this.element);
-
-        var isNoisy = false;
-        [Strings.json.experiments.complexity, Strings.json.experiments.frameRate].forEach(function (experiment) {
-            var data = testResults[experiment];
-            for (var measurement in data) {
-                if (this._isNoisyMeasurement(experiment, data, measurement, options))
-                    isNoisy = true;
-            }
-        }, this);
-
-        this._flattenedHeaders.forEach(function (header) {
-            var className = "";
-            if (header.className) {
-                if (typeof header.className == "function")
-                    className = header.className(testResults, options);
-                else
-                    className = header.className;
-            }
-
-            if (header.title == Strings.text.testName) {
-                var titleClassName = className;
-                if (isNoisy)
-                    titleClassName += " noisy-results";
-                var td = DocumentExtension.createElement("td", { class: titleClassName }, row);
-                td.textContent = testName;
-                return;
-            }
-
-            var td = DocumentExtension.createElement("td", { class: className }, row);
-            if (header.title == Strings.text.results.graph) {
-                this._addGraphButton(td, testName, testResults);
-            } else if (!("text" in header)) {
-                td.textContent = testResults[header.title];
-            } else if (typeof header.text == "string") {
-                var data = testResults[header.text];
-                if (typeof data == "number")
-                    data = data.toFixed(2);
-                td.textContent = data;
-            } else {
-                td.textContent = header.text(testResults, testName);
-            }
-        }, this);
-    },
-
-    _addSuite: function(suiteName, suiteResults, options)
-    {
-        for (var testName in suiteResults[Strings.json.results.tests]) {
-            var testResults = suiteResults[Strings.json.results.tests][testName];
-            this._addTest(testName, testResults, options);
-        }
-    },
-
-    _addIteration: function(iterationResult, options)
-    {
-        for (var suiteName in iterationResult[Strings.json.results.suites]) {
-            this._addEmptyRow();
-            this._addSuite(suiteName, iterationResult[Strings.json.results.suites][suiteName], options);
-        }
-    },
-
-    showIterations: function(iterationsResults, options)
-    {
-        this.clear();
-        this._addHeader();
-
-        iterationsResults.forEach(function(iterationResult) {
-            this._addIteration(iterationResult, options);
-        }, this);
-    }
-}
-
-window.Utilities =
-{
-    _parse: function(str, sep)
-    {
-        var output = {};
-        str.split(sep).forEach(function(part) {
-            var item = part.split("=");
-            var value = decodeURIComponent(item[1]);
-            if (value[0] == "'" )
-                output[item[0]] = value.substr(1, value.length - 2);
-            else
-                output[item[0]] = value;
-          });
-        return output;
-    },
-
-    parseParameters: function()
-    {
-        return this._parse(window.location.search.substr(1), "&");
-    },
-
-    parseArguments: function(str)
-    {
-        return this._parse(str, " ");
-    },
-
-    extendObject: function(obj1, obj2)
-    {
-        for (var attrname in obj2)
-            obj1[attrname] = obj2[attrname];
-        return obj1;
-    },
-
-    copyObject: function(obj)
-    {
-        return this.extendObject({}, obj);
-    },
-
-    mergeObjects: function(obj1, obj2)
-    {
-        return this.extendObject(this.copyObject(obj1), obj2);
-    },
-
-    createSubclass: function(superclass, classConstructor, extend)
-    {
-        classConstructor.prototype = Object.create(superclass.prototype);
-        classConstructor.prototype.constructor = classConstructor;
-        if (extend)
-            Utilities.extendObject(classConstructor.prototype, extend);
-        return classConstructor;
-    }
-}
+};
index e9d602d..2c2555f 100644 (file)
@@ -1,3 +1,237 @@
+ResultsDashboard = Utilities.createClass(
+    function()
+    {
+        this._iterationsSamplers = [];
+        this._processedData = undefined;
+    }, {
+
+    push: function(suitesSamplers)
+    {
+        this._iterationsSamplers.push(suitesSamplers);
+    },
+
+    _processData: function()
+    {
+        var iterationsResults = [];
+        var iterationsScores = [];
+
+        this._iterationsSamplers.forEach(function(iterationSamplers, index) {
+            var suitesResults = {};
+            var suitesScores = [];
+
+            for (var suiteName in iterationSamplers) {
+                var suite = suiteFromName(suiteName);
+                var suiteSamplerData = iterationSamplers[suiteName];
+
+                var testsResults = {};
+                var testsScores = [];
+
+                for (var testName in suiteSamplerData) {
+                    testsResults[testName] = suiteSamplerData[testName];
+                    testsScores.push(testsResults[testName][Strings.json.score]);
+                }
+
+                suitesResults[suiteName] =  {};
+                suitesResults[suiteName][Strings.json.score] = Statistics.geometricMean(testsScores);
+                suitesResults[suiteName][Strings.json.results.tests] = testsResults;
+                suitesScores.push(suitesResults[suiteName][Strings.json.score]);
+            }
+
+            iterationsResults[index] = {};
+            iterationsResults[index][Strings.json.score] = Statistics.geometricMean(suitesScores);
+            iterationsResults[index][Strings.json.results.suites] = suitesResults;
+            iterationsScores.push(iterationsResults[index][Strings.json.score]);
+        });
+
+        this._processedData = {};
+        this._processedData[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a * b; }));
+        this._processedData[Strings.json.results.iterations] = iterationsResults;
+    },
+
+    get data()
+    {
+        if (this._processedData)
+            return this._processedData;
+        this._processData();
+        return this._processedData;
+    },
+
+    get score()
+    {
+        return this.data[Strings.json.score];
+    }
+});
+
+ResultsTable = Utilities.createClass(
+    function(element, headers)
+    {
+        this.element = element;
+        this._headers = headers;
+
+        this._flattenedHeaders = [];
+        this._headers.forEach(function(header) {
+            if (header.children)
+                this._flattenedHeaders = this._flattenedHeaders.concat(header.children);
+            else
+                this._flattenedHeaders.push(header);
+        }, this);
+
+        this.clear();
+    }, {
+
+    clear: function()
+    {
+        this.element.innerHTML = "";
+    },
+
+    _addHeader: function()
+    {
+        var thead = DocumentExtension.createElement("thead", {}, this.element);
+        var row = DocumentExtension.createElement("tr", {}, thead);
+
+        this._headers.forEach(function (header) {
+            var th = DocumentExtension.createElement("th", {}, row);
+            if (header.title != Strings.text.results.graph)
+                th.textContent = header.title;
+            if (header.children)
+                th.colSpan = header.children.length;
+        });
+    },
+
+    _addGraphButton: function(td, testName, testResults)
+    {
+        var data = testResults[Strings.json.samples];
+        if (!data)
+            return;
+
+        var button = DocumentExtension.createElement("button", { class: "small-button" }, td);
+
+        button.addEventListener("click", function() {
+            var score = testResults[Strings.json.score].toFixed(2);
+            var complexity = testResults[Strings.json.experiments.complexity];
+            var mean = [
+                "mean: ",
+                complexity[Strings.json.measurements.average].toFixed(2),
+                " ± ",
+                complexity[Strings.json.measurements.stdev].toFixed(2),
+                " (",
+                complexity[Strings.json.measurements.percent].toFixed(2),
+                "%), worst 5%: ",
+                complexity[Strings.json.measurements.concern].toFixed(2)].join("");
+
+            var graphData = {
+                axes: [Strings.text.experiments.complexity, Strings.text.experiments.frameRate],
+                mean: [
+                    testResults[Strings.json.experiments.complexity][Strings.json.measurements.average],
+                    testResults[Strings.json.experiments.frameRate][Strings.json.measurements.average]
+                ],
+                samples: data,
+                samplingTimeOffset: testResults[Strings.json.samplingTimeOffset]
+            }
+            if (testResults[Strings.json.targetFPS])
+                graphData.targetFPS = testResults[Strings.json.targetFPS];
+            benchmarkController.showTestGraph(testName, score, mean, graphData);
+        });
+
+        button.textContent = Strings.text.results.graph + "...";
+    },
+
+    _isNoisyMeasurement: function(jsonExperiment, data, measurement, options)
+    {
+        const percentThreshold = 10;
+        const averageThreshold = 2;
+
+        if (measurement == Strings.json.measurements.percent)
+            return data[Strings.json.measurements.percent] >= percentThreshold;
+
+        if (jsonExperiment == Strings.json.experiments.frameRate && measurement == Strings.json.measurements.average)
+            return Math.abs(data[Strings.json.measurements.average] - options["frame-rate"]) >= averageThreshold;
+
+        return false;
+    },
+
+    _addEmptyRow: function()
+    {
+        var row = DocumentExtension.createElement("tr", {}, this.element);
+        this._flattenedHeaders.forEach(function (header) {
+            return DocumentExtension.createElement("td", { class: "suites-separator" }, row);
+        });
+    },
+
+    _addTest: function(testName, testResults, options)
+    {
+        var row = DocumentExtension.createElement("tr", {}, this.element);
+
+        var isNoisy = false;
+        [Strings.json.experiments.complexity, Strings.json.experiments.frameRate].forEach(function (experiment) {
+            var data = testResults[experiment];
+            for (var measurement in data) {
+                if (this._isNoisyMeasurement(experiment, data, measurement, options))
+                    isNoisy = true;
+            }
+        }, this);
+
+        this._flattenedHeaders.forEach(function (header) {
+            var className = "";
+            if (header.className) {
+                if (typeof header.className == "function")
+                    className = header.className(testResults, options);
+                else
+                    className = header.className;
+            }
+
+            if (header.title == Strings.text.testName) {
+                var titleClassName = className;
+                if (isNoisy)
+                    titleClassName += " noisy-results";
+                var td = DocumentExtension.createElement("td", { class: titleClassName }, row);
+                td.textContent = testName;
+                return;
+            }
+
+            var td = DocumentExtension.createElement("td", { class: className }, row);
+            if (header.title == Strings.text.results.graph) {
+                this._addGraphButton(td, testName, testResults);
+            } else if (!("text" in header)) {
+                td.textContent = testResults[header.title];
+            } else if (typeof header.text == "string") {
+                var data = testResults[header.text];
+                if (typeof data == "number")
+                    data = data.toFixed(2);
+                td.textContent = data;
+            } else {
+                td.textContent = header.text(testResults, testName);
+            }
+        }, this);
+    },
+
+    _addSuite: function(suiteName, suiteResults, options)
+    {
+        for (var testName in suiteResults[Strings.json.results.tests]) {
+            var testResults = suiteResults[Strings.json.results.tests][testName];
+            this._addTest(testName, testResults, options);
+        }
+    },
+
+    _addIteration: function(iterationResult, options)
+    {
+        for (var suiteName in iterationResult[Strings.json.results.suites]) {
+            this._addEmptyRow();
+            this._addSuite(suiteName, iterationResult[Strings.json.results.suites][suiteName], options);
+        }
+    },
+
+    showIterations: function(iterationsResults, options)
+    {
+        this.clear();
+        this._addHeader();
+
+        iterationsResults.forEach(function(iterationResult) {
+            this._addIteration(iterationResult, options);
+        }, this);
+    }
+});
+
 window.benchmarkRunnerClient = {
     iterationCount: 1,
     options: null,
index 8fd16f5..f62860e 100644 (file)
@@ -1,12 +1,12 @@
-function BenchmarkRunnerState(suites)
-{
-    this._suites = suites;
-    this._suiteIndex = -1;
-    this._testIndex = 0;
-    this.next();
-}
-
-BenchmarkRunnerState.prototype = {
+BenchmarkRunnerState = Utilities.createClass(
+    function(suites)
+    {
+        this._suites = suites;
+        this._suiteIndex = -1;
+        this._testIndex = 0;
+        this.next();
+    }, {
+
     currentSuite: function()
     {
         return this._suites[this._suiteIndex];
@@ -49,16 +49,16 @@ BenchmarkRunnerState.prototype = {
         frame.src = "tests/" + test.url;
         return promise;
     }
-};
+});
 
-function BenchmarkRunner(suites, frameContainer, client)
-{
-    this._suites = suites;
-    this._client = client;
-    this._frameContainer = frameContainer;
-}
+BenchmarkRunner = Utilities.createClass(
+    function(suites, frameContainer, client)
+    {
+        this._suites = suites;
+        this._client = client;
+        this._frameContainer = frameContainer;
+    }, {
 
-BenchmarkRunner.prototype = {
     _appendFrame: function()
     {
         var frame = document.createElement("iframe");
@@ -173,4 +173,4 @@ BenchmarkRunner.prototype = {
         if (this._runNextIteration)
             this._runNextIteration();
     }
-};
+});
index b02939d..a70c75b 100644 (file)
 
 // === PAINT OBJECTS ===
 
-function CanvasLineSegment(stage)
-{
-    var circle = Stage.randomInt(0, 2);
-    this._color = ["#e01040", "#10c030", "#e05010"][circle];
-    this._lineWidth = Math.pow(Math.random(), 12) * 20 + 3;
-    this._omega = Math.random() * 3 + 0.2;
-    var theta = Stage.randomAngle();
-    this._cosTheta = Math.cos(theta);
-    this._sinTheta = Math.sin(theta);
-    this._startX = stage.circleRadius * this._cosTheta + (0.5 + circle) / 3 * stage.size.x;
-    this._startY = stage.circleRadius * this._sinTheta + stage.size.y / 2;
-    this._length = Math.pow(Math.random(), 8) * 40 + 20;
-    this._segmentDirection = Math.random() > 0.5 ? -1 : 1;
-}
-
-CanvasLineSegment.prototype.draw = function(context)
-{
-    context.strokeStyle = this._color;
-    context.lineWidth = this._lineWidth;
-
-    this._length += Math.sin(Date.now()/100*this._omega);
-
-    context.beginPath();
-    context.moveTo(this._startX, this._startY);
-    context.lineTo(this._startX + this._segmentDirection * this._length * this._cosTheta,
-                   this._startY + this._segmentDirection * this._length * this._sinTheta);
-    context.stroke();
-};
-
-function CanvasArc(stage)
-{
-    var maxX = 6, maxY = 3;
-    var distanceX = stage.size.x / maxX;
-    var distanceY = stage.size.y / (maxY + 1);
-    var randY = Stage.randomInt(0, maxY);
-    var randX = Stage.randomInt(0, maxX - 1 * (randY % 2));
-
-    this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5));
-
-    this._radius = 20 + Math.pow(Math.random(), 5) * (Math.min(distanceX, distanceY) / 1.8);
-    this._startAngle = Stage.randomAngle();
-    this._endAngle = Stage.randomAngle();
-    this._omega = (Math.random() - 0.5) * 0.3;
-    this._counterclockwise = Stage.randomBool();
-    var colors = ["#101010", "#808080", "#c0c0c0"];
-    colors.push(["#e01040", "#10c030", "#e05010"][(randX + Math.ceil(randY / 2)) % 3]);
-    this._color = colors[Math.floor(Math.random() * colors.length)];
-    this._lineWidth = 1 + Math.pow(Math.random(), 5) * 30;
-    this._doStroke = Stage.randomInt(0, 3) != 0;
-};
-
-CanvasArc.prototype.draw = function(context)
-{
-    this._startAngle += this._omega;
-    this._endAngle += this._omega / 2;
-
-    if (this._doStroke) {
+CanvasLineSegment = Utilities.createClass(
+    function(stage)
+    {
+        var circle = Stage.randomInt(0, 2);
+        this._color = ["#e01040", "#10c030", "#e05010"][circle];
+        this._lineWidth = Math.pow(Math.random(), 12) * 20 + 3;
+        this._omega = Math.random() * 3 + 0.2;
+        var theta = Stage.randomAngle();
+        this._cosTheta = Math.cos(theta);
+        this._sinTheta = Math.sin(theta);
+        this._startX = stage.circleRadius * this._cosTheta + (0.5 + circle) / 3 * stage.size.x;
+        this._startY = stage.circleRadius * this._sinTheta + stage.size.y / 2;
+        this._length = Math.pow(Math.random(), 8) * 40 + 20;
+        this._segmentDirection = Math.random() > 0.5 ? -1 : 1;
+    }, {
+
+    draw: function(context)
+    {
         context.strokeStyle = this._color;
         context.lineWidth = this._lineWidth;
+
+        this._length += Math.sin(Date.now()/100*this._omega);
+
         context.beginPath();
-        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+        context.moveTo(this._startX, this._startY);
+        context.lineTo(this._startX + this._segmentDirection * this._length * this._cosTheta,
+                       this._startY + this._segmentDirection * this._length * this._sinTheta);
         context.stroke();
-    } else {
-        context.fillStyle = this._color;
-        context.beginPath();
-        context.lineTo(this._point.x, this._point.y);
-        context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
-        context.lineTo(this._point.x, this._point.y);
-        context.fill();
     }
-};
+});
+
+CanvasArc = Utilities.createClass(
+    function(stage)
+    {
+        var maxX = 6, maxY = 3;
+        var distanceX = stage.size.x / maxX;
+        var distanceY = stage.size.y / (maxY + 1);
+        var randY = Stage.randomInt(0, maxY);
+        var randX = Stage.randomInt(0, maxX - 1 * (randY % 2));
+
+        this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5));
+
+        this._radius = 20 + Math.pow(Math.random(), 5) * (Math.min(distanceX, distanceY) / 1.8);
+        this._startAngle = Stage.randomAngle();
+        this._endAngle = Stage.randomAngle();
+        this._omega = (Math.random() - 0.5) * 0.3;
+        this._counterclockwise = Stage.randomBool();
+        var colors = ["#101010", "#808080", "#c0c0c0"];
+        colors.push(["#e01040", "#10c030", "#e05010"][(randX + Math.ceil(randY / 2)) % 3]);
+        this._color = colors[Math.floor(Math.random() * colors.length)];
+        this._lineWidth = 1 + Math.pow(Math.random(), 5) * 30;
+        this._doStroke = Stage.randomInt(0, 3) != 0;
+    }, {
+
+    draw: function(context)
+    {
+        this._startAngle += this._omega;
+        this._endAngle += this._omega / 2;
+
+        if (this._doStroke) {
+            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();
+        } else {
+            context.fillStyle = this._color;
+            context.beginPath();
+            context.lineTo(this._point.x, this._point.y);
+            context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise);
+            context.lineTo(this._point.x, this._point.y);
+            context.fill();
+        }
+    }
+});
 
 // CanvasLinePoint contains no draw() method since it is either moveTo or
 // lineTo depending on its index.
-function CanvasLinePoint(stage, coordinateMaximum)
-{
-    var X_LOOPS = 40;
-    var Y_LOOPS = 20;
-
-    var offsets = [[-2, -1], [2, 1], [-1, 0], [1, 0], [-1, 2], [1, -2]];
-    var offset = offsets[Math.floor(Math.random() * offsets.length)];
-
-    this.coordinate = new Point(X_LOOPS/2, Y_LOOPS/2);
-    if (stage.objects.length) {
-        var head = stage.objects[stage.objects.length - 1].coordinate;
-        this.coordinate.x = head.x;
-        this.coordinate.y = head.y;
-    }
+CanvasLinePoint = Utilities.createClass(
+    function(stage, coordinateMaximum)
+    {
+        var X_LOOPS = 40;
+        var Y_LOOPS = 20;
 
-    var nextCoordinate = this.coordinate.x + offset[0];
-    if (nextCoordinate < 0 || nextCoordinate > X_LOOPS)
-        this.coordinate.x -= offset[0];
-    else
-        this.coordinate.x = nextCoordinate;
-    nextCoordinate = this.coordinate.y + offset[1];
-    if (nextCoordinate < 0 || nextCoordinate > Y_LOOPS)
-        this.coordinate.y -= offset[1];
-    else
-        this.coordinate.y = nextCoordinate;
-
-    var xOff = .25 * (this.coordinate.y % 2);
-    var randX = (xOff + this.coordinate.x) * stage.size.x / X_LOOPS;
-    var randY = this.coordinate.y * stage.size.y / Y_LOOPS;
-    var colors = ["#101010", "#808080", "#c0c0c0", "#101010", "#808080", "#c0c0c0", "#e01040"];
-    this.color = colors[Math.floor(Math.random() * colors.length)];
-
-    this.width = Math.pow(Math.random(), 5) * 20 + 1;
-    this.isSplit = Math.random() > 0.9;
-    this.point = new Point(randX, randY);
-}
+        var offsets = [[-2, -1], [2, 1], [-1, 0], [1, 0], [-1, 2], [1, -2]];
+        var offset = offsets[Math.floor(Math.random() * offsets.length)];
+
+        this.coordinate = new Point(X_LOOPS/2, Y_LOOPS/2);
+        if (stage.objects.length) {
+            var head = stage.objects[stage.objects.length - 1].coordinate;
+            this.coordinate.x = head.x;
+            this.coordinate.y = head.y;
+        }
+
+        var nextCoordinate = this.coordinate.x + offset[0];
+        if (nextCoordinate < 0 || nextCoordinate > X_LOOPS)
+            this.coordinate.x -= offset[0];
+        else
+            this.coordinate.x = nextCoordinate;
+        nextCoordinate = this.coordinate.y + offset[1];
+        if (nextCoordinate < 0 || nextCoordinate > Y_LOOPS)
+            this.coordinate.y -= offset[1];
+        else
+            this.coordinate.y = nextCoordinate;
+
+        var xOff = .25 * (this.coordinate.y % 2);
+        var randX = (xOff + this.coordinate.x) * stage.size.x / X_LOOPS;
+        var randY = this.coordinate.y * stage.size.y / Y_LOOPS;
+        var colors = ["#101010", "#808080", "#c0c0c0", "#101010", "#808080", "#c0c0c0", "#e01040"];
+        this.color = colors[Math.floor(Math.random() * colors.length)];
+
+        this.width = Math.pow(Math.random(), 5) * 20 + 1;
+        this.isSplit = Math.random() > 0.9;
+        this.point = new Point(randX, randY);
+    }
+);
 
 // === STAGES ===
 
index bb5064e..a544984 100644 (file)
@@ -1,11 +1,11 @@
-function Rotater(rotateInterval)
-{
-    this._timeDelta = 0;
-    this._rotateInterval = rotateInterval;
-}
+Rotater = Utilities.createClass(
+    function(rotateInterval)
+    {
+        this._timeDelta = 0;
+        this._rotateInterval = rotateInterval;
+        this._isSampling = false;
+    }, {
 
-Rotater.prototype =
-{
     get interval()
     {
         return this._rotateInterval;
@@ -30,7 +30,7 @@ Rotater.prototype =
     {
         return "rotate(" + Math.floor(this.degree()) + ", " + center.x + "," + center.y + ")";
     }
-};
+});
 
 function BenchmarkState(testInterval)
 {
@@ -82,7 +82,50 @@ BenchmarkState.prototype =
     }
 }
 
-function Stage() {}
+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)
@@ -137,58 +180,15 @@ Utilities.extendObject(Stage, {
     }
 });
 
-Stage.prototype =
-{
-    initialize: function(benchmark)
+Animator = Utilities.createClass(
+    function()
     {
-        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));
-    }
-};
-
-function Animator()
-{
-    this._intervalFrameCount = 0;
-    this._numberOfFramesToMeasurePerInterval = 3;
-    this._referenceTime = 0;
-    this._currentTimeOffset = 0;
-}
+        this._intervalFrameCount = 0;
+        this._numberOfFramesToMeasurePerInterval = 3;
+        this._referenceTime = 0;
+        this._currentTimeOffset = 0;
+    }, {
 
-Animator.prototype =
-{
     initialize: function(benchmark)
     {
         this._benchmark = benchmark;
@@ -257,26 +257,25 @@ Animator.prototype =
             requestAnimationFrame(this.animateLoop.bind(this));
         }
     }
-}
+});
 
-function Benchmark(stage, options)
-{
-    this._options = options;
-
-    this._stage = stage;
-    this._stage.initialize(this);
-    this._animator = new Animator();
-    this._animator.initialize(this);
-
-    this._recordInterval = 200;
-    this._isSampling = false;
-    this._controller = new PIDController(this._options["frame-rate"]);
-    this._sampler = new Sampler(4, 60 * this._options["test-interval"], this);
-    this._state = new BenchmarkState(this._options["test-interval"] * 1000);
-}
+Benchmark = Utilities.createClass(
+    function(stage, options)
+    {
+        this._options = options;
+
+        this._stage = stage;
+        this._stage.initialize(this);
+        this._animator = new Animator();
+        this._animator.initialize(this);
+
+        this._recordInterval = 200;
+        this._isSampling = false;
+        this._controller = new PIDController(this._options["frame-rate"]);
+        this._sampler = new Sampler(4, 60 * this._options["test-interval"], this);
+        this._state = new BenchmarkState(this._options["test-interval"] * 1000);
+    }, {
 
-Benchmark.prototype =
-{
     get options()
     {
         return this._options;
@@ -423,4 +422,4 @@ Benchmark.prototype =
             results[jsonExperiment][Strings.json.measurements.percent] = experiment.percentage();
         });
     }
-};
+});
index e9c62ee..52068ec 100644 (file)
@@ -1,19 +1,12 @@
-function Experiment()
-{
-    this._sum = 0;
-    this._squareSum = 0;
-    this._numberOfSamples = 0;
-    this._maxHeap = Algorithm.createMaxHeap(Experiment.defaults.CONCERN_SIZE);
-}
-
-Experiment.defaults =
-{
-    CONCERN: 5,
-    CONCERN_SIZE: 100,
-}
+Experiment = Utilities.createClass(
+    function()
+    {
+        this._sum = 0;
+        this._squareSum = 0;
+        this._numberOfSamples = 0;
+        this._maxHeap = Algorithm.createMaxHeap(Experiment.defaults.CONCERN_SIZE);
+    }, {
 
-Experiment.prototype =
-{
     sample: function(value)
     {
         this._sum += value;
@@ -49,24 +42,29 @@ Experiment.prototype =
     {
         return Statistics.geometricMean([this.mean(), Math.max(this.concern(percentage), 1)]);
     }
-}
+});
 
-function Sampler(seriesCount, expectedSampleCount, processor)
+Experiment.defaults =
 {
-    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;
-    this.marks = {};
+    CONCERN: 5,
+    CONCERN_SIZE: 100,
 }
 
-Sampler.prototype =
-{
+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;
+        this.marks = {};
+    }, {
+
     record: function() {
         // Assume that arguments.length == this.samples.length
         for (var i = 0; i < arguments.length; i++) {
@@ -99,4 +97,4 @@ Sampler.prototype =
 
         return results;
     }
-}
+});
index 183779a..d25ef8d 100644 (file)
 
 // === PAINT OBJECTS ===
 
-function CanvasLineSegment(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);
-}
-CanvasLineSegment.prototype.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();
-};
-
-function CanvasLinePoint(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));
-}
-CanvasLinePoint.prototype.draw = function(context) {
-    context.lineTo(this._point.x, this._point.y);
-};
-
-function CanvasQuadraticSegment(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);
-};
-CanvasQuadraticSegment.prototype.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();
-};
-
-function CanvasQuadraticPoint(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));
-};
-CanvasQuadraticPoint.prototype.draw = function(context) {
-    context.quadraticCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y);
-};
-
-function CanvasBezierSegment(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);
-};
-CanvasBezierSegment.prototype.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();
-};
-
-function CanvasBezierPoint(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));
-};
-CanvasBezierPoint.prototype.draw = function(context) {
-    context.bezierCurveTo(this._point1.x, this._point1.y, this._point2.x, this._point2.y, this._point3.x, this._point3.y);
-};
-
-function CanvasArcToSegment(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);
-};
-CanvasArcToSegment.prototype.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();
-};
-
-function CanvasArcToSegmentFill(stage) {
-    CanvasArcToSegment.call(this, stage);
-};
-CanvasArcToSegmentFill.prototype.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();
-};
-
-function CanvasArcSegment(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);
-};
-CanvasArcSegment.prototype.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();
-};
-
-function CanvasArcSegmentFill(stage) {
-    CanvasArcSegment.call(this, stage);
-};
-CanvasArcSegmentFill.prototype.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();
-};
-
-function CanvasRect(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);
-}
-CanvasRect.prototype.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();
-};
-
-function CanvasRectFill(stage) {
-    CanvasRect.call(this, stage);
-}
-CanvasRectFill.prototype.draw = function(context) {
-    context.fillStyle = this._color;
-    context.beginPath();
-    context.rect(this._point.x, this._point.y, this._width, this._height);
-    context.fill();
-};
+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();
+    }
+});
 
 // === STAGES ===
 
index 61dd5ea..a890ac1 100644 (file)
@@ -1,21 +1,23 @@
 (function() {
 
-function CanvasImageTile(stage, source)
-{
-    this._context = stage.context;
-    this._size = stage.tileSize;
-    this.source = source;
-}
-
-CanvasImageTile.prototype.getImageData = function()
-{
-    this._imagedata = this._context.getImageData(this.source.x, this.source.y, this._size.width, this._size.height);
-}
-
-CanvasImageTile.prototype.putImageData = function(destination)
-{
-    this._context.putImageData(this._imagedata, destination.x, destination.y);
-}
+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)
@@ -62,7 +64,7 @@ TiledCanvasImageStage = Utilities.createSubclass(Stage,
     {
         this._ctiles += count;
 
-        this._ctiles = Math.max(this._ctiles, 0);    
+        this._ctiles = Math.max(this._ctiles, 0);
         this._ctiles = Math.min(this._ctiles, this._tiles.length);
 
         return this._ctiles;
@@ -100,7 +102,7 @@ TiledCanvasImageStage = Utilities.createSubclass(Stage,
         for (var index = 0; index < this._ctiles; ++index)
             this._tiles[index].putImageData(destinations[index]);
     },
-    
+
     complexity: function()
     {
         return this._ctiles;
index f41e110..84d5af3 100644 (file)
@@ -1,5 +1,36 @@
 2016-02-06  Jon Lee  <jonlee@apple.com>
 
+        Add a convenience function for creating a class.
+
+        The pattern for creating a class is common enough to add as a Utilities
+        helper function. It also makes it easy to collapse class definitions when
+        editing.
+
+        * Animometer/resources/debug-runner/animometer.js: Move ProgressBar definition,
+        since it is only used here.
+        * Animometer/resources/runner/animometer.js: Move ResultsDashboard and
+        ResultsTable definition, since it is only used here.
+        * Animometer/resources/extensions.js: Move Utilities definition to the top. Convert
+        Point, Insets, SimplePromise.
+        (ProgressBar): Moved to animometer.js.
+        (ResultsDashboard): Moved to animometer.js.
+        (ResultsTable): Moved to animometer.js.
+        * Animometer/resources/runner/benchmark-runner.js: Convert BenchmarkRunnerState,
+        BenchmarkRunner.
+        * Animometer/tests/resources/main.js: Convert Rotater, Stage, Animator, Benchmark.
+        * Animometer/tests/resources/sampler.js: Convert Experiment, Sampler.
+
+        Convert test primitives.
+        * Animometer/tests/master/resources/canvas-tests.js: Convert CanvasLineSegment,
+        CanvasArc, CanvasLinePoint.
+        * Animometer/tests/simple/resources/simple-canvas-paths.js: Convert CanvasLineSegment,
+        CanvasLinePoint, CanvasQuadraticSegment, CanvasQuadraticPoint, CanvasBezierSegment,
+        CanvasBezierPoint, CanvasArcToSegment, CanvasArcToSegmentFill, CanvasArcSegment,
+        CanvasArcSegmentFill, CanvasRect, CanvasRectFill.
+        * Animometer/tests/simple/resources/tiled-canvas-image.js: Convert CanvasImageTile.
+
+2016-02-06  Jon Lee  <jonlee@apple.com>
+
         Minor improvements to debug harness.
 
         * Animometer/developer.html:
         and putImageData functions. This test draws a background on the canvas
         and then gets some random tiles from this background and draw them in
         destinations different from their original sources.
-        
+
         * Animometer/resources/debug-runner/tests.js: Adding the new test to the canvas simple tests suite.
-        
+
         * Animometer/resources/extensions.js:
         (Array.prototype.shuffle): Shuffles the elements of an array.
-        
+
         (Point.zero): Returns a new Point object whose x and y are equal zero.
         (Point.prototype.str): Used for debugging the Point object.
-        
+
         * Animometer/tests/simple/resources/tiled-canvas-image.js: Added.
         (CanvasImageTile):
         (CanvasImageTile.prototype.getImageData):