From bd405ecc4aabce1b157331bdc00d2b3525988d9b Mon Sep 17 00:00:00 2001 From: griffpatch Date: Sat, 28 Jan 2017 16:43:37 +0000 Subject: [PATCH 1/5] Optimisation - Only check browser compatability once This saves doing the checks everytime the time functions are referenced --- src/util/timer.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/util/timer.js b/src/util/timer.js index 17c66a567..a0b620112 100644 --- a/src/util/timer.js +++ b/src/util/timer.js @@ -27,13 +27,12 @@ Timer.prototype.startTime = 0; * Return the currently known absolute time, in ms precision. * @returns {number} ms elapsed since 1 January 1970 00:00:00 UTC. */ -Timer.prototype.time = function () { - if (Date.now) { +Timer.prototype.time = Date.now ? + function () { return Date.now(); - } else { + } : function () { return new Date().getTime(); - } -}; + }; /** * Returns a time accurate relative to other times produced by this function. @@ -42,14 +41,13 @@ Timer.prototype.time = function () { * Not guaranteed to produce the same absolute values per-system. * @returns {number} ms-scale accurate time relative to other relative times. */ -Timer.prototype.relativeTime = function () { - if (typeof self !== 'undefined' && - self.performance && 'now' in self.performance) { - return self.performance.now(); - } else { - return this.time(); - } -}; +Timer.prototype.relativeTime = + (typeof self !== 'undefined' && self.performance && 'now' in self.performance) ? + function () { + return self.performance.now(); + } : function () { + return this.time(); + }; /** * Start a timer for measuring elapsed time, From 30cdef57822b148b16f7ac522728c34271524baf Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 3 Feb 2017 15:13:39 +0000 Subject: [PATCH 2/5] chore(package): update webpack-dev-server to version 2.3.0 https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17baf3138..0b7410140 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,6 @@ "tap": "10.0.2", "travis-after-all": "1.4.4", "webpack": "2.2.1", - "webpack-dev-server": "1.16.3" + "webpack-dev-server": "2.3.0" } } From 7d69ecc00595c936efee2561ea73bd1dfcf07395 Mon Sep 17 00:00:00 2001 From: griffpatch Date: Wed, 8 Feb 2017 08:11:10 +0000 Subject: [PATCH 3/5] Optimisation - Only check browser compatability once Disable use of more accurate timer temporarilly due to performance. However, with the rearrange and introduction of the 'nowObj' it turns out most of the delay is in resolving 'self.performance'... so keeping this cached in nowObj actually mitigates most of the delay. --- src/util/timer.js | 50 +++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/util/timer.js b/src/util/timer.js index a0b620112..9a60e5688 100644 --- a/src/util/timer.js +++ b/src/util/timer.js @@ -23,16 +23,36 @@ var Timer = function () {}; */ Timer.prototype.startTime = 0; +/** + * Disable use of self.performance for now as it results in lower performance + * However, instancing it like below (caching the self.performance to a local variable) negates most of the issues. + * @type {boolean} + */ +var USE_PERFORMANCE = false; + +/** + * Legacy object to allow for us to call now to get the old style date time (for backwards compatibility) + * @deprecated This is only called via the nowObj.now() if no other means is possible... + */ +var legacyDateCode = { + now: function () { + return new Date().getTime(); + } +}; + +/** + * Use this object to route all time functions through single access points. + */ +var nowObj = (USE_PERFORMANCE && typeof self !== 'undefined' && self.performance && 'now' in self.performance) ? + self.performance : Date.now ? Date : legacyDateCode; + /** * Return the currently known absolute time, in ms precision. * @returns {number} ms elapsed since 1 January 1970 00:00:00 UTC. */ -Timer.prototype.time = Date.now ? - function () { - return Date.now(); - } : function () { - return new Date().getTime(); - }; +Timer.prototype.time = function () { + return nowObj.now(); +}; /** * Returns a time accurate relative to other times produced by this function. @@ -41,28 +61,20 @@ Timer.prototype.time = Date.now ? * Not guaranteed to produce the same absolute values per-system. * @returns {number} ms-scale accurate time relative to other relative times. */ -Timer.prototype.relativeTime = - (typeof self !== 'undefined' && self.performance && 'now' in self.performance) ? - function () { - return self.performance.now(); - } : function () { - return this.time(); - }; +Timer.prototype.relativeTime = function () { + return nowObj.now(); +}; /** * Start a timer for measuring elapsed time, * at the most accurate precision possible. */ Timer.prototype.start = function () { - this.startTime = this.relativeTime(); + this.startTime = nowObj.now(); }; -/** - * Check time elapsed since `timer.start` was called. - * @returns {number} Time elapsed, in ms (possibly sub-ms precision). - */ Timer.prototype.timeElapsed = function () { - return this.relativeTime() - this.startTime; + return nowObj.now() - this.startTime; }; module.exports = Timer; From 9cb595312e4a03502bdd3dbb191727a286070c33 Mon Sep 17 00:00:00 2001 From: griffpatch Date: Wed, 8 Feb 2017 09:44:10 +0000 Subject: [PATCH 4/5] Implement "Stop this script" function Existing implementation incorrectly terminates the entire thread. See: http://llk.github.io/scratch-vm/#144142535 --- src/blocks/scratch3_control.js | 2 +- src/engine/execute.js | 4 ++-- src/engine/thread.js | 21 +++++++++++++++++++++ test/unit/blocks_control.js | 8 ++++---- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/blocks/scratch3_control.js b/src/blocks/scratch3_control.js index 28737b361..285b241ab 100644 --- a/src/blocks/scratch3_control.js +++ b/src/blocks/scratch3_control.js @@ -110,7 +110,7 @@ Scratch3ControlBlocks.prototype.stop = function (args, util) { option === 'other scripts in stage') { util.stopOtherTargetThreads(); } else if (option === 'this script') { - util.stopThread(); + util.stopThisScript(); } }; diff --git a/src/engine/execute.js b/src/engine/execute.js index 44951aba3..226a866a7 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -183,8 +183,8 @@ var execute = function (sequencer, thread) { stopOtherTargetThreads: function () { runtime.stopForTarget(target, thread); }, - stopThread: function () { - sequencer.retireThread(thread); + stopThisScript: function () { + thread.stopThisScript(); }, startProcedure: function (procedureCode) { sequencer.stepToProcedure(thread, procedureCode); diff --git a/src/engine/thread.js b/src/engine/thread.js index 9693b26f1..f093f886e 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -140,6 +140,27 @@ Thread.prototype.popStack = function () { return this.stack.pop(); }; +/** + * Pop back down the stack frame until we hit a procedure call or the stack frame is emptied + */ +Thread.prototype.stopThisScript = function () { + var blockID = this.peekStack(); + while (blockID !== null) { + var block = this.target.blocks.getBlock(blockID); + if (typeof block !== 'undefined' && block.opcode === 'procedures_callnoreturn') { + break; + } + this.popStack(); + blockID = this.peekStack(); + } + + if (this.stack.length === 0) { + // Clean up! + this.requestScriptGlowInFrame = false; + this.status = Thread.STATUS_DONE; + } +}; + /** * Get top stack item. * @return {?string} Block ID on top of stack. diff --git a/test/unit/blocks_control.js b/test/unit/blocks_control.js index 2dc6049df..7867524ce 100644 --- a/test/unit/blocks_control.js +++ b/test/unit/blocks_control.js @@ -104,7 +104,7 @@ test('stop', function (t) { var state = { stopAll: 0, stopOtherTargetThreads: 0, - stopThread: 0 + stopThisScript: 0 }; var util = { stopAll: function () { @@ -113,8 +113,8 @@ test('stop', function (t) { stopOtherTargetThreads: function () { state.stopOtherTargetThreads++; }, - stopThread: function () { - state.stopThread++; + stopThisScript: function () { + state.stopThisScript++; } }; @@ -125,6 +125,6 @@ test('stop', function (t) { c.stop({STOP_OPTION: 'this script'}, util); t.strictEqual(state.stopAll, 1); t.strictEqual(state.stopOtherTargetThreads, 2); - t.strictEqual(state.stopThread, 1); + t.strictEqual(state.stopThisScript, 1); t.end(); }); From 2ba177aa0f7e69e236c877ae6006ff97d61bdc7a Mon Sep 17 00:00:00 2001 From: griffpatch Date: Thu, 9 Feb 2017 08:50:37 +0000 Subject: [PATCH 5/5] Bug - Return pen opacity to opaque When setting the pen color using pen blocks, the opacity should be reset to fully opaque if no alpha is supplied. --- src/blocks/scratch3_pen.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/blocks/scratch3_pen.js b/src/blocks/scratch3_pen.js index c8f98341e..9b9f64919 100644 --- a/src/blocks/scratch3_pen.js +++ b/src/blocks/scratch3_pen.js @@ -147,6 +147,7 @@ Scratch3PenBlocks.prototype._updatePenColor = function (penState) { penState.penAttributes.color4f[0] = rgb.r / 255.0; penState.penAttributes.color4f[1] = rgb.g / 255.0; penState.penAttributes.color4f[2] = rgb.b / 255.0; + penState.penAttributes.color4f[3] = 1; }; /** @@ -260,6 +261,8 @@ Scratch3PenBlocks.prototype.setPenColorToColor = function (args, util) { penState.penAttributes.color4f[2] = rgb.b / 255.0; if (rgb.hasOwnProperty('a')) { // Will there always be an 'a'? penState.penAttributes.color4f[3] = rgb.a / 255.0; + } else { + penState.penAttributes.color4f[3] = 1; } };