diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index c60774ae42a0..180ec49cb338 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -639,14 +639,6 @@ html|input.urlbar-input[textoverflow]:not([focused]) { -moz-binding: url("chrome://browser/content/search/search.xml#browser-search-autocomplete-result-popup"); } -/* Overlay a badge on top of the icon of additional open search providers - in the search panel. */ -.addengine-item > .button-box > .button-icon, -.addengine-item[type="menu"] > .button-box > .box-inherit > .button-icon { - -moz-binding: url("chrome://browser/content/search/search.xml#addengine-icon"); - display: -moz-stack; -} - #PopupAutoCompleteRichResult { -moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-rich-result-popup"); } diff --git a/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js b/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js index 99f3f256d4e0..ab94124887d7 100644 --- a/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js +++ b/browser/base/content/test/pageinfo/browser_pageinfo_firstPartyIsolation.js @@ -71,16 +71,15 @@ async function test() { Services.prefs.clearUserPref("privacy.firstparty.isolate"); }); + let url = "https://example.com/browser/browser/base/content/test/pageinfo/image.html"; gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser); - gBrowser.selectedBrowser.loadURI("https://example.com/browser/browser/base/content/test/pageinfo/image.html"); - await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); - - let spec = gBrowser.selectedBrowser.currentURI.spec; + gBrowser.selectedBrowser.loadURI(url); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser, false, url); // Pass a dummy imageElement, if there isn't an imageElement, pageInfo.js // will do a preview, however this sometimes will cause intermittent failures, // see bug 1403365. - let pageInfo = BrowserPageInfo(spec, "mediaTab", {}); + let pageInfo = BrowserPageInfo(url, "mediaTab", {}); info("waitForEvent pageInfo"); await waitForEvent(pageInfo, "load"); diff --git a/browser/components/search/content/search.xml b/browser/components/search/content/search.xml index 3bc2d4a3d41a..c98e4db09568 100644 --- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -1153,14 +1153,6 @@ - - - - - - - - .button-box { - -moz-box-pack: start; -} - .addengine-item:first-of-type { border-top: 1px solid var(--panel-separator-color); } @@ -176,20 +172,25 @@ menuitem[cmd="cmd_clearhistory"][disabled] { background-color: var(--arrowpanel-dimmed-further); } -.addengine-icon { - width: 16px; -} - -.addengine-badge { +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-icon { width: 16px; height: 16px; - margin: -7px -9px 7px 9px; - list-style-image: url("chrome://browser/skin/badge-add-engine.png"); } -.addengine-item > .button-box > .button-text, -.addengine-item[type=menu] > .button-box > .box-inherit > .button-text { - -moz-box-flex: 1; +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-badge { + display: -moz-box; + background: url(chrome://browser/skin/search-indicator-badge-add.svg) no-repeat center; + box-shadow: none; + /* "!important" is necessary to override the rule in toolbarbutton.css */ + margin: -4px 0 0 !important; + margin-inline-end: -4px !important; + width: 11px; + height: 11px; + min-width: 11px; + min-height: 11px; +} + +.addengine-item > .toolbarbutton-text { text-align: start; padding-inline-start: 10px; } @@ -199,16 +200,12 @@ menuitem[cmd="cmd_clearhistory"][disabled] { } @media (min-resolution: 1.1dppx) { - .addengine-badge { - list-style-image: url("chrome://browser/skin/badge-add-engine@2x.png"); - } - .addengine-item:not([image]) { list-style-image: url("chrome://browser/skin/search-engine-placeholder@2x.png"); } } -.addengine-item[type=menu] > .button-box > .button-menu-dropmarker { +.addengine-item[type=menu] > .toolbarbutton-menu-dropmarker { display: -moz-box; -moz-appearance: menuarrow !important; list-style-image: none; diff --git a/browser/themes/osx/searchbar.css b/browser/themes/osx/searchbar.css index a8fe3dd068ef..8285138c13d6 100644 --- a/browser/themes/osx/searchbar.css +++ b/browser/themes/osx/searchbar.css @@ -151,10 +151,6 @@ padding: 0 10px; } -.addengine-item > .button-box { - -moz-box-pack: start; -} - .addengine-item:first-of-type { border-top: 1px solid var(--panel-separator-color); } @@ -169,20 +165,25 @@ background-color: var(--arrowpanel-dimmed-further); } -.addengine-icon { - width: 16px; -} - -.addengine-badge { +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-icon { width: 16px; height: 16px; - margin: -7px -9px 7px 9px; - list-style-image: url("chrome://browser/skin/badge-add-engine.png"); } -.addengine-item > .button-box > .button-text, -.addengine-item[type=menu] > .button-box > .box-inherit > .button-text { - -moz-box-flex: 1; +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-badge { + display: -moz-box; + background: url(chrome://browser/skin/search-indicator-badge-add.svg) no-repeat center; + box-shadow: none; + /* "!important" is necessary to override the rule in toolbarbutton.css */ + margin: -4px 0 0 !important; + margin-inline-end: -4px !important; + width: 11px; + height: 11px; + min-width: 11px; + min-height: 11px; +} + +.addengine-item > .toolbarbutton-text { text-align: start; padding-inline-start: 10px; } @@ -192,16 +193,12 @@ } @media (min-resolution: 2dppx) { - .addengine-badge { - list-style-image: url("chrome://browser/skin/badge-add-engine@2x.png"); - } - .addengine-item:not([image]) { list-style-image: url("chrome://browser/skin/search-engine-placeholder@2x.png"); } } -.addengine-item[type=menu] > .button-box > .button-menu-dropmarker { +.addengine-item[type=menu] > .toolbarbutton-menu-dropmarker { display: -moz-box; -moz-appearance: menuarrow !important; list-style-image: none; diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index 9dbd44ea52f5..e2d0691f39a9 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -176,8 +176,6 @@ skin/classic/browser/zoom-out.svg (../shared/icons/zoom-out.svg) - skin/classic/browser/badge-add-engine.png (../shared/search/badge-add-engine.png) - skin/classic/browser/badge-add-engine@2x.png (../shared/search/badge-add-engine@2x.png) skin/classic/browser/search-engine-placeholder.png (../shared/search/search-engine-placeholder.png) skin/classic/browser/search-engine-placeholder@2x.png (../shared/search/search-engine-placeholder@2x.png) skin/classic/browser/search-indicator-badge-add.svg (../shared/search/search-indicator-badge-add.svg) diff --git a/browser/themes/shared/search/badge-add-engine.png b/browser/themes/shared/search/badge-add-engine.png deleted file mode 100644 index 226b7bf2b4c1..000000000000 Binary files a/browser/themes/shared/search/badge-add-engine.png and /dev/null differ diff --git a/browser/themes/shared/search/badge-add-engine@2x.png b/browser/themes/shared/search/badge-add-engine@2x.png deleted file mode 100644 index abf084aade08..000000000000 Binary files a/browser/themes/shared/search/badge-add-engine@2x.png and /dev/null differ diff --git a/browser/themes/windows/searchbar.css b/browser/themes/windows/searchbar.css index 13801ab10fed..5556eccb8c9c 100644 --- a/browser/themes/windows/searchbar.css +++ b/browser/themes/windows/searchbar.css @@ -152,10 +152,6 @@ padding: 0 10px; } -.addengine-item > .button-box { - -moz-box-pack: start; -} - .addengine-item:first-of-type { border-top: 1px solid var(--panel-separator-color); } @@ -170,20 +166,25 @@ background-color: var(--arrowpanel-dimmed-further); } -.addengine-icon { - width: 16px; -} - -.addengine-badge { +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-icon { width: 16px; height: 16px; - margin: -7px -9px 7px 9px; - list-style-image: url("chrome://browser/skin/badge-add-engine.png"); } -.addengine-item > .button-box > .button-text, -.addengine-item[type=menu] > .button-box > .box-inherit > .button-text { - -moz-box-flex: 1; +.addengine-item > .toolbarbutton-badge-stack > .toolbarbutton-badge { + display: -moz-box; + background: url(chrome://browser/skin/search-indicator-badge-add.svg) no-repeat center; + box-shadow: none; + /* "!important" is necessary to override the rule in toolbarbutton.css */ + margin: -4px 0 0 !important; + margin-inline-end: -4px !important; + width: 11px; + height: 11px; + min-width: 11px; + min-height: 11px; +} + +.addengine-item > .toolbarbutton-text { text-align: start; padding-inline-start: 10px; } @@ -193,16 +194,12 @@ } @media (min-resolution: 1.1dppx) { - .addengine-badge { - list-style-image: url("chrome://browser/skin/badge-add-engine@2x.png"); - } - .addengine-item:not([image]) { list-style-image: url("chrome://browser/skin/search-engine-placeholder@2x.png"); } } -.addengine-item[type=menu] > .button-box > .button-menu-dropmarker { +.addengine-item[type=menu] > .toolbarbutton-menu-dropmarker { display: -moz-box; -moz-appearance: menuarrow !important; list-style-image: none; diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index e7423fe7604f..080797a0bf7a 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,7 +1,9 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Taken from upstream commit: 0bcf3e687305960077e1255510e424d0437a3b69 +Version 5.0 +Comparison - https://github.com/devtools-html/debugger.html/compare/release-4...release-5 +Commit: https://github.com/devtools-html/debugger.html/commit/5ecfc84198524399ae75748bd1a28d2df2b45733 Packages: - babel-plugin-transform-es2015-modules-commonjs @6.26.0 diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index 273e9f1b2e63..77414546007a 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -3167,6 +3167,7 @@ html .breakpoints-list .breakpoint.paused { line-height: 1em; position: relative; transition: all 0.25s ease; + cursor: pointer; } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -3602,20 +3603,16 @@ img.ignore-exceptions { display: inline-block; } -.welcomebox .toggle-button-end { - position: absolute; - top: auto; - bottom: 0; - offset-inline-end: 0; - offset-inline-start: auto; -} - -.welcomebox .small-size-layout { +.welcomebox .normal-layout { display: none; } -.welcomebox .normal-layout { - display: inline-block; +.welcomebox .command-bar-button { + position: absolute; + top: auto; + offset-inline-end: 0; + offset-inline-start: auto; + bottom: 0; } .shortcutKeys { diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index afcffda7e0a9..30d1304aa74a 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -10218,7 +10218,8 @@ if (isDevelopment()) { pref("devtools.source-map.client-service.enabled", true); pref("devtools.debugger.pause-on-exceptions", false); pref("devtools.debugger.ignore-caught-exceptions", false); - pref("devtools.debugger.call-stack-visible", false); + pref("devtools.debugger.call-stack-visible", true); + pref("devtools.debugger.scopes-visible", true); pref("devtools.debugger.start-panel-collapsed", false); pref("devtools.debugger.end-panel-collapsed", false); pref("devtools.debugger.tabs", "[]"); @@ -10232,6 +10233,7 @@ if (isDevelopment()) { pref("devtools.debugger.project-directory-root", ""); pref("devtools.debugger.prefs-schema-version", "1.0.1"); pref("devtools.debugger.features.project-text-search", true); + pref("devtools.debugger.features.workers", true); pref("devtools.debugger.features.async-stepping", true); pref("devtools.debugger.features.wasm", true); pref("devtools.debugger.features.shortcuts", true); @@ -10248,6 +10250,7 @@ const prefs = new PrefsHelper("devtools", { pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"], ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"], callStackVisible: ["Bool", "debugger.call-stack-visible"], + scopesVisible: ["Bool", "debugger.scopes-visible"], startPanelCollapsed: ["Bool", "debugger.start-panel-collapsed"], endPanelCollapsed: ["Bool", "debugger.end-panel-collapsed"], frameworkGroupingOn: ["Bool", "debugger.ui.framework-grouping-on"], @@ -10273,7 +10276,8 @@ const features = new PrefsHelper("devtools.debugger.features", { columnBreakpoints: ["Bool", "column-breakpoints", false], mapScopes: ["Bool", "map-scopes", true], breakpointsDropdown: ["Bool", "breakpoints-dropdown", true], - removeCommandBarOptions: ["Bool", "remove-command-bar-options", true] + removeCommandBarOptions: ["Bool", "remove-command-bar-options", true], + workers: ["Bool", "workers", true] }); /* harmony export (immutable) */ __webpack_exports__["features"] = features; @@ -14118,7 +14122,7 @@ module.exports = " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg new file mode 100644 index 000000000000..83458b8095a2 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/lines.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg new file mode 100644 index 000000000000..a7d0eaf37570 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js new file mode 100644 index 000000000000..aa938c5189e0 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/tests.js @@ -0,0 +1,81 @@ +var Headers = { + testName: [ + { + title: "" + Strings.text.testName + "", + text: Strings.text.testName + } + ], + score: [ + { + title: Strings.text.score, + text: Strings.json.score + } + ], + details: [ + { + title: " ", + text: function(data) { + var bootstrap = data[Strings.json.complexity][Strings.json.bootstrap]; + return "±" + (Statistics.largestDeviationPercentage(bootstrap.confidenceLow, bootstrap.median, bootstrap.confidenceHigh) * 100).toFixed(2) + "%"; + } + } + ] +}; + +var Suite = function(name, tests) { + this.name = name; + this.tests = tests; +}; + +var Suites = []; + +Suites.push(new Suite("Animometer", + [ + { + url: "master/multiply.html", + name: "Multiply" + }, + { + url: "master/canvas-stage.html?pathType=arcs", + name: "Canvas Arcs" + }, + { + url: "master/leaves.html", + name: "Leaves" + }, + { + url: "master/canvas-stage.html?pathType=linePath", + name: "Paths" + }, + { + url: "master/canvas-stage.html?pathType=line&lineCap=square", + name: "Canvas Lines" + }, + { + url: "master/focus.html", + name: "Focus" + }, + { + url: "master/image-data.html", + name: "Images" + }, + { + url: "master/text.html", + name: "Design" + }, + { + url: "master/svg-particles.html", + name: "Suits" + }, + ] +)); + +function suiteFromName(name) +{ + return Suites.find(function(suite) { return suite.name == name; }); +} + +function testFromName(suite, name) +{ + return suite.tests.find(function(test) { return test.name == name; }); +} diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js b/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js new file mode 100644 index 000000000000..9322a797b677 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/statistics.js @@ -0,0 +1,397 @@ +Pseudo = +{ + initialRandomSeed: 49734321, + randomSeed: 49734321, + + resetRandomSeed: function() + { + Pseudo.randomSeed = Pseudo.initialRandomSeed; + }, + + random: function() + { + var randomSeed = Pseudo.randomSeed; + randomSeed = ((randomSeed + 0x7ed55d16) + (randomSeed << 12)) & 0xffffffff; + randomSeed = ((randomSeed ^ 0xc761c23c) ^ (randomSeed >>> 19)) & 0xffffffff; + randomSeed = ((randomSeed + 0x165667b1) + (randomSeed << 5)) & 0xffffffff; + randomSeed = ((randomSeed + 0xd3a2646c) ^ (randomSeed << 9)) & 0xffffffff; + randomSeed = ((randomSeed + 0xfd7046c5) + (randomSeed << 3)) & 0xffffffff; + randomSeed = ((randomSeed ^ 0xb55a4f09) ^ (randomSeed >>> 16)) & 0xffffffff; + Pseudo.randomSeed = randomSeed; + return (randomSeed & 0xfffffff) / 0x10000000; + } +}; + +Statistics = +{ + sampleMean: function(numberOfSamples, sum) + { + if (numberOfSamples < 1) + return 0; + return sum / numberOfSamples; + }, + + // With sum and sum of squares, we can compute the sample standard deviation in O(1). + // See https://rniwa.com/2012-11-10/sample-standard-deviation-in-terms-of-sum-and-square-sum-of-samples/ + unbiasedSampleStandardDeviation: function(numberOfSamples, sum, squareSum) + { + if (numberOfSamples < 2) + return 0; + return Math.sqrt((squareSum - sum * sum / numberOfSamples) / (numberOfSamples - 1)); + }, + + geometricMean: function(values) + { + if (!values.length) + return 0; + var roots = values.map(function(value) { return Math.pow(value, 1 / values.length); }) + return roots.reduce(function(a, b) { return a * b; }); + }, + + // Cumulative distribution function + cdf: function(value, mean, standardDeviation) + { + return 0.5 * (1 + Statistics.erf((value - mean) / (Math.sqrt(2 * standardDeviation * standardDeviation)))); + }, + + // Approximation of Gauss error function, Abramowitz and Stegun 7.1.26 + erf: function(value) + { + var sign = (value >= 0) ? 1 : -1; + value = Math.abs(value); + + var a1 = 0.254829592; + var a2 = -0.284496736; + var a3 = 1.421413741; + var a4 = -1.453152027; + var a5 = 1.061405429; + var p = 0.3275911; + + var t = 1.0 / (1.0 + p * value); + var y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-value * value); + return sign * y; + }, + + largestDeviationPercentage: function(low, mean, high) + { + return Math.max(Math.abs(low / mean - 1), (high / mean - 1)); + } +}; + +Experiment = Utilities.createClass( + function(includeConcern) + { + if (includeConcern) + this._maxHeap = Heap.createMaxHeap(Experiment.defaults.CONCERN_SIZE); + this.reset(); + }, { + + reset: function() + { + this._sum = 0; + this._squareSum = 0; + this._numberOfSamples = 0; + if (this._maxHeap) + this._maxHeap.init(); + }, + + get sampleCount() + { + return this._numberOfSamples; + }, + + sample: function(value) + { + this._sum += value; + this._squareSum += value * value; + if (this._maxHeap) + this._maxHeap.push(value); + ++this._numberOfSamples; + }, + + mean: function() + { + return Statistics.sampleMean(this._numberOfSamples, this._sum); + }, + + standardDeviation: function() + { + return Statistics.unbiasedSampleStandardDeviation(this._numberOfSamples, this._sum, this._squareSum); + }, + + cdf: function(value) + { + return Statistics.cdf(value, this.mean(), this.standardDeviation()); + }, + + percentage: function() + { + var mean = this.mean(); + return mean ? this.standardDeviation() * 100 / mean : 0; + }, + + concern: function(percentage) + { + if (!this._maxHeap) + return this.mean(); + + var size = Math.ceil(this._numberOfSamples * percentage / 100); + var values = this._maxHeap.values(size); + return values.length ? values.reduce(function(a, b) { return a + b; }) / values.length : 0; + }, + + score: function(percentage) + { + return Statistics.geometricMean([this.mean(), Math.max(this.concern(percentage), 1)]); + } +}); + +Experiment.defaults = +{ + CONCERN: 5, + CONCERN_SIZE: 100, +}; + +Regression = Utilities.createClass( + function(samples, getComplexity, getFrameLength, startIndex, endIndex, options) + { + var desiredFrameLength = options.desiredFrameLength || 1000/60; + var bestProfile; + + if (!options.preferredProfile || options.preferredProfile == Strings.json.profiles.slope) { + var slope = this._calculateRegression(samples, getComplexity, getFrameLength, startIndex, endIndex, { + shouldClip: true, + s1: desiredFrameLength, + t1: 0 + }); + if (!bestProfile || slope.error < bestProfile.error) { + bestProfile = slope; + this.profile = Strings.json.profiles.slope; + } + } + if (!options.preferredProfile || options.preferredProfile == Strings.json.profiles.flat) { + var flat = this._calculateRegression(samples, getComplexity, getFrameLength, startIndex, endIndex, { + shouldClip: true, + s1: desiredFrameLength, + t1: 0, + t2: 0 + }); + + if (!bestProfile || flat.error < bestProfile.error) { + bestProfile = flat; + this.profile = Strings.json.profiles.flat; + } + } + + this.startIndex = Math.min(startIndex, endIndex); + this.endIndex = Math.max(startIndex, endIndex); + + this.complexity = bestProfile.complexity; + this.s1 = bestProfile.s1; + this.t1 = bestProfile.t1; + this.s2 = bestProfile.s2; + this.t2 = bestProfile.t2; + this.stdev1 = bestProfile.stdev1; + this.stdev2 = bestProfile.stdev2; + this.n1 = bestProfile.n1; + this.n2 = bestProfile.n2; + this.error = bestProfile.error; + }, { + + valueAt: function(complexity) + { + if (this.n1 == 1 || complexity > this.complexity) + return this.s2 + this.t2 * complexity; + return this.s1 + this.t1 * complexity; + }, + + // A generic two-segment piecewise regression calculator. Based on Kundu/Ubhaya + // + // Minimize sum of (y - y')^2 + // where y = s1 + t1*x + // y = s2 + t2*x + // y' = s1 + t1*x' = s2 + t2*x' if x_0 <= x' <= x_n + // + // Allows for fixing s1, t1, s2, t2 + // + // x is assumed to be complexity, y is frame length. Can be used for pure complexity-FPS + // analysis or for ramp controllers since complexity monotonically decreases with time. + _calculateRegression: function(samples, getComplexity, getFrameLength, startIndex, endIndex, options) + { + if (startIndex == endIndex) { + // Only one sample point; we can't calculate any regression. + var x = getComplexity(samples, startIndex); + return { + complexity: x, + s1: x, + t1: 0, + s2: x, + t2: 0, + error1: 0, + error2: 0 + }; + } + + // x is expected to increase in complexity + var iterationDirection = endIndex > startIndex ? 1 : -1; + var lowComplexity = getComplexity(samples, startIndex); + var highComplexity = getComplexity(samples, endIndex); + var a1 = 0, b1 = 0, c1 = 0, d1 = 0, h1 = 0, k1 = 0; + var a2 = 0, b2 = 0, c2 = 0, d2 = 0, h2 = 0, k2 = 0; + + // Iterate from low to high complexity + for (var i = startIndex; iterationDirection * (endIndex - i) > -1; i += iterationDirection) { + var x = getComplexity(samples, i); + var y = getFrameLength(samples, i); + a2 += 1; + b2 += x; + c2 += x * x; + d2 += y; + h2 += y * x; + k2 += y * y; + } + + var s1_best, t1_best, s2_best, t2_best, n1_best, n2_best, error1_best, error2_best, x_best, x_prime; + + function setBest(s1, t1, error1, s2, t2, error2, splitIndex, x_prime, x) + { + s1_best = s1; + t1_best = t1; + error1_best = error1; + s2_best = s2; + t2_best = t2; + error2_best = error2; + // Number of samples included in the first segment, inclusive of splitIndex + n1_best = iterationDirection * (splitIndex - startIndex) + 1; + // Number of samples included in the second segment + n2_best = iterationDirection * (endIndex - splitIndex); + if (!options.shouldClip || (x_prime >= lowComplexity && x_prime <= highComplexity)) + x_best = x_prime; + else { + // Discontinuous piecewise regression + x_best = x; + } + } + + // Iterate from startIndex to endIndex - 1, inclusive + for (var i = startIndex; iterationDirection * (endIndex - i) > 0; i += iterationDirection) { + var x = getComplexity(samples, i); + var y = getFrameLength(samples, i); + var xx = x * x; + var yx = y * x; + var yy = y * y; + // a1, b1, etc. is sum from startIndex to i, inclusive + a1 += 1; + b1 += x; + c1 += xx; + d1 += y; + h1 += yx; + k1 += yy; + // a2, b2, etc. is sum from i+1 to endIndex, inclusive + a2 -= 1; + b2 -= x; + c2 -= xx; + d2 -= y; + h2 -= yx; + k2 -= yy; + + var A = c1*d1 - b1*h1; + var B = a1*h1 - b1*d1; + var C = a1*c1 - b1*b1; + var D = c2*d2 - b2*h2; + var E = a2*h2 - b2*d2; + var F = a2*c2 - b2*b2; + var s1 = options.s1 !== undefined ? options.s1 : (A / C); + var t1 = options.t1 !== undefined ? options.t1 : (B / C); + var s2 = options.s2 !== undefined ? options.s2 : (D / F); + var t2 = options.t2 !== undefined ? options.t2 : (E / F); + // Assumes that the two segments meet + var x_prime = (s1 - s2) / (t2 - t1); + + var error1 = (k1 + a1*s1*s1 + c1*t1*t1 - 2*d1*s1 - 2*h1*t1 + 2*b1*s1*t1) || Number.MAX_VALUE; + var error2 = (k2 + a2*s2*s2 + c2*t2*t2 - 2*d2*s2 - 2*h2*t2 + 2*b2*s2*t2) || Number.MAX_VALUE; + + if (i == startIndex) { + setBest(s1, t1, error1, s2, t2, error2, i, x_prime, x); + continue; + } + + if (C == 0 || F == 0) + continue; + + // Projected point is not between this and the next sample + if (x_prime > getComplexity(samples, i + iterationDirection) || x_prime < x) { + // Calculate lambda, which divides the weight of this sample between the two lines + + // These values remove the influence of this sample + var I = c1 - 2*b1*x + a1*xx; + var H = C - I; + var G = A + B*x - C*y; + + var J = D + E*x - F*y; + var K = c2 - 2*b2*x + a2*xx; + + var lambda = (G*F + G*K - H*J) / (I*J + G*K); + if (lambda > 0 && lambda < 1) { + var lambda1 = 1 - lambda; + s1 = options.s1 !== undefined ? options.s1 : ((A - lambda1*(-h1*x + d1*xx + c1*y - b1*yx)) / (C - lambda1*I)); + t1 = options.t1 !== undefined ? options.t1 : ((B - lambda1*(h1 - d1*x - b1*y + a1*yx)) / (C - lambda1*I)); + s2 = options.s2 !== undefined ? options.s2 : ((D + lambda1*(-h2*x + d2*xx + c2*y - b2*yx)) / (F + lambda1*K)); + t2 = options.t2 !== undefined ? options.t2 : ((E + lambda1*(h2 - d2*x - b2*y + a2*yx)) / (F + lambda1*K)); + x_prime = (s1 - s2) / (t2 - t1); + + error1 = ((k1 + a1*s1*s1 + c1*t1*t1 - 2*d1*s1 - 2*h1*t1 + 2*b1*s1*t1) - lambda1 * Math.pow(y - (s1 + t1*x), 2)) || Number.MAX_VALUE; + error2 = ((k2 + a2*s2*s2 + c2*t2*t2 - 2*d2*s2 - 2*h2*t2 + 2*b2*s2*t2) + lambda1 * Math.pow(y - (s2 + t2*x), 2)) || Number.MAX_VALUE; + } else if (t1 != t2) + continue; + } + + if (error1 + error2 < error1_best + error2_best) + setBest(s1, t1, error1, s2, t2, error2, i, x_prime, x); + } + + return { + complexity: x_best, + s1: s1_best, + t1: t1_best, + stdev1: Math.sqrt(error1_best / n1_best), + s2: s2_best, + t2: t2_best, + stdev2: Math.sqrt(error2_best / n2_best), + error: error1_best + error2_best, + n1: n1_best, + n2: n2_best + }; + } +}); + +Utilities.extendObject(Regression, { + bootstrap: function(samples, iterationCount, processResample, confidencePercentage) + { + var sampleLength = samples.length; + var resample = new Array(sampleLength); + + var bootstrapEstimator = new Experiment; + var bootstrapData = new Array(iterationCount); + + Pseudo.resetRandomSeed(); + for (var i = 0; i < iterationCount; ++i) { + for (var j = 0; j < sampleLength; ++j) + resample[j] = samples[Math.floor(Pseudo.random() * sampleLength)]; + + var resampleResult = processResample(resample); + bootstrapEstimator.sample(resampleResult); + bootstrapData[i] = resampleResult; + } + + bootstrapData.sort(function(a, b) { return a - b; }); + return { + confidenceLow: bootstrapData[Math.round((iterationCount - 1) * (1 - confidencePercentage) / 2)], + confidenceHigh: bootstrapData[Math.round((iterationCount - 1) * (1 + confidencePercentage) / 2)], + median: bootstrapData[Math.round(iterationCount / 2)], + mean: bootstrapEstimator.mean(), + data: bootstrapData, + confidencePercentage: confidencePercentage + }; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js b/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js new file mode 100644 index 000000000000..b58f67e9912d --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/strings.js @@ -0,0 +1,51 @@ +var Strings = { + text: { + testName: "Test Name", + score: "Score" + }, + json: { + marks: "marks", + samplingStartTimeOffset: "Start sampling", + samplingEndTimeOffset: "End sampling", + + samples: "samples", + dataFieldMap: "dataFieldMap", + controller: "controller", + time: "time", + complexity: "complexity", + complexityAverage: "complexityAverage", + frameLength: "frameLength", + smoothedFrameLength: "smoothedFrameLength", + + result: "result", + configuration: "configuration", + score: "score", + scoreLowerBound: "scoreLowerBound", + scoreUpperBound: "scoreUpperBound", + bootstrap: "bootstrap", + measurements: { + average: "average", + concern: "concern", + stdev: "stdev", + percent: "percent" + }, + + regressions: { + startIndex: "startIndex", + endIndex: "endIndex", + segment1: "segment1", + segment2: "segment2", + profile: "profile" + }, + + profiles: { + slope: "slope", + flat: "flat" + }, + + results: { + iterations: "iterationsResults", + tests: "testsResults" + } + } +}; diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js new file mode 100644 index 000000000000..58f5df385ed4 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/3d/resources/webgl.js @@ -0,0 +1,184 @@ +(function() { + +WebGLStage = Utilities.createSubclass(Stage, + function(element, options) + { + Stage.call(this); + }, + { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + + this._numTriangles = 0; + this._bufferSize = 0; + + this._gl = this.element.getContext("webgl"); + var gl = this._gl; + + gl.clearColor(0.5, 0.5, 0.5, 1); + + // Create the vertex shader object. + var vertexShader = gl.createShader(gl.VERTEX_SHADER); + + // The source code for the shader is extracted from the + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html new file mode 100644 index 000000000000..864c19adcd62 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-images.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html new file mode 100644 index 000000000000..c759d45c0887 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-canvas-shapes.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html new file mode 100644 index 000000000000..058de486de64 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-images.html @@ -0,0 +1,22 @@ + + + + + + + + +
+ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html new file mode 100644 index 000000000000..0c1248f49035 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-css-shapes.html @@ -0,0 +1,33 @@ + + + + + + + + +
+ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html new file mode 100644 index 000000000000..2b6a0b9db50a --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-images.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html new file mode 100644 index 000000000000..a821231672fe --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-svg-shapes.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html new file mode 100644 index 000000000000..f67f14ad3636 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/bouncing-tagged-images.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js new file mode 100644 index 000000000000..5fba5ad76108 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-images.js @@ -0,0 +1,47 @@ +(function() { + +BouncingCanvasImage = Utilities.createSubclass(BouncingCanvasParticle, + function(stage) + { + BouncingCanvasParticle.call(this, stage, "image"); + this._imageElement = stage.imageElement; + }, { + + _draw: function() + { + this.context.save(); + this.applyRotation(); + this.context.drawImage(this._imageElement, 0, 0, this.size.x, this.size.y); + this.context.restore(); + } +}); + +BouncingCanvasImagesStage = Utilities.createSubclass(BouncingCanvasParticlesStage, + function() + { + BouncingCanvasParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingCanvasParticlesStage.prototype.initialize.call(this, benchmark, options); + var imageSrc = options["imageSrc"] || "resources/yin-yang.svg"; + this.imageElement = document.querySelector(".hidden[src=\"" + imageSrc + "\"]"); + }, + + createParticle: function() + { + return new BouncingCanvasImage(this); + } +}); + +BouncingCanvasImagesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingCanvasImagesStage(), options); + } +); + +window.benchmarkClass = BouncingCanvasImagesBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js new file mode 100644 index 000000000000..0a76ba05c3d9 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-particles.js @@ -0,0 +1,88 @@ +BouncingCanvasParticle = Utilities.createSubclass(BouncingParticle, + function(stage, shape) + { + BouncingParticle.call(this, stage); + this.context = stage.context; + this._shape = shape; + this._clip = stage.clip; + }, { + + applyRotation: function() + { + if (this._shape == "circle") + return; + + this.context.translate(this.size.x / 2, this.size.y / 2); + this.context.rotate(this.rotater.degree() * Math.PI / 180); + this.context.translate(-this.size.x / 2, -this.size.y / 2); + }, + + applyClipping: function() + { + var clipPoints = BouncingCanvasParticle.clips[this._clip]; + if (!clipPoints) + return; + + this.context.beginPath(); + clipPoints.forEach(function(point, index) { + var point = this.size.multiply(point); + if (!index) + this.context.moveTo(point.x, point.y); + else + this.context.lineTo(point.x, point.y); + }, this); + + this.context.closePath(); + this.context.clip(); + }, + + _draw: function() + { + throw "Not implemented"; + }, + + animate: function(timeDelta) + { + BouncingParticle.prototype.animate.call(this, timeDelta); + this.context.save(); + this.context.translate(this.position.x, this.position.y); + this._draw(); + this.context.restore(); + } +}); + +BouncingCanvasParticle.clips = { + star: [ + new Point(0.50, 0.00), + new Point(0.38, 0.38), + new Point(0.00, 0.38), + new Point(0.30, 0.60), + new Point(0.18, 1.00), + new Point(0.50, 0.75), + new Point(0.82, 1.00), + new Point(0.70, 0.60), + new Point(1.00, 0.38), + new Point(0.62, 0.38) + ] +}; + +BouncingCanvasParticlesStage = Utilities.createSubclass(BouncingParticlesStage, + function() + { + BouncingParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingParticlesStage.prototype.initialize.call(this, benchmark, options); + this.context = this.element.getContext("2d"); + }, + + animate: function(timeDelta) + { + this.context.clearRect(0, 0, this.size.x, this.size.y); + this.particles.forEach(function(particle) { + particle.animate(timeDelta); + }); + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js new file mode 100644 index 000000000000..49a31cf40d49 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-canvas-shapes.js @@ -0,0 +1,87 @@ +(function() { + +BouncingCanvasShape = Utilities.createSubclass(BouncingCanvasParticle, + function(stage) + { + BouncingCanvasParticle.call(this, stage, stage.shape); + this._fill = stage.fill; + this._color0 = Stage.randomColor(); + this._color1 = Stage.randomColor(); + }, { + + _applyFill: function() + { + switch (this._fill) { + case "gradient": + var gradient = this.context.createLinearGradient(0, 0, this.size.width, 0); + gradient.addColorStop(0, this._color0); + gradient.addColorStop(1, this._color1); + this.context.fillStyle = gradient; + break; + + case "solid": + default: + this.context.fillStyle = this._color0; + break; + } + }, + + _drawShape: function() + { + this.context.beginPath(); + + switch (this._shape) { + case "rect": + this.context.rect(0, 0, this.size.width, this.size.height); + break; + + case "circle": + default: + var center = this.size.center; + var radius = Math.min(this.size.x, this.size.y) / 2; + this.context.arc(center.x, center.y, radius, 0, Math.PI * 2, true); + break; + } + + this.context.fill(); + }, + + _draw: function() + { + this.context.save(); + this._applyFill(); + this.applyRotation(); + this.applyClipping(); + this._drawShape(); + this.context.restore(); + } +}); + +BouncingCanvasShapesStage = Utilities.createSubclass(BouncingCanvasParticlesStage, + function () + { + BouncingCanvasParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingCanvasParticlesStage.prototype.initialize.call(this, benchmark, options); + this.parseShapeParameters(options); + }, + + createParticle: function() + { + return new BouncingCanvasShape(this); + } +}); + +BouncingCanvasShapesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingCanvasShapesStage(), options); + } +); + +window.benchmarkClass = BouncingCanvasShapesBenchmark; + +})(); \ No newline at end of file diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js new file mode 100644 index 000000000000..ce9a48c27685 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-images.js @@ -0,0 +1,61 @@ +(function() { + +BouncingCssImage = 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); + + stage.element.appendChild(this.element); + this._move(); + }, { + + _move: function() + { + this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px) " + this.rotater.rotateZ(); + }, + + animate: function(timeDelta) + { + BouncingParticle.prototype.animate.call(this, timeDelta); + this._move(); + } +}); + +BouncingCssImagesStage = 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"; + }, + + createParticle: function() + { + return new BouncingCssImage(this); + }, + + particleWillBeRemoved: function(particle) + { + particle.element.remove(); + } +}); + +BouncingCssImagesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingCssImagesStage(), options); + } +); + +window.benchmarkClass = BouncingCssImagesBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js new file mode 100644 index 000000000000..a1f81863f908 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-css-shapes.js @@ -0,0 +1,86 @@ +(function() { + +BouncingCssShape = Utilities.createSubclass(BouncingParticle, + function(stage) + { + BouncingParticle.call(this, stage); + + this.element = this._createSpan(stage); + + switch (stage.fill) { + case "solid": + default: + this.element.style.backgroundColor = Stage.randomColor(); + break; + + case "gradient": + this.element.style.background = "linear-gradient(" + Stage.randomColor() + ", " + Stage.randomColor() + ")"; + break; + } + + if (stage.blend) + this.element.style.mixBlendMode = Stage.randomStyleMixBlendMode(); + + // Some browsers have not un-prefixed the css filter yet. + if (stage.filter) + Utilities.setElementPrefixedProperty(this.element, "filter", Stage.randomStyleFilter()); + + this._move(); + }, { + + _createSpan: function(stage) + { + var span = document.createElement("span"); + span.className = stage.shape + " " + stage.clip; + span.style.width = this.size.x + "px"; + span.style.height = this.size.y + "px"; + stage.element.appendChild(span); + return span; + }, + + _move: function() + { + this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px)" + this.rotater.rotateZ(); + }, + + animate: function(timeDelta) + { + BouncingParticle.prototype.animate.call(this, timeDelta); + this.rotater.next(timeDelta); + this._move(); + } +}); + +BouncingCssShapesStage = Utilities.createSubclass(BouncingParticlesStage, + function() + { + BouncingParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingParticlesStage.prototype.initialize.call(this, benchmark, options); + this.parseShapeParameters(options); + }, + + createParticle: function() + { + return new BouncingCssShape(this); + }, + + particleWillBeRemoved: function(particle) + { + particle.element.remove(); + } +}); + +BouncingCssShapesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingCssShapesStage(), options); + } +); + +window.benchmarkClass = BouncingCssShapesBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js new file mode 100644 index 000000000000..27e02a708510 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-particles.js @@ -0,0 +1,123 @@ +function BouncingParticle(stage) +{ + this._stageSize = stage.size; + this.size = stage.particleSize; + + this.position = Stage.randomPosition(stage.size.subtract(stage.particleSize)); + this._angle = Stage.randomAngle(); + this._velocity = Stage.randomVelocity(stage.maxVelocity); + this.rotater = Stage.randomRotater(); +} + +BouncingParticle.prototype = +{ + get center() + { + return this.position.add(this.size.center); + }, + + animate: function(timeDelta) + { + this.position = this.position.move(this._angle, this._velocity, timeDelta); + this.rotater.next(timeDelta); + + // If particle is going to move off right side + if (this.position.x + this.size.x > this._stageSize.x) { + // If direction is East-South, go West-South. + if (this._angle >= 0 && this._angle < Math.PI / 2) + this._angle = Math.PI - this._angle; + // If angle is East-North, go West-North. + else if (this._angle > Math.PI / 2 * 3) + this._angle = this._angle - (this._angle - Math.PI / 2 * 3) * 2; + // Make sure the particle does not go outside the stage boundaries. + this.position.x = this._stageSize.x - this.size.x; + } + + // If particle is going to move off left side + if (this.position.x < 0) { + // If angle is West-South, go East-South. + if (this._angle > Math.PI / 2 && this._angle < Math.PI) + this._angle = Math.PI - this._angle; + // If angle is West-North, go East-North. + else if (this._angle > Math.PI && this._angle < Math.PI / 2 * 3) + this._angle = this._angle + (Math.PI / 2 * 3 - this._angle) * 2; + // Make sure the particle does not go outside the stage boundaries. + this.position.x = 0; + } + + // If particle is going to move off bottom side + if (this.position.y + this.size.y > this._stageSize.y) { + // If direction is South, go North. + if (this._angle > 0 && this._angle < Math.PI) + this._angle = Math.PI * 2 - this._angle; + // Make sure the particle does not go outside the stage boundaries. + this.position.y = this._stageSize.y - this.size.y; + } + + // If particle is going to move off top side + if (this.position.y < 0) { + // If direction is North, go South. + if (this._angle > Math.PI && this._angle < Math.PI * 2) + this._angle = this._angle - (this._angle - Math.PI) * 2; + // Make sure the particle does not go outside the stage boundaries. + this.position.y = 0; + } + } +} + +BouncingParticlesStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + this.particles = []; + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + this.particleSize = new Point(parseInt(options["particleWidth"]) || 10, parseInt(options["particleHeight"]) || 10); + this.maxVelocity = Math.max(parseInt(options["maxVelocity"]) || 500, 100); + }, + + parseShapeParameters: function(options) + { + this.shape = options["shape"] || "circle"; + this.fill = options["fill"] || "solid"; + this.clip = options["clip"] || ""; + this.blend = options["blend"] || false; + this.filter = options["filter"] || false; + }, + + animate: function(timeDelta) + { + this.particles.forEach(function(particle) { + particle.animate(timeDelta); + }); + }, + + tune: function(count) + { + if (count == 0) + return; + + if (count > 0) { + for (var i = 0; i < count; ++i) + this.particles.push(this.createParticle()); + return; + } + + count = Math.min(-count, this.particles.length); + + if (typeof(this.particleWillBeRemoved) == "function") { + for (var i = 0; i < count; ++i) + this.particleWillBeRemoved(this.particles[this.particles.length - 1 - i]); + } + + this.particles.splice(-count, count); + }, + + complexity: function() + { + return this.particles.length; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js new file mode 100644 index 000000000000..223955731201 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-images.js @@ -0,0 +1,43 @@ +(function() { + +BouncingSvgImage = Utilities.createSubclass(BouncingSvgParticle, + function(stage) + { + BouncingSvgParticle.call(this, stage, "image"); + + var attrs = { x: 0, y: 0, width: this.size.x, height: this.size.y }; + var xlinkAttrs = { href: stage.imageSrc }; + this.element = Utilities.createSVGElement("image", attrs, xlinkAttrs, stage.element); + this._move(); + } +); + +BouncingSvgImagesStage = Utilities.createSubclass(BouncingSvgParticlesStage, + function() + { + BouncingSvgParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingSvgParticlesStage.prototype.initialize.call(this, benchmark, options); + this.imageSrc = options["imageSrc"] || "resources/yin-yang.svg"; + }, + + createParticle: function() + { + return new BouncingSvgImage(this); + } +}); + +BouncingSvgImagesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingSvgImagesStage(), options); + } +); + +window.benchmarkClass = BouncingSvgImagesBenchmark; + +})(); + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js new file mode 100644 index 000000000000..0988c42d8e7e --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-particles.js @@ -0,0 +1,67 @@ +BouncingSvgParticle = Utilities.createSubclass(BouncingParticle, + function(stage, shape) + { + BouncingParticle.call(this, stage); + this._shape = shape; + }, { + + _applyClipping: function(stage) + { + if (stage.clip != "star") + return; + + stage.ensureClipStarIsCreated(); + this.element.setAttribute("clip-path", "url(#star-clip)"); + }, + + _move: function() + { + var transform = "translate(" + this.position.x + ", " + this.position.y + ")"; + if (this._shape != "circle") + transform += this.rotater.rotate(this.size.center); + this.element.setAttribute("transform", transform); + }, + + animate: function(timeDelta) + { + BouncingParticle.prototype.animate.call(this, timeDelta); + this._move(); + } +}); + +BouncingSvgParticlesStage = Utilities.createSubclass(BouncingParticlesStage, + function() + { + BouncingParticlesStage.call(this); + }, { + + _createDefs: function() + { + return Utilities.createSVGElement("defs", {}, {}, this.element); + }, + + _ensureDefsIsCreated: function() + { + return this.element.querySelector("defs") || this._createDefs(); + }, + + _createClipStar: function() + { + var attrs = { id: "star-clip", clipPathUnits: "objectBoundingBox" }; + var clipPath = Utilities.createSVGElement("clipPath", attrs, {}, this._ensureDefsIsCreated()); + + attrs = { d: "M.50,0L.38,.38L0,.38L.30,.60L.18,1L.50,.75L.82,1L.70,.60L1,.38L.62,.38z" }; + Utilities.createSVGElement("path", attrs, {}, clipPath); + return clipPath; + }, + + ensureClipStarIsCreated: function() + { + return this.element.querySelector("#star-clip") || this._createClipStar(); + }, + + particleWillBeRemoved: function(particle) + { + particle.element.remove(); + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js new file mode 100644 index 000000000000..14c917cc3184 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-svg-shapes.js @@ -0,0 +1,101 @@ +(function() { + +BouncingSvgShape = Utilities.createSubclass(BouncingSvgParticle, + function(stage) + { + BouncingSvgParticle.call(this, stage, stage.shape); + this._fill = stage.fill; + + this._createShape(stage); + this._applyClipping(stage); + this._applyFill(stage); + + this._move(); + }, { + + _createShape: function(stage) + { + switch (this._shape) { + case "rect": + var attrs = { x: 0, y: 0, width: this.size.x, height: this.size.y }; + this.element = Utilities.createSVGElement("rect", attrs, {}, stage.element); + break; + + case "circle": + default: + var attrs = { cx: this.size.x / 2, cy: this.size.y / 2, r: Math.min(this.size.x, this.size.y) / 2 }; + this.element = Utilities.createSVGElement("circle", attrs, {}, stage.element); + break; + } + }, + + _applyFill: function(stage) + { + switch (this._fill) { + case "gradient": + var gradient = stage.createGradient(2); + this.element.setAttribute("fill", "url(#" + gradient.getAttribute("id") + ")"); + break; + + case "solid": + default: + this.element.setAttribute("fill", Stage.randomColor()); + break; + } + } +}); + +BouncingSvgShapesStage = Utilities.createSubclass(BouncingSvgParticlesStage, + function() + { + BouncingSvgParticlesStage.call(this); + }, { + + initialize: function(benchmark, options) + { + BouncingSvgParticlesStage.prototype.initialize.call(this, benchmark, options); + this.parseShapeParameters(options); + this._gradientsCount = 0; + }, + + createGradient: function(stops) + { + var attrs = { id: "gradient-" + ++this._gradientsCount }; + var gradient = Utilities.createSVGElement("linearGradient", attrs, {}, this._ensureDefsIsCreated()); + + for (var i = 0; i < stops; ++i) { + attrs = { offset: i * 100 / (stops - 1) + "%", 'stop-color': Stage.randomColor() }; + Utilities.createSVGElement("stop", attrs, {}, gradient); + } + + return gradient; + }, + + createParticle: function() + { + return new BouncingSvgShape(this); + }, + + particleWillBeRemoved: function(particle) + { + BouncingSvgParticlesStage.prototype.particleWillBeRemoved.call(this, particle); + + var fill = particle.element.getAttribute("fill"); + if (fill.indexOf("url(#") != 0) + return; + + var gradient = this.element.querySelector(fill.substring(4, fill.length - 1)); + this._ensureDefsIsCreated().removeChild(gradient); + } +}); + +BouncingSvgShapesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingSvgShapesStage(), options); + } +); + +window.benchmarkClass = BouncingSvgShapesBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js new file mode 100644 index 000000000000..1ef6a091d213 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/bouncing-tagged-images.js @@ -0,0 +1,106 @@ +(function() { + +BouncingTaggedImage = 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.randomElementInArray(stage.images).src); + + stage.element.appendChild(this.element); + this._move(); + }, { + + _move: function() + { + this.element.style.transform = "translate(" + this.position.x + "px," + this.position.y + "px) " + this.rotater.rotateZ(); + }, + + animate: function(timeDelta) + { + BouncingParticle.prototype.animate.call(this, timeDelta); + this._move(); + } +}); + +BouncingTaggedImagesStage = Utilities.createSubclass(BouncingParticlesStage, + + function() + { + BouncingParticlesStage.call(this); + }, { + + imageSrcs: [ + "image1", + "image2", + "image3", + "image4", + "image5", + ], + images: [], + + initialize: function(benchmark, options) + { + BouncingParticlesStage.prototype.initialize.call(this, benchmark, options); + + var lastPromise; + var images = this.images; + this.imageSrcs.forEach(function(imageSrc) { + var promise = this._loadImage("resources/" + imageSrc + ".jpg"); + if (!lastPromise) + lastPromise = promise; + else { + lastPromise = lastPromise.then(function(img) { + images.push(img); + return promise; + }); + } + }, this); + + lastPromise.then(function(img) { + images.push(img); + benchmark.readyPromise.resolve(); + }); + }, + + _loadImage: function(src) { + var img = new Image; + var promise = new SimplePromise; + + img.onload = function(e) { + promise.resolve(e.target); + }; + + img.src = src; + return promise; + }, + + createParticle: function() + { + return new BouncingTaggedImage(this); + }, + + particleWillBeRemoved: function(particle) + { + particle.element.remove(); + } +}); + +BouncingTaggedImagesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new BouncingTaggedImagesStage(), options); + }, { + + waitUntilReady: function() { + this.readyPromise = new SimplePromise; + return this.readyPromise; + } +}); + +window.benchmarkClass = BouncingTaggedImagesBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg new file mode 100644 index 000000000000..ea7a4c130368 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image1.jpg differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg new file mode 100644 index 000000000000..697272dcb093 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image2.jpg differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg new file mode 100644 index 000000000000..6e5964e7a98f Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image3.jpg differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg new file mode 100644 index 000000000000..806f548c44ac Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image4.jpg differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg new file mode 100644 index 000000000000..d7971f6bcbaf Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/bouncing-particles/resources/image5.jpg differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html new file mode 100644 index 000000000000..6d5b0bf5e632 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/compositing-transforms.html @@ -0,0 +1,24 @@ + + + + + + + + +
+ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html new file mode 100644 index 000000000000..02264d746f2c --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/focus.html @@ -0,0 +1,51 @@ + + + + + + + + +
+
focus
+
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html new file mode 100644 index 000000000000..625882ebef41 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/leaves.html @@ -0,0 +1,26 @@ + + + + + + + + +
+ + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html new file mode 100644 index 000000000000..fdc09399c947 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/particles.html @@ -0,0 +1,24 @@ + + + + + + + + +
+ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js new file mode 100644 index 000000000000..9fd401eeeb75 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/compositing-transforms.js @@ -0,0 +1,66 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js new file mode 100644 index 000000000000..471444b2e7ec --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/dom-particles.js @@ -0,0 +1,73 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js new file mode 100644 index 000000000000..d7722cdff42a --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/focus.js @@ -0,0 +1,166 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js new file mode 100644 index 000000000000..604c973667f0 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/dom/resources/leaves.js @@ -0,0 +1,48 @@ +Leaf = Utilities.createSubclass(Particle, + function(stage) + { + this.element = document.createElement("img"); + this.element.setAttribute("src", Stage.randomElementInArray(stage.images).src); + stage.element.appendChild(this.element); + + Particle.call(this, stage); + }, { + + sizeMinimum: 20, + sizeRange: 40, + + reset: function() + { + Particle.prototype.reset.call(this); + this.element.style.width = this.size.x + "px"; + this.element.style.height = this.size.y + "px"; + this._opacity = .01; + this._opacityRate = 0.02 * Stage.random(1, 6); + this._position = new Point(Stage.random(0, this.maxPosition.x), Stage.random(-this.size.height, this.maxPosition.y)); + this._velocity = new Point(Stage.random(-6, -2), .1 * this.size.y + Stage.random(-1, 1)); + }, + + animate: function(timeDelta) + { + this.rotater.next(timeDelta); + + this._position.x += this._velocity.x + 8 * this.stage.focusX; + this._position.y += this._velocity.y; + this._opacity += this._opacityRate; + if (this._opacity > 1) { + this._opacity = 1; + this._opacityRate *= -1; + } else if (this._opacity < 0 || this._position.y > this.stage.size.height) + this.reset(); + + if (this._position.x < -this.size.width || this._position.x > this.stage.size.width) + this._position.x = this._position.x - Math.sign(this._position.x) * (this.size.width + this.stage.size.width); + this.move(); + }, + + move: function() + { + this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ(); + this.element.style.opacity = this._opacity; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html new file mode 100644 index 000000000000..f86cb44e10b2 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/canvas-stage.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html new file mode 100644 index 000000000000..e97a7cd79f54 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/focus.html @@ -0,0 +1,29 @@ + + + + + + + + +
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html new file mode 100644 index 000000000000..36b52c9d8750 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/image-data.html @@ -0,0 +1,28 @@ + + + + + + + + +
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html new file mode 100644 index 000000000000..ada054025ca7 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/leaves.html @@ -0,0 +1,25 @@ + + + + + + + + +
+ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html new file mode 100644 index 000000000000..717aff7d8b4b --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/multiply.html @@ -0,0 +1,53 @@ + + + + + + + + +
+
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js new file mode 100644 index 000000000000..22002eccd61f --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-stage.js @@ -0,0 +1,52 @@ +SimpleCanvasStage = Utilities.createSubclass(Stage, + function(canvasObject) + { + Stage.call(this); + this._canvasObject = canvasObject; + this.objects = []; + this.offsetIndex = 0; + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + this.context = this.element.getContext("2d"); + }, + + tune: function(count) + { + if (count == 0) + return; + + if (count < 0) { + this.offsetIndex = Math.min(this.offsetIndex - count, this.objects.length); + return; + } + + var newIndex = this.offsetIndex - count; + if (newIndex < 0) { + this.offsetIndex = 0; + newIndex = -newIndex; + for (var i = 0; i < newIndex; ++i) { + if (this._canvasObject.constructor === Array) + this.objects.push(new (Stage.randomElementInArray(this._canvasObject))(this)); + else + this.objects.push(new this._canvasObject(this)); + } + } else + this.offsetIndex = newIndex; + }, + + animate: function() + { + var context = this.context; + context.clearRect(0, 0, this.size.x, this.size.y); + for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) + this.objects[i].draw(context); + }, + + complexity: function() + { + return this.objects.length - this.offsetIndex; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js new file mode 100644 index 000000000000..79fc86708296 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/canvas-tests.js @@ -0,0 +1,311 @@ +(function() { + +// === PAINT OBJECTS === + +CanvasLineSegment = Utilities.createClass( + function(stage) + { + var circle = Stage.randomInt(0, 3); + this._color = ["#e01040", "#10c030", "#744CBA", "#e05010"][circle]; + this._lineWidth = Math.pow(Pseudo.random(), 12) * 20 + 3; + this._omega = Pseudo.random() * 3 + 0.2; + var theta = Stage.randomAngle(); + this._cosTheta = Math.cos(theta); + this._sinTheta = Math.sin(theta); + this._startX = stage.circleRadius * this._cosTheta + stage.circleX[circle]; + this._startY = stage.circleRadius * this._sinTheta + stage.circleY[circle]; + this._length = Math.pow(Pseudo.random(), 8) * stage.lineLengthMaximum + stage.lineMinimum; + this._segmentDirection = Pseudo.random() > 0.5 ? -1 : 1; + }, { + + draw: function(context) + { + context.strokeStyle = this._color; + context.lineWidth = this._lineWidth; + + this._length += Math.sin(Stage.dateCounterValue(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(); + } +}); + +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(Pseudo.random(), 5) * (Math.min(distanceX, distanceY) / 1.8); + this._startAngle = Stage.randomAngle(); + this._endAngle = Stage.randomAngle(); + this._omega = (Pseudo.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(Pseudo.random() * colors.length)]; + this._lineWidth = 1 + Math.pow(Pseudo.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. +CanvasLinePoint = Utilities.createClass( + function(stage) + { + var colors = ["#101010", "#808080", "#c0c0c0", "#101010", "#808080", "#c0c0c0", "#e01040"]; + this.color = Stage.randomElementInArray(colors); + this.width = Math.pow(Pseudo.random(), 5) * 20 + 1; + this.isSplit = Pseudo.random() > 0.95; + + var nextPoint; + if (stage.objects.length) + nextPoint = this.randomPoint(stage, stage.objects[stage.objects.length - 1].coordinate); + else + nextPoint = this.randomPoint(stage, this.gridSize.center); + this.point = nextPoint.point; + this.coordinate = nextPoint.coordinate; + }, { + + gridSize: new Point(80, 40), + offsets: [ + new Point(-4, 0), + new Point(2, 0), + new Point(1, -2), + new Point(1, 2), + ], + + randomPoint: function(stage, startCoordinate) + { + var coordinate = startCoordinate; + if (stage.objects.length) { + var offset = Stage.randomElementInArray(this.offsets); + + coordinate = coordinate.add(offset); + if (coordinate.x < 0 || coordinate.x > this.gridSize.width) + coordinate.x -= offset.x * 2; + if (coordinate.y < 0 || coordinate.y > this.gridSize.height) + coordinate.y -= offset.y * 2; + } + + var x = (coordinate.x + .5) * stage.size.x / (this.gridSize.width + 1); + var y = (coordinate.y + .5) * stage.size.y / (this.gridSize.height + 1); + return { + point: new Point(x, y), + coordinate: coordinate + }; + }, + + draw: function(context) + { + context.lineTo(this.point.x, this.point.y); + } +}); + +CanvasQuadraticSegment = Utilities.createSubclass(CanvasLinePoint, + function(stage) + { + CanvasLinePoint.call(this, stage); + // The chosen point is instead the control point. + this._point2 = this.point; + + // Get another random point for the actual end point of the segment. + var nextPoint = this.randomPoint(stage, this.coordinate); + this.point = nextPoint.point; + this.coordinate = nextPoint.coordinate; + }, { + + draw: function(context) + { + context.quadraticCurveTo(this._point2.x, this._point2.y, this.point.x, this.point.y); + } +}); + +CanvasBezierSegment = Utilities.createSubclass(CanvasLinePoint, + function(stage) + { + CanvasLinePoint.call(this, stage); + // The chosen point is instead the first control point. + this._point2 = this.point; + var nextPoint = this.randomPoint(stage, this.coordinate); + this._point3 = nextPoint.point; + + nextPoint = this.randomPoint(stage, nextPoint.coordinate); + this.point = nextPoint.point; + this.coordinate = nextPoint.coordinate; + }, { + + draw: function(context, off) + { + context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this.point.x, this.point.y); + } +}); + +// === STAGES === + +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"; + this.lineMinimum = 20; + this.lineLengthMaximum = 40; + this.circleRadius = this.size.x / 8 - .4 * (this.lineMinimum + this.lineLengthMaximum); + this.circleX = [ + 5.5 / 32 * this.size.x, + 12.5 / 32 * this.size.x, + 19.5 / 32 * this.size.x, + 26.5 / 32 * this.size.x, + ]; + this.circleY = [ + 2.1 / 3 * this.size.y, + 0.9 / 3 * this.size.y, + 2.1 / 3 * this.size.y, + 0.9 / 3 * this.size.y + ]; + this.halfSize = this.size.multiply(.5); + this.twoFifthsSizeX = this.size.x * .4; + }, + + animate: function() + { + var context = this.context; + context.clearRect(0, 0, this.size.x, this.size.y); + + var angle = Stage.dateFractionalValue(3000) * Math.PI * 2; + var dx = this.twoFifthsSizeX * Math.cos(angle); + var dy = this.twoFifthsSizeX * Math.sin(angle); + + var gradient = context.createLinearGradient(this.halfSize.x + dx, this.halfSize.y + dy, this.halfSize.x - dx, this.halfSize.y - dy); + var gradientStep = 0.5 + 0.5 * Math.sin(Stage.dateFractionalValue(5000) * Math.PI * 2); + var colorStopStep = Utilities.lerp(gradientStep, -.1, .1); + var brightnessStep = Math.round(Utilities.lerp(gradientStep, 32, 64)); + var color1Step = "rgba(" + brightnessStep + "," + brightnessStep + "," + (brightnessStep << 1) + ",.4)"; + var color2Step = "rgba(" + (brightnessStep << 1) + "," + (brightnessStep << 1) + "," + brightnessStep + ",.4)"; + gradient.addColorStop(0, color1Step); + gradient.addColorStop(.2 + colorStopStep, color1Step); + gradient.addColorStop(.8 - colorStopStep, color2Step); + gradient.addColorStop(1, color2Step); + + context.lineWidth = 15; + for(var i = 0; i < 4; i++) { + context.strokeStyle = ["#e01040", "#10c030", "#744CBA", "#e05010"][i]; + context.fillStyle = ["#70051d", "#016112", "#2F0C6E", "#702701"][i]; + context.beginPath(); + context.arc(this.circleX[i], this.circleY[i], this.circleRadius, 0, Math.PI*2); + context.stroke(); + context.fill(); + context.fillStyle = gradient; + context.fill(); + } + + for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) + this.objects[i].draw(context); + } +}); + +CanvasLinePathStage = Utilities.createSubclass(SimpleCanvasStage, + function() + { + SimpleCanvasStage.call(this, [CanvasLinePoint, CanvasLinePoint, CanvasQuadraticSegment, CanvasBezierSegment]); + }, { + + initialize: function(benchmark, options) + { + SimpleCanvasStage.prototype.initialize.call(this, benchmark, options); + this.context.lineJoin = options["lineJoin"] || "bevel"; + this.context.lineCap = options["lineCap"] || "butt"; + }, + + animate: function() { + var context = this.context; + + context.clearRect(0, 0, this.size.x, this.size.y); + context.beginPath(); + for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) { + var object = this.objects[i]; + if (i == this.offsetIndex) { + context.lineWidth = object.width; + context.strokeStyle = object.color; + context.beginPath(); + context.moveTo(object.point.x, object.point.y); + } else { + object.draw(context); + + if (object.isSplit) { + context.stroke(); + + context.lineWidth = object.width; + context.strokeStyle = object.color; + context.beginPath(); + context.moveTo(object.point.x, object.point.y); + } + + if (Pseudo.random() > 0.995) + object.isSplit = !object.isSplit; + } + } + context.stroke(); + } +}); + +// === BENCHMARK === + +CanvasPathBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + var stage; + switch (options["pathType"]) { + case "line": + stage = new CanvasLineSegmentStage(); + break; + case "linePath": + stage = new CanvasLinePathStage(); + break; + case "arcs": + stage = new SimpleCanvasStage(CanvasArc); + break; + } + + Benchmark.call(this, stage, options); + } +); + +window.benchmarkClass = CanvasPathBenchmark; + +})(); \ No newline at end of file diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg new file mode 100644 index 000000000000..3f94e7a4b296 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png new file mode 100644 index 000000000000..e513ce11e337 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/compass100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg new file mode 100644 index 000000000000..e3c7611d2ab1 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png new file mode 100644 index 000000000000..81f9c1641d8f Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/console100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg new file mode 100644 index 000000000000..68860efa86ef --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png new file mode 100644 index 000000000000..790e3dcfcada Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/contribute100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg new file mode 100644 index 000000000000..646ddf446c69 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png new file mode 100644 index 000000000000..e2652096dcd1 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/debugger100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js new file mode 100644 index 000000000000..04842e744e52 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/focus.js @@ -0,0 +1,129 @@ +(function() { + +var minimumDiameter = 30; +var sizeVariance = 20; +var travelDistance = 50; + +var minBlurValue = 1; +var maxBlurValue = 10; + +var opacityMultiplier = 30; +var focusDuration = 1000; +var movementDuration = 2500; + +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); + var left = Stage.random(0, stage.size.width - size); + + this.particle = document.createElement("div"); + this.particle.style.width = size + "px"; + this.particle.style.height = size + "px"; + this.particle.style.top = top + "px"; + this.particle.style.left = left + "px"; + this.particle.style.zIndex = Math.round((1 - this._depth) * 10); + + 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; + + this.animate(stage, 0, 0); + }, { + + hide: function() + { + this.particle.style.display = "none"; + }, + + show: function() + { + this.particle.style.display = "block"; + }, + + animate: function(stage, sinFactor, cosFactor) + { + var top = sinFactor * this._sinMultiplier; + var left = cosFactor * this._cosMultiplier; + var distance = Math.abs(this._depth - stage.focalPoint); + var blur = Utilities.lerp(distance, minBlurValue, maxBlurValue); + var opacity = Math.max(5, opacityMultiplier * (1 - distance)); + + Utilities.setElementPrefixedProperty(this.particle, "filter", "blur(" + blur + "px) opacity(" + opacity + "%)"); + this.particle.style.transform = "translate3d(" + left + "%, " + top + "%, 0)"; + } +}); + +var FocusStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + + this._testElements = []; + this._offsetIndex = 0; + this.focalPoint = 0.5; + }, + + complexity: function() + { + return 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.particle); + } + 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 / movementDuration); + var cosFactor = Math.cos(time / movementDuration); + + this.focalPoint = 0.5 + 0.5 * Math.sin(time / focusDuration); + + for (var i = 0; i < this._offsetIndex; ++i) + this._testElements[i].animate(this, sinFactor, cosFactor); + } +}); + +var FocusBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new FocusStage(), options); + } +); + +window.benchmarkClass = FocusBenchmark; + +}()); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js new file mode 100644 index 000000000000..6de5d068bb9b --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/image-data.js @@ -0,0 +1,181 @@ +(function() { + +var ImageDataStage = Utilities.createSubclass(Stage, + function() { + Stage.call(this); + + this.testElements = []; + this._offsetIndex = 0; + }, { + + imageWidth: 50, + imageHeight: 50, + pixelStride: 4, + rowStride: 200, + weightNegativeThreshold: 0.04, + weightPositiveThreshold: 0.96, + imageSrcs: [ + "compass", + "console", + "contribute", + "debugger", + "inspector", + "layout", + "performance", + "script", + "shortcuts", + "standards", + "storage", + "styles", + "timeline" + ], + images: [], + + initialize: function(benchmark) + { + Stage.prototype.initialize.call(this, benchmark); + + var lastPromise; + var images = this.images; + this.imageSrcs.forEach(function(imageSrc) { + var promise = this._loadImage("resources/" + imageSrc + ".svg"); + if (!lastPromise) + lastPromise = promise; + else { + lastPromise = lastPromise.then(function(img) { + images.push(img); + return promise; + }); + } + }, this); + + lastPromise.then(function(img) { + images.push(img); + benchmark.readyPromise.resolve(); + }.bind(this)); + }, + + _loadImage: function(src) { + var img = new Image; + var promise = new SimplePromise; + + img.addEventListener('load', function onImageLoad(e) { + img.removeEventListener('load', onImageLoad); + promise.resolve(img); + }); + + img.src = src; + return promise; + }, + + tune: function(count) + { + if (count == 0) + return; + + if (count < 0) { + this._offsetIndex = Math.max(this._offsetIndex + count, 0); + for (var i = this._offsetIndex; i < this.testElements.length; ++i) + this.testElements[i].style.display = "none"; + return; + } + + this._offsetIndex = this._offsetIndex + count; + var index = Math.min(this._offsetIndex, this.testElements.length); + for (var i = 0; i < index; ++i) { + this.testElements[i].style.display = "block"; + this._refreshElement(this.testElements[i]); + } + if (this._offsetIndex <= this.testElements.length) + return; + + index = this._offsetIndex - this.testElements.length; + for (var i = 0; i < index; ++i) { + var element = this._createTestElement(); + this.testElements.push(element); + this.element.appendChild(element); + } + }, + + _createTestElement: function() { + var element = document.createElement('canvas'); + element.width = this.imageWidth; + element.height = this.imageHeight; + element.style.width = this.imageWidth + 'px'; + element.style.height = this.imageHeight + 'px'; + + this._refreshElement(element); + return element; + }, + + _refreshElement: function(element) { + var top = Stage.randomInt(0, Math.floor((this.size.height - this.imageHeight) / this.imageHeight)) * this.imageHeight; + var left = Stage.randomInt(0, Math.floor((this.size.width - this.imageWidth) / this.imageWidth)) * this.imageWidth; + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + }, + + animate: function(timeDelta) { + for (var i = 0; i < this._offsetIndex; ++i) { + var element = this.testElements[i]; + var context = element.getContext("2d"); + + // Get image data + var imageData = context.getImageData(0, 0, this.imageWidth, this.imageHeight); + + var didDraw = false, + neighborPixelIndex, + dataLen = imageData.data.length; + for (var j = 0; j < dataLen; j += this.pixelStride) { + if (imageData.data[j + 3] === 0) + continue; + + // get random neighboring pixel color + neighborPixelIndex = this._getRandomNeighboringPixelIndex(j, dataLen); + + // Update the RGB data + imageData.data[j] = imageData.data[neighborPixelIndex]; + imageData.data[j + 1] = imageData.data[neighborPixelIndex + 1]; + imageData.data[j + 2] = imageData.data[neighborPixelIndex + 2]; + imageData.data[j + 3] = imageData.data[neighborPixelIndex + 3]; + didDraw = true; + } + + if (didDraw) + context.putImageData(imageData, 0, 0); + else { + this._refreshElement(element); + element.getContext("2d").drawImage(Stage.randomElementInArray(this.images), 0, 0, this.imageWidth, this.imageHeight); + } + } + }, + + _getRandomNeighboringPixelIndex: function(pixelIdx, pixelArrayLength) + { + var xOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold)); + var yOffset = Math.floor((Pseudo.random() - this.weightNegativeThreshold) / (this.weightPositiveThreshold - this.weightNegativeThreshold)); + return (pixelIdx + this.pixelStride * xOffset + this.rowStride * yOffset) % pixelArrayLength; + }, + + complexity: function() + { + return this._offsetIndex; + } +}); + +var ImageDataBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new ImageDataStage(), options); + }, { + + waitUntilReady: function() { + this.readyPromise = new SimplePromise; + return this.readyPromise; + } +}); + +window.benchmarkClass = ImageDataBenchmark; + +}()); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg new file mode 100644 index 000000000000..68cc413052d9 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png new file mode 100644 index 000000000000..26d1a7d59297 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/inspector100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg new file mode 100644 index 000000000000..73db97eb4637 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png new file mode 100644 index 000000000000..5b1ec2806b11 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/layout100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js new file mode 100644 index 000000000000..7a049836ff24 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/leaves.js @@ -0,0 +1,135 @@ +Leaf = Utilities.createSubclass(Particle, + function(stage) + { + this.element = document.createElement("img"); + this.element.setAttribute("src", Stage.randomElementInArray(stage.images).src); + var sizeString = this.sizeMinimum + "px"; + this.element.style.width = sizeString; + this.element.style.height = sizeString; + stage.element.appendChild(this.element); + + Particle.call(this, stage); + }, { + + sizeMinimum: 25, + sizeRange: 0, + + reset: function() + { + Particle.prototype.reset.call(this); + this._life = Stage.randomInt(20, 100); + this._position = new Point(Stage.random(0, this.maxPosition.x), Stage.random(-this.size.height, this.maxPosition.y)); + this._velocity = new Point(Stage.random(-6, -2), .1 * this.size.y + Stage.random(-1, 1)); + }, + + animate: function(timeDelta) + { + this.rotater.next(timeDelta); + + this._position.x += this._velocity.x + 8 * this.stage.focusX; + this._position.y += this._velocity.y; + + this._life--; + if (!this._life || this._position.y > this.stage.size.height) + this.reset(); + + if (this._position.x < -this.size.width || this._position.x > this.stage.size.width) + this._position.x = this._position.x - Math.sign(this._position.x) * (this.size.width + this.stage.size.width); + this.move(); + }, + + move: function() + { + this.element.style.transform = "translate(" + this._position.x + "px, " + this._position.y + "px)" + this.rotater.rotateZ(); + } +}); + +Utilities.extendObject(ParticlesStage.prototype, { + + imageSrcs: [ + "compass", + "console", + "contribute", + "debugger", + "inspector", + "layout", + "performance", + "script", + "shortcuts", + "standards", + "storage", + "styles", + "timeline" + ], + images: [], + + initialize: function(benchmark) + { + Stage.prototype.initialize.call(this, benchmark); + + var lastPromise; + var images = this.images; + this.imageSrcs.forEach(function(imageSrc) { + var promise = this._loadImage("../master/resources/" + imageSrc + "100.png"); + if (!lastPromise) + lastPromise = promise; + else { + lastPromise = lastPromise.then(function(img) { + images.push(img); + return promise; + }); + } + }, this); + + lastPromise.then(function(img) { + images.push(img); + benchmark.readyPromise.resolve(); + }); + }, + + _loadImage: function(src) { + var img = new Image; + var promise = new SimplePromise; + + img.onload = function(e) { + promise.resolve(e.target); + }; + + img.src = src; + return promise; + }, + + animate: function(timeDelta) + { + this.focusX = 0.5 + 0.5 * Math.sin(Stage.dateFractionalValue(10000) * Math.PI * 2); + timeDelta /= 4; + this.particles.forEach(function(particle) { + particle.animate(timeDelta); + }); + }, + + createParticle: function() + { + return new Leaf(this); + }, + + willRemoveParticle: function(particle) + { + particle.element.remove(); + } +}); + +LeavesBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new ParticlesStage(), options); + }, { + + waitUntilReady: function() { + this.readyPromise = new SimplePromise; + return this.readyPromise; + } + +}); + +window.benchmarkClass = LeavesBenchmark; diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js new file mode 100644 index 000000000000..e93cfbb5b90e --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/multiply.js @@ -0,0 +1,119 @@ +(function() { + +var MultiplyStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + this.tiles = []; + this._offsetIndex = 0; + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + var tileSize = Math.round(this.size.height / 25); + + // Fill the scene with elements + var x = Math.round((this.size.width - tileSize) / 2); + var y = Math.round((this.size.height - tileSize) / 2); + var tileStride = tileSize; + var direction = 0; + var spiralCounter = 2; + var nextIndex = 1; + var maxSide = Math.floor(y / tileStride) * 2 + 1; + this._centerSpiralCount = maxSide * maxSide; + for (var i = 0; i < this._centerSpiralCount; ++i) { + this._addTile(x, y, tileSize, Stage.randomInt(0, 359)); + + if (i == nextIndex) { + direction = (direction + 1) % 4; + spiralCounter++; + nextIndex += spiralCounter >> 1; + } + if (direction == 0) + x += tileStride; + else if (direction == 1) + y -= tileStride; + else if (direction == 2) + x -= tileStride; + else + y += tileStride; + } + + this._sidePanelCount = maxSide * Math.floor((this.size.width - x) / tileStride) * 2; + for (var i = 0; i < this._sidePanelCount; ++i) { + var sideX = x + Math.floor(Math.floor(i / maxSide) / 2) * tileStride; + var sideY = y - tileStride * (i % maxSide); + + if (Math.floor(i / maxSide) % 2 == 1) + sideX = this.size.width - sideX - tileSize + 1; + this._addTile(sideX, sideY, tileSize, Stage.randomInt(0, 359)); + } + }, + + _addTile: function(x, y, tileSize, rotateDeg) + { + var tile = Utilities.createElement("div", { class: "div-" + Stage.randomInt(0,6) }, this.element); + var halfTileSize = tileSize / 2; + tile.style.left = x + 'px'; + tile.style.top = y + 'px'; + tile.style.width = tileSize + 'px'; + tile.style.height = tileSize + 'px'; + tile.style.visibility = "hidden"; + + var distance = 1 / tileSize * this.size.multiply(0.5).subtract(new Point(x + halfTileSize, y + halfTileSize)).length(); + this.tiles.push({ + element: tile, + rotate: rotateDeg, + step: Math.max(3, distance / 1.5), + distance: distance, + active: false + }); + }, + + complexity: function() + { + return this._offsetIndex; + }, + + tune: function(count) + { + this._offsetIndex = Math.max(0, Math.min(this._offsetIndex + count, this.tiles.length)); + this._distanceFactor = 1.5 * (1 - 0.5 * Math.max(this._offsetIndex - this._centerSpiralCount, 0) / this._sidePanelCount) / Math.sqrt(this._offsetIndex); + }, + + animate: function() + { + var progress = this._benchmark.timestamp % 10000 / 10000; + var bounceProgress = Math.sin(2 * Math.abs( 0.5 - progress)); + var l = Utilities.lerp(bounceProgress, 20, 50); + var hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,"; + + for (var i = 0; i < this._offsetIndex; ++i) { + var tile = this.tiles[i]; + tile.active = true; + tile.element.style.visibility = ""; + tile.rotate += tile.step; + tile.element.style.transform = "rotate(" + tile.rotate + "deg)"; + + var influence = Math.max(.01, 1 - (tile.distance * this._distanceFactor)); + tile.element.style.backgroundColor = hslPrefix + l * Math.tan(influence / 1.25) + "%," + influence + ")"; + } + + for (var i = this._offsetIndex; i < this.tiles.length && this.tiles[i].active; ++i) { + this.tiles[i].active = false; + this.tiles[i].element.style.visibility = "hidden"; + } + } +}); + +var MultiplyBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new MultiplyStage(), options); + } +); + +window.benchmarkClass = MultiplyBenchmark; + +}()); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js new file mode 100644 index 000000000000..cf474e414238 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/particles.js @@ -0,0 +1,112 @@ +function Particle(stage) +{ + this.stage = stage; + this.rotater = Stage.randomRotater(); + this.reset(); + this.move(); +} + +Particle.prototype = +{ + sizeMinimum: 40, + sizeRange: 10, + + reset: function() + { + var randSize = Math.round(Math.pow(Pseudo.random(), 4) * this.sizeRange + this.sizeMinimum); + this.size = new Point(randSize, randSize); + this.minPosition = this.size.center; + this.maxPosition = this.stage.size.subtract(this.minPosition); + }, + + animate: function(timeDelta) + { + this.rotater.next(timeDelta); + + this.position = this.position.add(this.velocity.multiply(timeDelta)); + this.velocity.y += 0.03; + + // If particle is going to move off right side + if (this.position.x > this.maxPosition.x) { + if (this.velocity.x > 0) + this.velocity.x *= -1; + this.position.x = this.maxPosition.x; + } else if (this.position.x < this.minPosition.x) { + // If particle is going to move off left side + if (this.velocity.x < 0) + this.velocity.x *= -1; + this.position.x = this.minPosition.x; + } + + // If particle is going to move off bottom side + if (this.position.y > this.maxPosition.y) { + // Adjust direction but maintain magnitude + var magnitude = this.velocity.length(); + this.velocity.x *= 1.5 + .005 * this.size.x; + this.velocity = this.velocity.normalize().multiply(magnitude); + if (Math.abs(this.velocity.y) < 0.7) + this.reset(); + else { + if (this.velocity.y > 0) + this.velocity.y *= -0.999; + this.position.y = this.maxPosition.y; + } + } else if (this.position.y < this.minPosition.y) { + // If particle is going to move off top side + var magnitude = this.velocity.length(); + this.velocity.x *= 1.5 + .005 * this.size.x; + this.velocity = this.velocity.normalize().multiply(magnitude); + if (this.velocity.y < 0) + this.velocity.y *= -0.998; + this.position.y = this.minPosition.y; + } + + this.move(); + }, + + move: function() + { + } +} + +ParticlesStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + this.particles = []; + }, { + + animate: function(timeDelta) + { + timeDelta /= 4; + this.particles.forEach(function(particle) { + particle.animate(timeDelta); + }); + }, + + tune: function(count) + { + if (count == 0) + return; + + if (count > 0) { + for (var i = 0; i < count; ++i) + this.particles.push(this.createParticle()); + return; + } + + count = Math.min(-count, this.particles.length); + + if (typeof(this.willRemoveParticle) == "function") { + for (var i = 0; i < count; ++i) + this.willRemoveParticle(this.particles[i]); + } + + this.particles.splice(0, count); + }, + + complexity: function() + { + return this.particles.length; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg new file mode 100644 index 000000000000..37c4e952c184 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png new file mode 100644 index 000000000000..3f8a187596c4 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/performance100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg new file mode 100644 index 000000000000..5e3f9c1b03d7 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png new file mode 100644 index 000000000000..c2ea55ead77f Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/script100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg new file mode 100644 index 000000000000..edaa84963b33 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png new file mode 100644 index 000000000000..aeb23e0a4026 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/shortcuts100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg new file mode 100644 index 000000000000..ac1e6934d850 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png new file mode 100644 index 000000000000..ff386ff1631f Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/standards100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg new file mode 100644 index 000000000000..c34a9ed255ca --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png new file mode 100644 index 000000000000..bc59d92fcf7a Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/storage100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg new file mode 100644 index 000000000000..f50cff7d6dcb --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png new file mode 100644 index 000000000000..7bc9fffe9cc7 Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/styles100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js new file mode 100644 index 000000000000..2ce24b56f1c8 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/svg-particles.js @@ -0,0 +1,111 @@ +(function() { + +SVGParticle = Utilities.createSubclass(Particle, + function(stage) + { + var shapeId = "#shape-" + Stage.randomInt(1, stage.particleTypeCount); + this.isClipPath = Stage.randomBool(); + if (this.isClipPath) { + this.element = Utilities.createSVGElement("rect", { + x: 0, + y: 0, + "clip-path": "url(" + shapeId + ")" + }, {}, stage.element); + } else { + var shapePath = document.querySelector(shapeId + " path"); + this.element = shapePath.cloneNode(); + stage.element.appendChild(this.element); + } + + this.gradient = document.getElementById("default-gradient").cloneNode(true); + this.gradient.id = "gradient-" + stage.gradientsCounter++; + stage.gradientsDefs.appendChild(this.gradient); + this.element.setAttribute("fill", "url(#" + this.gradient.id + ")"); + + Particle.call(this, stage); + }, { + + sizeMinimum: 30, + sizeRange: 40, + + reset: function() + { + Particle.prototype.reset.call(this); + + this.position = Stage.randomElementInArray(this.stage.emitLocation); + + var velocityMagnitude = Stage.random(.5, 2.5); + var angle = Stage.randomInt(0, this.stage.emitSteps) / this.stage.emitSteps * Math.PI * 2 + Stage.dateCounterValue(1000) * this.stage.emissionSpin + velocityMagnitude; + this.velocity = new Point(Math.sin(angle), Math.cos(angle)) + .multiply(velocityMagnitude); + + if (this.isClipPath) { + this.element.setAttribute("width", this.size.x); + this.element.setAttribute("height", this.size.y); + this.transformSuffix = " translate(-" + this.size.center.x + ",-" + this.size.center.y + ")"; + } else + this.transformSuffix = " scale(" + this.size.x + ") translate(-.5,-.5)"; + + this.stage.colorOffset = (this.stage.colorOffset + .5) % 360; + + var transform = this.stage.element.createSVGTransform(); + transform.setRotate(Stage.randomInt(0, 359), 0, 0); + this.gradient.gradientTransform.baseVal.initialize(transform); + + var stops = this.gradient.querySelectorAll("stop"); + stops[0].setAttribute("stop-color", "hsl(" + this.stage.colorOffset + ", 70%, 45%)"); + stops[1].setAttribute("stop-color", "hsl(" + ((this.stage.colorOffset + Stage.randomInt(50,100)) % 360) + ", 70%, 65%)"); + }, + + move: function() + { + this.element.setAttribute("transform", "translate(" + this.position.x + "," + this.position.y + ") " + this.rotater.rotate(Point.zero) + this.transformSuffix); + } +}); + +SVGParticleStage = 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); + + this.particleTypeCount = document.querySelectorAll(".shape").length; + this.gradientsDefs = document.getElementById("gradients"); + this.gradientsCounter = 0; + }, + + createParticle: function() + { + return new SVGParticle(this); + }, + + willRemoveParticle: function(particle) + { + particle.element.remove(); + if (particle.gradient) + particle.gradient.remove(); + } +}); + +SVGParticleBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new SVGParticleStage(), options); + } +); + +window.benchmarkClass = SVGParticleBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js new file mode 100644 index 000000000000..c7ebe464b3c7 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/text.js @@ -0,0 +1,116 @@ +(function() { + +var TextStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + + this.testElements = []; + this._offsetIndex = 0; + }, { + + shadowFalloff: new UnitBezier(new Point(0.015, 0.750), new Point(0.755, 0.235)), + shimmerAverage: 0, + shimmerMax: 0.5, + millisecondsPerRotation: 1000 / (.26 * Math.PI * 2), + particleDistanceX: 1.5, + particleDistanceY: .5, + lightnessMin: 13, + lightnessMax: 94, + gradients: [ + [10, 176, 176, 209, 148, 140], + [171, 120, 154, 245, 196, 154], + [224, 99, 99, 71, 134, 148], + [101, 100, 117, 80, 230, 175], + [232, 165, 30, 69, 186, 172] + ], + + initialize: function(benchmark) + { + Stage.prototype.initialize.call(this, benchmark); + + this._template = document.getElementById("template"); + this._offset = this.size.subtract(Point.elementClientSize(this._template)).multiply(.5); + this._template.style.left = this._offset.width + "px"; + this._template.style.top = this._offset.height + "px"; + + this._stepProgress = 0; + }, + + tune: function(count) + { + if (count == 0) + return; + + if (count < 0) { + this._offsetIndex = Math.max(this._offsetIndex + count, 0); + for (var i = this._offsetIndex; i < this.testElements.length; ++i) + this.testElements[i].style.visibility = "hidden"; + + this._stepProgress = 1 / this._offsetIndex; + return; + } + + this._offsetIndex = this._offsetIndex + count; + this._stepProgress = 1 / this._offsetIndex; + + var index = Math.min(this._offsetIndex, this.testElements.length); + for (var i = 0; i < index; ++i) + this.testElements[i].style.visibility = "visible"; + + if (this._offsetIndex <= this.testElements.length) + return; + + for (var i = this.testElements.length; i < this._offsetIndex; ++i) { + var clone = this._template.cloneNode(true); + this.testElements.push(clone); + this.element.insertBefore(clone, this.element.firstChild); + } + }, + + animate: function(timeDelta) { + var angle = Stage.dateCounterValue(this.millisecondsPerRotation); + + var progress = 0; + var stepX = Math.sin(angle) * this.particleDistanceX; + var stepY = Math.cos(angle) * this.particleDistanceY; + var x = -stepX * 3; + var y = -stepY * 3; + var gradient = this.gradients[Math.floor(angle/(Math.PI * 2)) % this.gradients.length]; + var offset = Stage.dateCounterValue(200); + this._template.style.transform = "translate(" + Math.floor(x) + "px," + Math.floor(y) + "px)"; + for (var i = 0; i < this._offsetIndex; ++i) { + var element = this.testElements[i]; + + var colorProgress = this.shadowFalloff.solve(progress); + var shimmer = Math.sin(offset - colorProgress); + colorProgress = Math.max(Math.min(colorProgress + Utilities.lerp(shimmer, this.shimmerAverage, this.shimmerMax), 1), 0); + var r = Math.round(Utilities.lerp(colorProgress, gradient[0], gradient[3])); + var g = Math.round(Utilities.lerp(colorProgress, gradient[1], gradient[4])); + var b = Math.round(Utilities.lerp(colorProgress, gradient[2], gradient[5])); + element.style.color = "rgb(" + r + "," + g + "," + b + ")"; + + x += stepX; + y += stepY; + element.style.transform = "translate(" + Math.floor(x) + "px," + Math.floor(y) + "px)"; + + progress += this._stepProgress; + } + }, + + complexity: function() + { + return 1 + this._offsetIndex; + } +}); + +var TextBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new TextStage(), options); + } +); + +window.benchmarkClass = TextBenchmark; + +}()); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg new file mode 100644 index 000000000000..cd1e8a4e209b --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png new file mode 100644 index 000000000000..b9839f84470b Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/master/resources/timeline100.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html new file mode 100644 index 000000000000..46a19369da9d --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/svg-particles.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html b/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html new file mode 100644 index 000000000000..5e94b8ce952b --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/master/text.html @@ -0,0 +1,82 @@ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
σχέδιο设计suunnittelu
designдизайнتصميم
디자인conceptionデザイン
konstruktionעיצובdiseño
+
+
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js new file mode 100644 index 000000000000..b9776d571e3b --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/main.js @@ -0,0 +1,934 @@ +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; + } +}); + +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"]; + // Default data series: timestamp, complexity, estimatedFrameLength + var sampleSize = options["sample-capacity"] || (60 * options["test-interval"] / 1000); + this._sampler = new Sampler(options["series-count"] || 3, 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(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; + }, + + _measureAndResetInterval: function(currentTimestamp) + { + var sampleCount = this._sampler.sampleCount; + var averageFrameLength = 0; + + if (this._intervalEndTimestamp) { + var intervalStartTimestamp = this._sampler.samples[0][this._intervalStartIndex]; + averageFrameLength = (currentTimestamp - intervalStartTimestamp) / (sampleCount - this._intervalStartIndex); + } + + this._intervalStartIndex = sampleCount; + this._intervalEndTimestamp = currentTimestamp + this.intervalSamplingLength; + + return averageFrameLength; + }, + + update: function(timestamp, stage) + { + 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; + } + } else if (timestamp >= this._intervalEndTimestamp) { + var intervalStartTimestamp = this._sampler.samples[0][this._intervalStartIndex]; + intervalAverageFrameLength = this._measureAndResetInterval(timestamp); + if (this._isFrameLengthEstimatorEnabled) { + this._frameLengthEstimator.sample(intervalAverageFrameLength); + frameLengthEstimate = this._frameLengthEstimator.estimate; + } + didFinishInterval = true; + this.didFinishInterval(timestamp, stage, intervalAverageFrameLength); + } + + this._sampler.record(timestamp, stage.complexity(), frameLengthEstimate); + this.tune(timestamp, stage, lastFrameLength, didFinishInterval, intervalAverageFrameLength); + }, + + 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, complexityAverageSamples) + { + complexityAverageSamples.addField(Strings.json.complexity, 0); + complexityAverageSamples.addField(Strings.json.frameLength, 1); + complexityAverageSamples.addField(Strings.json.measurements.stdev, 2); + + complexitySamples.sort(function(a, b) { + return complexitySamples.getFieldInDatum(a, Strings.json.complexity) - complexitySamples.getFieldInDatum(b, Strings.json.complexity); + }); + + // Samples averaged based on complexity + var currentComplexity = -1; + var experimentAtComplexity; + function addSample() { + var mean = experimentAtComplexity.mean(); + var stdev = experimentAtComplexity.standardDeviation(); + + var averageSample = complexityAverageSamples.createDatum(); + complexityAverageSamples.push(averageSample); + complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.complexity, currentComplexity); + complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.frameLength, mean); + complexityAverageSamples.setFieldInDatum(averageSample, Strings.json.measurements.stdev, stdev); + } + complexitySamples.forEach(function(sample) { + var sampleComplexity = complexitySamples.getFieldInDatum(sample, Strings.json.complexity); + if (sampleComplexity != currentComplexity) { + if (currentComplexity > -1) + addSample(); + + currentComplexity = sampleComplexity; + experimentAtComplexity = new Experiment; + } + experimentAtComplexity.sample(complexitySamples.getFieldInDatum(sample, Strings.json.frameLength)); + }); + // Finish off the last one + addSample(); + }, + + processSamples: function(results) + { + var complexityExperiment = new Experiment; + var smoothedFrameLengthExperiment = new Experiment; + + var samples = this._sampler.samples; + + for (var markName in this._marks) + this._marks[markName].time -= this._startTimestamp; + results[Strings.json.marks] = this._marks; + + results[Strings.json.samples] = {}; + + var controllerSamples = new SampleData; + results[Strings.json.samples][Strings.json.controller] = controllerSamples; + + controllerSamples.addField(Strings.json.time, 0); + controllerSamples.addField(Strings.json.complexity, 1); + controllerSamples.addField(Strings.json.frameLength, 2); + controllerSamples.addField(Strings.json.smoothedFrameLength, 3); + + var complexitySamples = new SampleData(controllerSamples.fieldMap); + results[Strings.json.samples][Strings.json.complexity] = complexitySamples; + + samples[0].forEach(function(timestamp, i) { + var sample = controllerSamples.createDatum(); + controllerSamples.push(sample); + complexitySamples.push(sample); + + // Represent time in milliseconds + controllerSamples.setFieldInDatum(sample, Strings.json.time, timestamp - this._startTimestamp); + controllerSamples.setFieldInDatum(sample, Strings.json.complexity, samples[1][i]); + + if (i == 0) + controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, 1000/60); + else + controllerSamples.setFieldInDatum(sample, Strings.json.frameLength, timestamp - samples[0][i - 1]); + + if (samples[2][i] != -1) + controllerSamples.setFieldInDatum(sample, Strings.json.smoothedFrameLength, samples[2][i]); + }, this); + + var complexityAverageSamples = new SampleData; + results[Strings.json.samples][Strings.json.complexityAverage] = complexityAverageSamples; + this._processComplexitySamples(complexitySamples, complexityAverageSamples); + } +}); + +FixedController = Utilities.createSubclass(Controller, + function(benchmark, options) + { + Controller.call(this, benchmark, options); + this.initialComplexity = options["complexity"]; + this.intervalSamplingLength = 0; + } +); + +StepController = Utilities.createSubclass(Controller, + function(benchmark, options) + { + Controller.call(this, benchmark, options); + this.initialComplexity = options["complexity"]; + this.intervalSamplingLength = 0; + this._stepped = false; + this._stepTime = options["test-interval"] / 2; + }, { + + start: function(startTimestamp, stage) + { + Controller.prototype.start.call(this, startTimestamp, stage); + this._stepTime += startTimestamp; + }, + + tune: function(timestamp, stage) + { + if (this._stepped || timestamp < this._stepTime) + return; + + this.mark(Strings.json.samplingEndTimeOffset, timestamp); + this._stepped = true; + stage.tune(stage.complexity() * 3); + } +}); + +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 60 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(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(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(timestamp, stage.complexity(), this._frameLengthEstimator.estimate); + + // Start the next interval. + this._intervalFrameCount = 0; + this._intervalTimestamp = timestamp; + } +}); + +RampController = Utilities.createSubclass(Controller, + function(benchmark, options) + { + // The tier warmup takes at most 5 seconds + options["sample-capacity"] = (options["test-interval"] / 1000 + 5) * 60; + 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; + + // 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; + }, { + + // 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, + + rampWarmupLength: 200, + + // Used for regression calculations in the ramps + frameLengthDesired: 1000/60, + // Add some tolerance; frame lengths shorter than this are considered to be @ the desired frame length + frameLengthDesiredThreshold: 1000/58, + // During tier sampling get at least this slow to find the right complexity range + frameLengthTierThreshold: 1000/30, + // Try to make each ramp get this slow so that we can cross the break point + frameLengthRampLowerThreshold: 1000/45, + // Do not let the regression calculation at the maximum complexity of a ramp get slower than this threshold + frameLengthRampUpperThreshold: 1000/20, + + start: function(startTimestamp, stage) + { + Controller.prototype.start.call(this, startTimestamp, stage); + this._rampStartTimestamp = 0; + this.intervalSamplingLength = 100; + }, + + didFinishInterval: function(timestamp, stage, intervalAverageFrameLength) + { + 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 isAnimatingAt60FPS = currentFrameLength < this.frameLengthDesiredThreshold; + var hasFinishedSlowTierTest = timestamp > this._tierStartTimestamp + this.tierSlowTestLength; + + if (!isAnimatingAt60FPS && !hasFinishedSlowTierTest) + return; + + // We're measuring at 60 fps, so quickly move on to the next tier, or + // we've slower than 60 fps, but we've let this tier run long enough to + // get an estimate + this._lastTierComplexity = currentComplexity; + this._lastTierFrameLength = currentFrameLength; + + this._tier += .5; + var nextTierComplexity = Math.round(Math.pow(10, this._tier)); + 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.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 60 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 60fps 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 regression = new Regression(this._sampler.samples, this._getComplexity, this._getFrameLength, + 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[0][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; + }, + + _getComplexity: function(samples, i) { + return samples[1][i]; + }, + + _getFrameLength: function(samples, i) { + return samples[0][i] - samples[0][i - 1]; + }, + + processSamples: function(results) + { + Controller.prototype.processSamples.call(this, results); + + // 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; + } + + var controllerSamples = results[Strings.json.samples][Strings.json.controller]; + 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)); + }); + + var complexityAverageSamples = new SampleData; + results[Strings.json.samples][Strings.json.complexityAverage] = complexityAverageSamples; + this._processComplexitySamples(complexitySamples, complexityAverageSamples); + } +}); + +Ramp30Controller = Utilities.createSubclass(RampController, + function(benchmark, options) + { + RampController.call(this, benchmark, options); + }, { + + frameLengthDesired: 1000/30, + frameLengthDesiredThreshold: 1000/29, + frameLengthTierThreshold: 1000/20, + frameLengthRampLowerThreshold: 1000/20, + frameLengthRampUpperThreshold: 1000/12 +}); + +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._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 "step": + this._controller = new StepController(this, options); + break; + case "adaptive": + this._controller = new AdaptiveController(this, options); + break; + case "ramp": + this._controller = new RampController(this, options); + break; + case "ramp30": + this._controller = new Ramp30Controller(this, options); + } + }, { + + get stage() + { + return this._stage; + }, + + get timestamp() + { + return this._currentTimestamp - this._startTimestamp; + }, + + 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; + else if (timestamp - this._previousTimestamp >= 100) { + this._didWarmUp = true; + this._startTimestamp = timestamp; + this._controller.start(timestamp, this._stage); + this._previousTimestamp = timestamp; + } + + this._stage.animate(0); + 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/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js new file mode 100644 index 000000000000..9c2706e2a3b9 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/math.js @@ -0,0 +1,268 @@ +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/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css new file mode 100644 index 000000000000..0b6ffdc4a21c --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/stage.css @@ -0,0 +1,27 @@ +html { + height: 100%; +} +body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + background-color: rgb(241, 241, 241); + font-family: "Helvetica Neue", Helvetica, Verdana, sans-serif; +} + +#stage { + position: relative; + width: 100%; + height: 100%; + background-color: rgb(241, 241, 241); + overflow: hidden; +} + +#center-text { + position: absolute; + z-index: 3; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg new file mode 100644 index 000000000000..3c46ae041972 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/star.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png new file mode 100644 index 000000000000..3162f6ec003c Binary files /dev/null and b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.png differ diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg new file mode 100644 index 000000000000..4412626774d4 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/resources/yin-yang.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js new file mode 100644 index 000000000000..cda985b2215f --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas-paths.js @@ -0,0 +1,453 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js new file mode 100644 index 000000000000..483d535d755e --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/simple-canvas.js @@ -0,0 +1,35 @@ +Utilities.extendObject(SimpleCanvasStage.prototype, { + tune: function(count) + { + if (count == 0) + return; + + if (count < 0) { + this.offsetIndex = Math.max(this.offsetIndex + count, 0); + return; + } + + this.offsetIndex = this.offsetIndex + count; + if (this.offsetIndex > this.objects.length) { + // For some tests, it may be easier to see how well the test is going + // by limiting the range of coordinates in which new objects can reside + var coordinateMaximumFactor = Math.min(this.objects.length, Math.min(this.size.x, this.size.y)) / Math.min(this.size.x, this.size.y); + var newIndex = this.offsetIndex - this.objects.length; + for (var i = 0; i < newIndex; ++i) + this.objects.push(new this._canvasObject(this, coordinateMaximumFactor)); + } + }, + + animate: function() + { + var context = this.context; + context.clearRect(0, 0, this.size.x, this.size.y); + for (var i = 0, length = this.offsetIndex; i < length; ++i) + this.objects[i].draw(context); + }, + + complexity: function() + { + return this.offsetIndex; + } +}); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js new file mode 100644 index 000000000000..f5d02b68a43f --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/resources/tiled-canvas-image.js @@ -0,0 +1,119 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html new file mode 100644 index 000000000000..5bb69bc54f70 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/simple-canvas-paths.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html new file mode 100644 index 000000000000..c7c0fef77402 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/simple/tiled-canvas-image.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js new file mode 100644 index 000000000000..b74984c010c9 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-canvas.js @@ -0,0 +1,89 @@ +(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/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js new file mode 100644 index 000000000000..cdaa814af010 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-css.js @@ -0,0 +1,46 @@ +(function() { + +TemplateCssStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + + // Do initialization here. + }, + + 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. You + // may need to define your object so it keeps its animation data. + // This object should encapsulate a corrosponding HTMLElement. + // You may also define a method called animate() in this object + // and just call this function here for all the elements. + + // Loop through all your objects and ask them to animate. + } +}); + +TemplateCssBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new TemplateCssStage(), options); + } +); + +window.benchmarkClass = TemplateCssBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js new file mode 100644 index 000000000000..8fee9c34784a --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/resources/template-svg.js @@ -0,0 +1,46 @@ +(function() { + +TemplateSvgStage = Utilities.createSubclass(Stage, + function() + { + Stage.call(this); + }, { + + initialize: function(benchmark, options) + { + Stage.prototype.initialize.call(this, benchmark, options); + + // Do initialization here. + }, + + 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. + + // TODO: Change objects in the stage. + }, + + animate: function(timeDelta) + { + // Animate the elements such that all of them are redrawn. You + // may need to define your object so it keeps its animation data. + // This object should encapsulate a corrosponding SVGElement. + // You may also define a method called animate() in this object + // and just call this function here for all the elements. + + // TODO: Loop through all your objects and ask them to animate. + } +}); + +TemplateSvgBenchmark = Utilities.createSubclass(Benchmark, + function(options) + { + Benchmark.call(this, new TemplateSvgStage(), options); + } +); + +window.benchmarkClass = TemplateSvgBenchmark; + +})(); diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html new file mode 100644 index 000000000000..dcb7f52861bb --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-canvas.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html new file mode 100644 index 000000000000..70eb214e9505 --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-css.html @@ -0,0 +1,16 @@ + + + + + + + +
+ + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html new file mode 100644 index 000000000000..7a14fc45d68d --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/tests/template/template-svg.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/MotionMark/version b/third_party/webkit/PerformanceTests/MotionMark/version new file mode 100644 index 000000000000..241f47c42dbb --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/version @@ -0,0 +1,2 @@ +1.0 +r205655+ \ No newline at end of file diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm index e0a566914b0d..cfafeffa0315 100644 --- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm +++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm @@ -28,8 +28,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Downloads", "resource://gre/modules/Downloads.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore", "resource://gre/modules/DownloadStore.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "DownloadImport", - "resource://gre/modules/DownloadImport.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper", "resource://gre/modules/DownloadUIHelper.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",