diff --git a/browser/components/sessionstore/src/SessionWorker.js b/browser/components/sessionstore/src/SessionWorker.js index c62464265eed..276d8d7aa51e 100644 --- a/browser/components/sessionstore/src/SessionWorker.js +++ b/browser/components/sessionstore/src/SessionWorker.js @@ -87,7 +87,8 @@ let Agent = { return { result: this.initialState, - telemetry: {FX_SESSION_RESTORE_READ_FILE_MS: durationMs} + telemetry: {FX_SESSION_RESTORE_READ_FILE_MS: durationMs, + FX_SESSION_RESTORE_FILE_SIZE_BYTES: bytes.byteLength} }; } catch (ex if isNoSuchFileEx(ex)) { // Ignore exceptions about non-existent files. diff --git a/browser/components/sessionstore/src/TabState.jsm b/browser/components/sessionstore/src/TabState.jsm index f1448db3616f..3cf7b3bcea8c 100644 --- a/browser/components/sessionstore/src/TabState.jsm +++ b/browser/components/sessionstore/src/TabState.jsm @@ -168,6 +168,11 @@ let TabStateInternal = { // text and scroll data. let history = yield Messenger.send(tab, "SessionStore:collectSessionHistory"); + // The tab could have been closed while waiting for a response. + if (!tab.linkedBrowser) { + return; + } + // Collect basic tab data, without session history and storage. let tabData = this._collectBaseTabData(tab); diff --git a/browser/components/sessionstore/test/content.js b/browser/components/sessionstore/test/content.js index e25a3e792b01..e839d1375651 100644 --- a/browser/components/sessionstore/test/content.js +++ b/browser/components/sessionstore/test/content.js @@ -29,13 +29,13 @@ addMessageListener("ss-test:getStyleSheets", function (msg) { addMessageListener("ss-test:enableStyleSheetsForSet", function (msg) { content.document.enableStyleSheetsForSet(msg.data); - sendSyncMessage("ss-test:enableStyleSheetsForSet"); + sendAsyncMessage("ss-test:enableStyleSheetsForSet"); }); addMessageListener("ss-test:enableSubDocumentStyleSheetsForSet", function (msg) { let iframe = content.document.getElementById(msg.data.id); iframe.contentDocument.enableStyleSheetsForSet(msg.data.set); - sendSyncMessage("ss-test:enableSubDocumentStyleSheetsForSet"); + sendAsyncMessage("ss-test:enableSubDocumentStyleSheetsForSet"); }); addMessageListener("ss-test:getAuthorStyleDisabled", function (msg) { diff --git a/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js b/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js index 2764651aa86b..a3d3dfc50817 100644 --- a/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js +++ b/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js @@ -91,9 +91,6 @@ function testImageTooltip(index) { assertTooltipShownOn(target, () => { let images = markup.tooltip.panel.getElementsByTagName("image"); is(images.length, 1, "Tooltip for [" + TEST_NODES[index] + "] contains an image"); - if (isImg) { - compareImageData(node, images[0].src); - } markup.tooltip.hide(); diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js index a6ce58834a4a..6cca63cfe007 100644 --- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -557,6 +557,17 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, { this.refreshZebra(); }, + /** + * Removes all network requests and closes the sidebar if open. + */ + clear: function() { + NetMonitorView.Sidebar.toggle(false); + $("#details-pane-toggle").disabled = true; + + this.empty(); + this.refreshSummary(); + }, + /** * Predicates used when filtering items. * diff --git a/browser/devtools/netmonitor/netmonitor.xul b/browser/devtools/netmonitor/netmonitor.xul index e984a6c98670..6f508272a6fe 100644 --- a/browser/devtools/netmonitor/netmonitor.xul +++ b/browser/devtools/netmonitor/netmonitor.xul @@ -210,6 +210,11 @@ class="plain requests-menu-footer-label" flex="1" crop="end"/> + diff --git a/browser/devtools/netmonitor/test/browser.ini b/browser/devtools/netmonitor/test/browser.ini index 2b51210b3a11..4bb0b9e47369 100644 --- a/browser/devtools/netmonitor/test/browser.ini +++ b/browser/devtools/netmonitor/test/browser.ini @@ -26,6 +26,7 @@ support-files = [browser_net_accessibility-01.js] [browser_net_accessibility-02.js] [browser_net_autoscroll.js] +[browser_net_clear.js] [browser_net_content-type.js] [browser_net_copy_url.js] [browser_net_cyrillic-01.js] diff --git a/browser/devtools/netmonitor/test/browser_net_clear.js b/browser/devtools/netmonitor/test/browser_net_clear.js new file mode 100644 index 000000000000..a78492cd7b87 --- /dev/null +++ b/browser/devtools/netmonitor/test/browser_net_clear.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the clear button empties the request menu. + */ + +function test() { + initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => { + info("Starting test... "); + + let { document, $, NetMonitorView } = aMonitor.panelWin; + let { RequestsMenu } = NetMonitorView; + let detailsPane = $("#details-pane"); + let detailsPaneToggleButton = $('#details-pane-toggle'); + let clearButton = $('#requests-menu-clear-button'); + + RequestsMenu.lazyUpdate = false; + + // Make sure we start in a sane state + assertNoRequestState(RequestsMenu, detailsPaneToggleButton); + + // Load one request and assert it shows up in the lis + aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.NETWORK_EVENT, () => { + assertSingleRequestState(RequestsMenu, detailsPaneToggleButton); + + // Click clear and make sure the requests are gone + EventUtils.sendMouseEvent({ type: "click" }, clearButton); + assertNoRequestState(RequestsMenu, detailsPaneToggleButton); + + // Load a second request and make sure they still show up + aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.NETWORK_EVENT, () => { + assertSingleRequestState(RequestsMenu, detailsPaneToggleButton); + + // Make sure we can now open the details pane + NetMonitorView.toggleDetailsPane({ visible: true, animated: false }); + ok(!detailsPane.hasAttribute("pane-collapsed") && + !detailsPaneToggleButton.hasAttribute("pane-collapsed"), + "The details pane should be visible after clicking the toggle button."); + + // Click clear and make sure the details pane closes + EventUtils.sendMouseEvent({ type: "click" }, clearButton); + assertNoRequestState(RequestsMenu, detailsPaneToggleButton); + ok(detailsPane.hasAttribute("pane-collapsed") && + detailsPaneToggleButton.hasAttribute("pane-collapsed"), + "The details pane should not be visible clicking 'clear'."); + + teardown(aMonitor).then(finish); + }); + + aDebuggee.location.reload(); + }); + + aDebuggee.location.reload(); + }); + + /** + * Asserts the state of the network monitor when one request has loaded + */ + function assertSingleRequestState(RequestsMenu, detailsPaneToggleButton) { + is(RequestsMenu.itemCount, 1, + "The request menu should have one item at this point."); + is(detailsPaneToggleButton.hasAttribute("disabled"), false, + "The pane toggle button should be enabled after a request is made."); + } + + /** + * Asserts the state of the network monitor when no requests have loaded + */ + function assertNoRequestState(RequestsMenu, detailsPaneToggleButton) { + is(RequestsMenu.itemCount, 0, + "The request menu should be empty at this point."); + is(detailsPaneToggleButton.hasAttribute("disabled"), true, + "The pane toggle button should be disabled when the request menu is cleared."); + } +} diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js index eac788a4cab5..9d3e8a84d273 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js @@ -35,9 +35,6 @@ function runTests() }; let lastMethodCalled = null; - sp.__noSuchMethod__ = function(aMethodName) { - lastMethodCalled = aMethodName; - }; for (let id in methodsAndItems) { lastMethodCalled = null; @@ -46,7 +43,9 @@ function runTests() let oldMethod = sp[methodName]; ok(oldMethod, "found method " + methodName + " in Scratchpad object"); - delete sp[methodName]; + sp[methodName] = () => { + lastMethodCalled = methodName; + } let menu = doc.getElementById(id); ok(menu, "found menuitem #" + id); @@ -64,7 +63,5 @@ function runTests() sp[methodName] = oldMethod; } - delete sp.__noSuchMethod__; - finish(); } diff --git a/browser/devtools/shadereditor/shadereditor.js b/browser/devtools/shadereditor/shadereditor.js index 615e4fd88233..b887c0946fca 100644 --- a/browser/devtools/shadereditor/shadereditor.js +++ b/browser/devtools/shadereditor/shadereditor.js @@ -32,7 +32,7 @@ const EVENTS = { }; const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties" -const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba +const HIGHLIGHT_TINT = [1, 0, 0.25, 1]; // rgba const TYPING_MAX_DELAY = 500; // ms const SHADERS_AUTOGROW_ITEMS = 4; const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px @@ -297,7 +297,7 @@ let ShadersListView = Heritage.extend(WidgetMethods, { _onProgramMouseEnter: function(e) { let sourceItem = this.getItemForElement(e.target, { noSiblings: true }); if (sourceItem && !sourceItem.attachment.isBlackBoxed) { - sourceItem.attachment.programActor.highlight(HIGHLIGHT_COLOR); + sourceItem.attachment.programActor.highlight(HIGHLIGHT_TINT); if (e instanceof Event) { e.preventDefault(); diff --git a/browser/devtools/shadereditor/test/browser.ini b/browser/devtools/shadereditor/test/browser.ini index 7efa1dd6587e..c90e31cd656e 100644 --- a/browser/devtools/shadereditor/test/browser.ini +++ b/browser/devtools/shadereditor/test/browser.ini @@ -1,5 +1,6 @@ [DEFAULT] support-files = + doc_blended-geometry.html doc_multiple-contexts.html doc_overlapping-geometry.html doc_shader-order.html @@ -14,9 +15,11 @@ support-files = [browser_se_editors-lazy-init.js] [browser_se_first-run.js] [browser_se_navigation.js] -[browser_se_programs-blackbox.js] +[browser_se_programs-blackbox-01.js] +[browser_se_programs-blackbox-02.js] [browser_se_programs-cache.js] -[browser_se_programs-highlight.js] +[browser_se_programs-highlight-01.js] +[browser_se_programs-highlight-02.js] [browser_se_programs-list.js] [browser_se_shaders-edit-01.js] [browser_se_shaders-edit-02.js] diff --git a/browser/devtools/shadereditor/test/browser_se_programs-blackbox.js b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-01.js similarity index 95% rename from browser/devtools/shadereditor/test/browser_se_programs-blackbox.js rename to browser/devtools/shadereditor/test/browser_se_programs-blackbox-01.js index e39f8a543943..0e6a3e693af2 100644 --- a/browser/devtools/shadereditor/test/browser_se_programs-blackbox.js +++ b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-01.js @@ -84,7 +84,7 @@ function ifWebGLSupported() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); - ok(true, "Highlighting didn't work while blackboxed (1)."); + ok(true, "Highlighting shouldn't work while blackboxed (1)."); ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) }); ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) }); @@ -93,7 +93,7 @@ function ifWebGLSupported() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); - ok(true, "Highlighting didn't work while blackboxed (2)."); + ok(true, "Highlighting shouldn't work while blackboxed (2)."); ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) }); @@ -101,7 +101,7 @@ function ifWebGLSupported() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); - ok(true, "Highlighting didn't work while blackboxed (3)."); + ok(true, "Highlighting shouldn't work while blackboxed (3)."); getBlackBoxCheckbox(panel, 0).click(); getBlackBoxCheckbox(panel, 1).click(); @@ -133,9 +133,9 @@ function ifWebGLSupported() { ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) }); yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); - yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); ok(true, "The second program was correctly highlighted."); ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) }); diff --git a/browser/devtools/shadereditor/test/browser_se_programs-blackbox-02.js b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-02.js new file mode 100644 index 000000000000..71202aa6f61f --- /dev/null +++ b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-02.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if blackboxing a program works properly in tandem with blended + * overlapping geometry. + */ + +function ifWebGLSupported() { + let [target, debuggee, panel] = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + let firstProgramActor = yield once(gFront, "program-linked"); + let secondProgramActor = yield once(gFront, "program-linked"); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The canvas was correctly drawn."); + + getBlackBoxCheckbox(panel, 0).click(); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 127 }, true); + ok(true, "The first program was correctly blackboxed."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 127, g: 127, b: 127, a: 255 }, true); + ok(true, "The second program was correctly blackboxed."); + + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unblackboxed."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 255 }, true); + ok(true, "The two programs were correctly blackboxed again."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unblackboxed again."); + + yield teardown(panel); + finish(); +} + +function getBlackBoxCheckbox(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-checkbox")[aIndex]; +} + +function once(aTarget, aEvent) { + let deferred = promise.defer(); + aTarget.once(aEvent, deferred.resolve); + return deferred.promise; +} diff --git a/browser/devtools/shadereditor/test/browser_se_programs-highlight.js b/browser/devtools/shadereditor/test/browser_se_programs-highlight-01.js similarity index 95% rename from browser/devtools/shadereditor/test/browser_se_programs-highlight.js rename to browser/devtools/shadereditor/test/browser_se_programs-highlight-01.js index 5e0eb6c35367..6f54f7734bf1 100644 --- a/browser/devtools/shadereditor/test/browser_se_programs-highlight.js +++ b/browser/devtools/shadereditor/test/browser_se_programs-highlight-01.js @@ -47,9 +47,9 @@ function ifWebGLSupported() { ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) }); yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); - yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); ok(true, "The second program was correctly highlighted."); ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) }); diff --git a/browser/devtools/shadereditor/test/browser_se_programs-highlight-02.js b/browser/devtools/shadereditor/test/browser_se_programs-highlight-02.js new file mode 100644 index 000000000000..d5d13464100b --- /dev/null +++ b/browser/devtools/shadereditor/test/browser_se_programs-highlight-02.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if highlighting a program works properly in tandem with blended + * overlapping geometry. + */ + +function ifWebGLSupported() { + let [target, debuggee, panel] = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + let firstProgramActor = yield once(gFront, "program-linked"); + let secondProgramActor = yield once(gFront, "program-linked"); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The canvas was correctly drawn."); + + ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 0) }); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 0, b: 32, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 32, a: 127 }, true); + ok(true, "The first program was correctly highlighted."); + + ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) }); + ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 255, g: 0, b: 64, a: 255 }, true); + ok(true, "The second program was correctly highlighted."); + + ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unhighlighted."); + + yield teardown(panel); + finish(); +} + +function getItemLabel(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-label")[aIndex]; +} + +function once(aTarget, aEvent) { + let deferred = promise.defer(); + aTarget.once(aEvent, deferred.resolve); + return deferred.promise; +} diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js index 5a516b188d8b..024a6ca7c945 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js @@ -19,9 +19,9 @@ function ifWebGLSupported() { yield checkShaderSource("The shader sources are correct before highlighting."); ok(true, "The corner pixel colors are correct before highlighting."); - yield programActor.highlight([0, 0, 1, 1]); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); - yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true); + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); yield checkShaderSource("The shader sources are preserved after highlighting."); ok(true, "The corner pixel colors are correct after highlighting."); diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js index 925fde818140..61bd306054c8 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js @@ -70,9 +70,9 @@ function ifWebGLSupported() { ok(fragSource.contains("vec3 vFragmentColor;"), "The previous correct fragment shader source was preserved."); - yield programActor.highlight([0, 0, 1, 1]); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); - yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true); + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); ok(true, "Highlighting worked after setting a defective fragment source."); yield programActor.unhighlight(); diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js index 070bf6e886e2..f9f4c7f774cc 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js @@ -27,15 +27,18 @@ function ifWebGLSupported() { function testHighlighting(programActor) { return Task.spawn(function() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color was correct before highlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); - yield programActor.highlight([0, 0, 1, 1]); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); - ok(true, "The top left pixel color is correct after highlighting."); + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); yield programActor.unhighlight(); yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color is correct after unhighlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); }); } } diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js index d26e3f3b5bc1..580d91ffecfa 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js @@ -81,15 +81,18 @@ function ifWebGLSupported() { function checkHighlightingInTheFirstPage(programActor) { return Task.spawn(function() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color was correct before highlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); - yield programActor.highlight([0, 0, 1, 1]); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); - ok(true, "The top left pixel color is correct after highlighting."); + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); yield programActor.unhighlight(); yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color is correct after unhighlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); }); } diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js index 96b449d2baf1..6fa445c67760 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js @@ -81,15 +81,18 @@ function ifWebGLSupported() { function checkHighlightingInTheFirstPage(programActor) { return Task.spawn(function() { yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color was correct before highlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); - yield programActor.highlight([0, 0, 1, 1]); - yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); - ok(true, "The top left pixel color is correct after highlighting."); + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); yield programActor.unhighlight(); yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); - ok(true, "The top left pixel color is correct after unhighlighting."); + yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); }); } diff --git a/browser/devtools/shadereditor/test/doc_blended-geometry.html b/browser/devtools/shadereditor/test/doc_blended-geometry.html new file mode 100644 index 000000000000..7137026effe1 --- /dev/null +++ b/browser/devtools/shadereditor/test/doc_blended-geometry.html @@ -0,0 +1,136 @@ + + + + +
+ +Hello world!
+ + diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index 38606ddabbfb..9c2a6f8c3485 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -3074,6 +3074,14 @@ JSTerm.prototype = { */ _autocompleteQuery: null, + /** + * The frameActorId used in the last autocomplete query. Whenever this changes + * the autocomplete cache must be invalidated. + * @private + * @type string + */ + _lastFrameActorId: null, + /** * The Web Console sidebar. * @see this._createSidebar() @@ -4286,6 +4294,8 @@ JSTerm.prototype = { { let inputNode = this.inputNode; let inputValue = inputNode.value; + let frameActor = this.getFrameActor(this.SELECTED_FRAME); + // If the inputNode has no value, then don't try to complete on it. if (!inputValue) { this.clearCompletion(); @@ -4299,7 +4309,7 @@ JSTerm.prototype = { } // Update the completion results. - if (this.lastCompletion.value != inputValue) { + if (this.lastCompletion.value != inputValue || frameActor != this._lastFrameActorId) { this._updateCompletionResult(aType, aCallback); return false; } @@ -4335,7 +4345,8 @@ JSTerm.prototype = { _updateCompletionResult: function JST__updateCompletionResult(aType, aCallback) { - if (this.lastCompletion.value == this.inputNode.value) { + let frameActor = this.getFrameActor(this.SELECTED_FRAME); + if (this.lastCompletion.value == this.inputNode.value && frameActor == this._lastFrameActorId) { return; } @@ -4350,7 +4361,7 @@ JSTerm.prototype = { // character we ask the server again for suggestions. // Check if last character is non-alphanumeric - if (!/[a-zA-Z0-9]$/.test(input)) { + if (!/[a-zA-Z0-9]$/.test(input) || frameActor != this._lastFrameActorId) { this._autocompleteQuery = null; this._autocompleteCache = null; } @@ -4380,6 +4391,8 @@ JSTerm.prototype = { return; } + this._lastFrameActorId = frameActor; + this.lastCompletion = { requestId: requestId, completionType: aType, @@ -4388,7 +4401,8 @@ JSTerm.prototype = { let callback = this._receiveAutocompleteProperties.bind(this, requestId, aCallback); - this.webConsoleClient.autocomplete(input, cursor, callback); + + this.webConsoleClient.autocomplete(input, cursor, callback, frameActor); }, /** diff --git a/browser/extensions/shumway/content/ShumwayStreamConverter.jsm b/browser/extensions/shumway/content/ShumwayStreamConverter.jsm index 5eaab67e0ab6..4e65474b7203 100644 --- a/browser/extensions/shumway/content/ShumwayStreamConverter.jsm +++ b/browser/extensions/shumway/content/ShumwayStreamConverter.jsm @@ -72,7 +72,8 @@ function log(aMsg) { } function getDOMWindow(aChannel) { - var requestor = aChannel.notificationCallbacks; + var requestor = aChannel.notificationCallbacks || + aChannel.loadGroup.notificationCallbacks; var win = requestor.getInterface(Components.interfaces.nsIDOMWindow); return win; } @@ -177,7 +178,10 @@ function isShumwayEnabledFor(actions) { // blacklisting well known sites with issues if (/\.ytimg\.com\//i.test(url) /* youtube movies */ || - /\/vui.swf\b/i.test(url) /* vidyo manager */ ) { + /\/vui.swf\b/i.test(url) /* vidyo manager */ || + /soundcloud\.com\/player\/assets\/swf/i.test(url) /* soundcloud */ || + /sndcdn\.com\/assets\/swf/.test(url) /* soundcloud */ || + /vimeocdn\.com/.test(url) /* vimeo */) { return false; } @@ -727,34 +731,45 @@ ShumwayStreamConverterBase.prototype = { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }, - isValidRequest: function() { - return true; - }, - getUrlHint: function(requestUrl) { return requestUrl.spec; }, createChromeActions: function(window, document, urlHint) { - var url; + var url = urlHint; var baseUrl; var pageUrl; var element = window.frameElement; var isOverlay = false; var objectParams = {}; if (element) { - var tagName = element.nodeName; + // PlayPreview overlay "belongs" to the embed/object tag and consists of + // DIV and IFRAME. Starting from IFRAME and looking for first object tag. + var tagName = element.nodeName, containerElement; while (tagName != 'EMBED' && tagName != 'OBJECT') { // plugin overlay skipping until the target plugin is found isOverlay = true; + containerElement = element; element = element.parentNode; - if (!element) - throw 'Plugin element is not found'; + if (!element) { + throw new Error('Plugin element is not found'); + } tagName = element.nodeName; } - // TODO: remove hack once bug 920927 is fixed - element.style.visibility = 'visible'; + if (isOverlay) { + // Checking if overlay is a proper PlayPreview overlay. + for (var i = 0; i < element.children.length; i++) { + if (element.children[i] === containerElement) { + throw new Error('Plugin element is invalid'); + } + } + } + } + + if (element) { + // Getting absolute URL from the EMBED tag + url = element.srcURI.spec; pageUrl = element.ownerDocument.location.href; // proper page url? @@ -764,7 +779,6 @@ ShumwayStreamConverterBase.prototype = { objectParams[paramName] = element.attributes[i].value; } } else { - url = element.getAttribute('data'); for (var i = 0; i < element.childNodes.length; ++i) { var paramElement = element.childNodes[i]; if (paramElement.nodeType != 1 || @@ -777,7 +791,10 @@ ShumwayStreamConverterBase.prototype = { } } - url = url || objectParams.src || objectParams.movie; + if (!url) { // at this point url shall be known -- asserting + throw new Error('Movie url is not specified'); + } + baseUrl = objectParams.base || pageUrl; var movieParams = {}; @@ -794,9 +811,6 @@ ShumwayStreamConverterBase.prototype = { } } - url = !url ? urlHint : Services.io.newURI(url, null, - baseUrl ? Services.io.newURI(baseUrl, null, null) : null).spec; - var allowScriptAccess = false; switch (objectParams.allowscriptaccess || 'sameDomain') { case 'always': @@ -830,9 +844,6 @@ ShumwayStreamConverterBase.prototype = { // nsIStreamConverter::asyncConvertData asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { - if(!this.isValidRequest(aCtxt)) - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - // Store the listener passed to us this.listener = aListener; }, @@ -847,8 +858,15 @@ ShumwayStreamConverterBase.prototype = { onStartRequest: function(aRequest, aContext) { // Setup the request so we can use it below. aRequest.QueryInterface(Ci.nsIChannel); - // Cancel the request so the viewer can handle it. - aRequest.cancel(Cr.NS_BINDING_ABORTED); + + aRequest.QueryInterface(Ci.nsIWritablePropertyBag); + + // Change the content type so we don't get stuck in a loop. + aRequest.setProperty('contentType', aRequest.contentType); + aRequest.contentType = 'text/html'; + + // TODO For now suspending request, however we can continue fetching data + aRequest.suspend(); var originalURI = aRequest.URI; @@ -857,61 +875,74 @@ ShumwayStreamConverterBase.prototype = { getBoolPref('shumway.simpleMode', false); // Create a new channel that loads the viewer as a resource. - var channel = Services.io.newChannel(isSimpleMode ? + var viewerUrl = isSimpleMode ? 'resource://shumway/web/simple.html' : - 'resource://shumway/web/viewer.html', null, null); + 'resource://shumway/web/viewer.html'; + var channel = Services.io.newChannel(viewerUrl, null, null); var converter = this; var listener = this.listener; // Proxy all the request observer calls, when it gets to onStopRequest // we can get the dom window. var proxy = { - onStartRequest: function() { - listener.onStartRequest.apply(listener, arguments); + onStartRequest: function(request, context) { + listener.onStartRequest(aRequest, context); }, - onDataAvailable: function() { - listener.onDataAvailable.apply(listener, arguments); + onDataAvailable: function(request, context, inputStream, offset, count) { + listener.onDataAvailable(aRequest, context, inputStream, offset, count); }, - onStopRequest: function() { + onStopRequest: function(request, context, statusCode) { + // Cancel the request so the viewer can handle it. + aRequest.resume(); + aRequest.cancel(Cr.NS_BINDING_ABORTED); + var domWindow = getDOMWindow(channel); - if (domWindow.document.documentURIObject.equals(channel.originalURI)) { - // Double check the url is still the correct one. - let actions = converter.createChromeActions(domWindow, - domWindow.document, - converter.getUrlHint(originalURI)); - if (!isShumwayEnabledFor(actions)) { - actions.fallback(true); - return; - } + let actions = converter.createChromeActions(domWindow, + domWindow.document, + converter.getUrlHint(originalURI)); - // Report telemetry on amount of swfs on the page - if (actions.isOverlay) { - // Looking for last actions with same baseUrl - var prevPageActions = ActivationQueue.findLastOnPage(actions.baseUrl); - var pageIndex = !prevPageActions ? 1 : (prevPageActions.telemetry.pageIndex + 1); - actions.telemetry.pageIndex = pageIndex; - ShumwayTelemetry.onPageIndex(pageIndex); - } else { - ShumwayTelemetry.onPageIndex(0); - } - - actions.activationCallback = function(domWindow, isSimpleMode) { - delete this.activationCallback; - activateShumwayScripts(domWindow, isSimpleMode); - }.bind(actions, domWindow, isSimpleMode); - ActivationQueue.enqueue(actions); - - let requestListener = new RequestListener(actions); - domWindow.addEventListener('shumway.message', function(event) { - requestListener.receive(event); - }, false, true); + if (!isShumwayEnabledFor(actions)) { + actions.fallback(true); + return; } - listener.onStopRequest.apply(listener, arguments); + + // Report telemetry on amount of swfs on the page + if (actions.isOverlay) { + // Looking for last actions with same baseUrl + var prevPageActions = ActivationQueue.findLastOnPage(actions.baseUrl); + var pageIndex = !prevPageActions ? 1 : (prevPageActions.telemetry.pageIndex + 1); + actions.telemetry.pageIndex = pageIndex; + ShumwayTelemetry.onPageIndex(pageIndex); + } else { + ShumwayTelemetry.onPageIndex(0); + } + + actions.activationCallback = function(domWindow, isSimpleMode) { + delete this.activationCallback; + activateShumwayScripts(domWindow, isSimpleMode); + }.bind(actions, domWindow, isSimpleMode); + ActivationQueue.enqueue(actions); + + let requestListener = new RequestListener(actions); + domWindow.addEventListener('shumway.message', function(event) { + requestListener.receive(event); + }, false, true); + + listener.onStopRequest(aRequest, context, statusCode); } }; - // XXX? Keep the URL the same so the browser sees it as the same. - // channel.originalURI = aRequest.URI; + // Keep the URL the same so the browser sees it as the same. + channel.originalURI = aRequest.URI; + channel.loadGroup = aRequest.loadGroup; + + // We can use resource principal when data is fetched by the chrome + // e.g. useful for NoScript + var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1'] + .getService(Ci.nsIScriptSecurityManager); + var uri = Services.io.newURI(viewerUrl, null, null); + var resourcePrincipal = securityManager.getNoAppCodebasePrincipal(uri); + aRequest.owner = resourcePrincipal; channel.asyncOpen(proxy, aContext); }, @@ -943,17 +974,6 @@ copyProperties(ShumwayStreamOverlayConverter.prototype, { classDescription: 'Shumway PlayPreview Component', contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*' }); -ShumwayStreamOverlayConverter.prototype.isValidRequest = - (function(aCtxt) { - try { - var request = aCtxt; - request.QueryInterface(Ci.nsIChannel); - var spec = request.URI.spec; - return spec.indexOf(EXPECTED_PLAYPREVIEW_URI_PREFIX) === 0; - } catch (e) { - return false; - } - }); ShumwayStreamOverlayConverter.prototype.getUrlHint = function (requestUrl) { return ''; }; diff --git a/browser/extensions/shumway/content/avm2/generated/avm1lib/avm1lib.abc b/browser/extensions/shumway/content/avm2/generated/avm1lib/avm1lib.abc index 0f9c67914b51..cfa75d6d6ac0 100644 Binary files a/browser/extensions/shumway/content/avm2/generated/avm1lib/avm1lib.abc and b/browser/extensions/shumway/content/avm2/generated/avm1lib/avm1lib.abc differ diff --git a/browser/extensions/shumway/content/avm2/generated/builtin/builtin.abc b/browser/extensions/shumway/content/avm2/generated/builtin/builtin.abc index 28ccc19e9f2b..53a0322aad8d 100644 Binary files a/browser/extensions/shumway/content/avm2/generated/builtin/builtin.abc and b/browser/extensions/shumway/content/avm2/generated/builtin/builtin.abc differ diff --git a/browser/extensions/shumway/content/shumway-worker.js b/browser/extensions/shumway/content/shumway-worker.js index 63af10ea8eec..8fdbf8fbc76a 100644 --- a/browser/extensions/shumway/content/shumway-worker.js +++ b/browser/extensions/shumway/content/shumway-worker.js @@ -156,6 +156,25 @@ throw new Error(msg); } }(this)); +var create = Object.create; +var defineProperty = Object.defineProperty; +var keys = Object.keys; +var isArray = Array.isArray; +var fromCharCode = String.fromCharCode; +var logE = Math.log; +var max = Math.max; +var min = Math.min; +var pow = Math.pow; +var push = Array.prototype.push; +var slice = Array.prototype.slice; +var splice = Array.prototype.splice; +function fail(msg, context) { + throw new Error((context ? context + ': ' : '') + msg); +} +function assert(cond, msg, context) { + if (!cond) + fail(msg, context); +} function scriptProperties(namespace, props) { return props.reduce(function (o, p) { o[p] = namespace + ' ' + p; @@ -168,10 +187,6 @@ function cloneObject(obj) { clone[prop] = obj[prop]; return clone; } -function throwError(name, error) { - var message = formatErrorMessage.apply(null, slice.call(arguments, 1)); - throwErrorFromVM(AVM2.currentDomain(), name, message, error.code); -} function sortByDepth(a, b) { var levelA = a._level; var levelB = b._level; @@ -198,6 +213,89 @@ function sortByDepth(a, b) { function sortNumeric(a, b) { return a - b; } +function rgbaObjToStr(color) { + return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')'; +} +function rgbIntAlphaToStr(color, alpha) { + color |= 0; + if (alpha >= 1) { + var colorStr = color.toString(16); + while (colorStr.length < 6) { + colorStr = '0' + colorStr; + } + return '#' + colorStr; + } + var red = color >> 16 & 255; + var green = color >> 8 & 255; + var blue = color & 255; + return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')'; +} +function argbUintToStr(argb) { + return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')'; +} +(function functionNameSupport() { + if (eval('function t() {} t.name === \'t\'')) { + return; + } + Object.defineProperty(Function.prototype, 'name', { + get: function () { + if (this.__name) { + return this.__name; + } + var m = /function\s([^\(]+)/.exec(this.toString()); + var name = m && m[1] !== 'anonymous' ? m[1] : null; + this.__name = name; + return name; + }, + configurable: true, + enumerable: false + }); +}()); +var randomStyleCache; +var nextStyle = 0; +function randomStyle() { + if (!randomStyleCache) { + randomStyleCache = [ + '#ff5e3a', + '#ff9500', + '#ffdb4c', + '#87fc70', + '#52edc7', + '#1ad6fd', + '#c644fc', + '#ef4db6', + '#4a4a4a', + '#dbddde', + '#ff3b30', + '#ff9500', + '#ffcc00', + '#4cd964', + '#34aadc', + '#007aff', + '#5856d6', + '#ff2d55', + '#8e8e93', + '#c7c7cc', + '#5ad427', + '#c86edf', + '#d1eefc', + '#e0f8d8', + '#fb2b69', + '#f7f7f7', + '#1d77ef', + '#d6cec3', + '#55efcb', + '#ff4981', + '#ffd3e0', + '#f7f7f7', + '#ff1300', + '#1f1f21', + '#bdbec2', + '#ff3a2d' + ]; + } + return randomStyleCache[nextStyle++ % randomStyleCache.length]; +} var Promise = function PromiseClosure() { function isPromise(obj) { return typeof obj === 'object' && obj !== null && typeof obj.then === 'function'; @@ -450,73 +548,6 @@ if (!this.performance) { if (!this.performance.now) { this.performance.now = Date.now; } -var create = Object.create; -var defineProperty = Object.defineProperty; -var keys = Object.keys; -var isArray = Array.isArray; -var fromCharCode = String.fromCharCode; -var logE = Math.log; -var max = Math.max; -var min = Math.min; -var pow = Math.pow; -var push = Array.prototype.push; -var slice = Array.prototype.slice; -var splice = Array.prototype.splice; -function fail(msg, context) { - throw new Error((context ? context + ': ' : '') + msg); -} -function assert(cond, msg, context) { - if (!cond) - fail(msg, context); -} -function rgbaObjToStr(color) { - return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')'; -} -function rgbIntAlphaToStr(color, alpha) { - color |= 0; - if (alpha >= 1) { - var colorStr = color.toString(16); - while (colorStr.length < 6) { - colorStr = '0' + colorStr; - } - return '#' + colorStr; - } - var red = color >> 16 & 255; - var green = color >> 8 & 255; - var blue = color & 255; - return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')'; -} -function argbUintToStr(argb) { - return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')'; -} -(function functionNameSupport() { - if (eval('function t() {} t.name === \'t\'')) { - return; - } - Object.defineProperty(Function.prototype, 'name', { - get: function () { - if (this.__name) { - return this.__name; - } - var m = /function\s([^\(]+)/.exec(this.toString()); - var name = m && m[1] !== 'anonymous' ? m[1] : null; - this.__name = name; - return name; - }, - configurable: true, - enumerable: false - }); -}()); -var randomStyleCache; -function randomStyle() { - if (!randomStyleCache) { - randomStyleCache = []; - for (var i = 0; i < 50; i++) { - randomStyleCache.push('#' + ('00000' + (Math.random() * (1 << 24) | 0).toString(16)).slice(-6)); - } - } - return randomStyleCache[Math.random() * randomStyleCache.length | 0]; -} var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74; var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87; var SWF_TAG_CODE_DEFINE_BITS = 6; @@ -1364,7 +1395,7 @@ function applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph) { path.addSegment(commands, data, morphData); } } -function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph) { +function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) { var isMorph = recordsMorph !== null; var styles = { fill0: 0, @@ -1372,8 +1403,8 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, line: 0 }; var segment = null; - var allFillPaths = fillPaths; - var allLinePaths = linePaths; + var allPaths; + var defaultPath; var numRecords = records.length - 1; var x = 0; var y = 0; @@ -1391,10 +1422,17 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); } if (record.hasNewStyles) { + if (!allPaths) { + allPaths = []; + } + push.apply(allPaths, fillPaths); fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies); - push.apply(allFillPaths, fillPaths); + push.apply(allPaths, linePaths); linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies); - push.apply(allLinePaths, linePaths); + if (defaultPath) { + allPaths.push(defaultPath); + defaultPath = null; + } styles = { fill0: 0, fill1: 0, @@ -1438,7 +1476,33 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, } } } else { + if (!segment) { + if (!defaultPath) { + var style = { + color: { + red: 0, + green: 0, + blue: 0, + alpha: 255 + }, + width: 20 + }; + defaultPath = new SegmentedPath(null, processStyle(style, true)); + } + segment = defaultPath.addSegment([], [], isMorph ? [] : null); + segment.commands.push(SHAPE_MOVE_TO); + segment.data.push(x, y); + if (isMorph) { + segment.morphData.push(morphX, morphY); + } + } if (isMorph) { + while (morphRecord && morphRecord.type === 0) { + morphRecord = recordsMorph[j++]; + } + if (!morphRecord) { + morphRecord = record; + } } if (record.isStraight && (!isMorph || morphRecord.isStraight)) { x += record.deltaX | 0; @@ -1488,20 +1552,28 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, } } applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); - push.apply(allFillPaths, allLinePaths); + if (allPaths) { + push.apply(allPaths, fillPaths); + } else { + allPaths = fillPaths; + } + push.apply(allPaths, linePaths); + if (defaultPath) { + allPaths.push(defaultPath); + } var removeCount = 0; - for (i = 0; i < allFillPaths.length; i++) { - path = allFillPaths[i]; + for (i = 0; i < allPaths.length; i++) { + path = allPaths[i]; if (!path.head()) { removeCount++; continue; } - allFillPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph); + allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables); } - allFillPaths.length -= removeCount; - return allFillPaths; + allPaths.length -= removeCount; + return allPaths; } -function segmentedPathToShapePath(path, isMorph) { +function segmentedPathToShapePath(path, isMorph, transferables) { var start = path.head(); var end = start; var finalRoot = null; @@ -1556,7 +1628,7 @@ function segmentedPathToShapePath(path, isMorph) { totalDataLength += current.data.length; current = current.next; } - var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph); + var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables); var allCommands = shape.commands; var allData = shape.data; var allMorphData = shape.morphData; @@ -1564,13 +1636,10 @@ function segmentedPathToShapePath(path, isMorph) { var dataIndex = 0; current = finalRoot; while (current) { - var offset = 0; var commands = current.commands; var data = current.data; var morphData = current.morphData; - if (data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]) { - offset = 1; - } + var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]); for (var i = offset; i < commands.length; i++, commandsIndex++) { allCommands[commandsIndex] = commands[i]; } @@ -1598,7 +1667,7 @@ function processStyle(style, isLineStyle, dictionary, dependencies) { if (isLineStyle) { style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0]; style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0]; - style.miterLimit = style.miterLimitFactor * 2; + style.miterLimit = (style.miterLimitFactor || 1.5) * 2; if (!style.color && style.hasFill) { var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies); style.style = fillStyle.style; @@ -1667,9 +1736,10 @@ function createPathsList(styles, isLineStyle, dictionary, dependencies) { } function defineShape(tag, dictionary) { var dependencies = []; + var transferables = []; var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies); var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies); - var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null); + var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables); if (tag.bboxMorph) { var mbox = tag.bboxMorph; extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin); @@ -1689,9 +1759,16 @@ function defineShape(tag, dictionary) { bboxMorph: tag.bboxMorph, isMorph: tag.isMorph, paths: paths, - require: dependencies.length ? dependencies : null + require: dependencies.length ? dependencies : null, + transferables: transferables }; } +function logShape(paths, bbox) { + var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) { + return path.serialize(); + }).join() + ']}'; + console.log(output); +} function SegmentedPath(fillStyle, lineStyle) { this.fillStyle = fillStyle; this.lineStyle = lineStyle; @@ -1745,7 +1822,7 @@ var SHAPE_WIDE_LINE_TO = 5; var SHAPE_CUBIC_CURVE_TO = 6; var SHAPE_CIRCLE = 7; var SHAPE_ELLIPSE = 8; -function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) { +function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) { this.fillStyle = fillStyle; this.lineStyle = lineStyle; if (commandsCount) { @@ -1758,8 +1835,21 @@ function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) { } this.bounds = null; this.strokeBounds = null; - this.isMorph = isMorph; + this.isMorph = !(!isMorph); this.fullyInitialized = false; + if (inWorker) { + this.buffers = [ + this.commands.buffer, + this.data.buffer + ]; + transferables.push(this.commands.buffer, this.data.buffer); + if (isMorph) { + this.buffers.push(this.morphData.buffer); + transferables.push(this.morphData.buffer); + } + } else { + this.buffers = null; + } } ShapePath.prototype = { moveTo: function (x, y) { @@ -1808,8 +1898,8 @@ ShapePath.prototype = { var formOpen = false; var formOpenX = 0; var formOpenY = 0; - for (var j = 0, k = 0; j < commands.length; j++) { - if (!this.isMorph) { + if (!this.isMorph) { + for (var j = 0, k = 0; j < commands.length; j++) { switch (commands[j]) { case SHAPE_MOVE_TO: formOpen = true; @@ -1874,9 +1964,14 @@ ShapePath.prototype = { } break; default: + if (commands[j] === 0 && j === commands.length - 1) { + break; + } console.warn('Unknown drawing command encountered: ' + commands[j]); } - } else { + } + } else { + for (var j = 0, k = 0; j < commands.length; j++) { switch (commands[j]) { case SHAPE_MOVE_TO: ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio)); @@ -2359,8 +2454,29 @@ ShapePath.prototype = { this.strokeBounds = bounds; } return bounds; + }, + serialize: function () { + var output = '{'; + if (this.fillStyle) { + output += '"fill":' + JSON.stringify(this.fillStyle) + ','; + } + if (this.lineStyle) { + output += '"stroke":' + JSON.stringify(this.lineStyle) + ','; + } + output += '"commands":[' + Array.apply([], this.commands).join() + '],'; + output += '"data":[' + Array.apply([], this.data).join() + ']'; + return output + '}'; } }; +ShapePath.fromPlainObject = function (obj) { + var path = new ShapePath(obj.fill || null, obj.stroke || null); + path.commands = new Uint8Array(obj.commands); + path.data = new Int32Array(obj.data); + if (!inWorker) { + finishShapePath(path); + } + return path; +}; function distanceSq(x1, y1, x2, y2) { var dX = x2 - x1; var dY = y2 - y1; @@ -2578,23 +2694,24 @@ function extendBoundsByY(bounds, y) { function morph(start, end, ratio) { return start + (end - start) * ratio; } -function finishShapePaths(paths, dictionary) { - for (var i = 0; i < paths.length; i++) { - var path = paths[i]; - if (path.fullyInitialized) { - continue; - } - if (!(path instanceof ShapePath)) { - var untypedPath = path; - path = paths[i] = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph); - path.commands = untypedPath.commands; - path.data = untypedPath.data; - path.morphData = untypedPath.morphData; - } - path.fillStyle && initStyle(path.fillStyle, dictionary); - path.lineStyle && initStyle(path.lineStyle, dictionary); - path.fullyInitialized = true; +function finishShapePath(path, dictionary) { + if (path.fullyInitialized) { + return path; } + if (!(path instanceof ShapePath)) { + var untypedPath = path; + path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph); + path.commands = new Uint8Array(untypedPath.buffers[0]); + path.data = new Int32Array(untypedPath.buffers[1]); + if (untypedPath.isMorph) { + path.morphData = new Int32Array(untypedPath.buffers[2]); + } + path.buffers = null; + } + path.fillStyle && initStyle(path.fillStyle, dictionary); + path.lineStyle && initStyle(path.lineStyle, dictionary); + path.fullyInitialized = true; + return path; } var inWorker = typeof window === 'undefined'; var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null; @@ -2610,7 +2727,7 @@ function buildLinearGradientFactory(colorStops) { } return gradient; }; - fn.defaultGradient = defaultGradient; + fn.defaultFillStyle = defaultGradient; return fn; } function buildRadialGradientFactory(focalPoint, colorStops) { @@ -2625,7 +2742,31 @@ function buildRadialGradientFactory(focalPoint, colorStops) { } return gradient; }; - fn.defaultGradient = defaultGradient; + fn.defaultFillStyle = defaultGradient; + return fn; +} +function buildBitmapPatternFactory(img, repeat) { + var defaultPattern = factoryCtx.createPattern(img, repeat); + var cachedTransform, cachedTransformKey; + var fn = function createBitmapPattern(ctx, colorTransform) { + if (!colorTransform.mode) { + return defaultPattern; + } + var key = colorTransform.getTransformFingerprint(); + if (key === cachedTransformKey) { + return cachedTransform; + } + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + colorTransform.setAlpha(ctx, true); + ctx.drawImage(img, 0, 0); + cachedTransform = ctx.createPattern(canvas, repeat); + cachedTransformKey = key; + return cachedTransform; + }; + fn.defaultFillStyle = defaultPattern; return fn; } function initStyle(style, dictionary) { @@ -2662,7 +2803,7 @@ function initStyle(style, dictionary) { case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP: var bitmap = dictionary[style.bitmapId]; var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP; - style.style = factoryCtx.createPattern(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat'); + style.style = buildBitmapPatternFactory(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat'); break; default: fail('invalid fill style', 'shape'); @@ -3120,1143 +3261,407 @@ function defineText(tag, dictionary) { return props; } var $RELEASE = false; -var LoaderDefinition = function () { - var WORKERS_ENABLED = true; - var LOADER_PATH; - var workerScripts; - if (true) { - LOADER_PATH = 'shumway-worker.js'; - } else { - LOADER_PATH = 'flash/display/Loader.js'; - workerScripts = [ - '../../../lib/DataView.js/DataView.js', - '../util.js', - '../../swf/config.js', - '../../swf/util.js', - '../../swf/swf.js', - '../../swf/types.js', - '../../swf/structs.js', - '../../swf/tags.js', - '../../swf/inflate.js', - '../../swf/stream.js', - '../../swf/templates.js', - '../../swf/generator.js', - '../../swf/handlers.js', - '../../swf/parser.js', - '../../swf/bitmap.js', - '../../swf/button.js', - '../../swf/font.js', - '../../swf/image.js', - '../../swf/label.js', - '../../swf/shape.js', - '../../swf/sound.js', - '../../swf/text.js' - ]; +var isWorker = typeof window === 'undefined'; +if (isWorker && !true) { + importScripts.apply(null, [ + '../../lib/DataView.js/DataView.js', + '../flash/util.js', + 'config.js', + 'swf.js', + 'types.js', + 'structs.js', + 'tags.js', + 'inflate.js', + 'stream.js', + 'templates.js', + 'generator.js', + 'handlers.js', + 'parser.js', + 'bitmap.js', + 'button.js', + 'font.js', + 'image.js', + 'label.js', + 'shape.js', + 'sound.js', + 'text.js' + ]); +} +function defineSymbol(swfTag, symbols) { + var symbol; + switch (swfTag.code) { + case SWF_TAG_CODE_DEFINE_BITS: + case SWF_TAG_CODE_DEFINE_BITS_JPEG2: + case SWF_TAG_CODE_DEFINE_BITS_JPEG3: + case SWF_TAG_CODE_DEFINE_BITS_JPEG4: + case SWF_TAG_CODE_JPEG_TABLES: + symbol = defineImage(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS: + case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2: + symbol = defineBitmap(swfTag); + break; + case SWF_TAG_CODE_DEFINE_BUTTON: + case SWF_TAG_CODE_DEFINE_BUTTON2: + symbol = defineButton(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_EDIT_TEXT: + symbol = defineText(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_FONT: + case SWF_TAG_CODE_DEFINE_FONT2: + case SWF_TAG_CODE_DEFINE_FONT3: + case SWF_TAG_CODE_DEFINE_FONT4: + symbol = defineFont(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_MORPH_SHAPE: + case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2: + case SWF_TAG_CODE_DEFINE_SHAPE: + case SWF_TAG_CODE_DEFINE_SHAPE2: + case SWF_TAG_CODE_DEFINE_SHAPE3: + case SWF_TAG_CODE_DEFINE_SHAPE4: + symbol = defineShape(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_SOUND: + symbol = defineSound(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_BINARY_DATA: + symbol = { + type: 'binary', + id: swfTag.id, + data: swfTag.data + }; + break; + case SWF_TAG_CODE_DEFINE_SPRITE: + var depths = {}; + var frame = { + type: 'frame' + }; + var frames = []; + var tags = swfTag.tags; + var frameScripts = null; + var frameIndex = 0; + var soundStream = null; + for (var i = 0, n = tags.length; i < n; i++) { + var tag = tags[i]; + switch (tag.code) { + case SWF_TAG_CODE_DO_ACTION: + if (!frameScripts) + frameScripts = []; + frameScripts.push(frameIndex); + frameScripts.push(tag.actionsData); + break; + case SWF_TAG_CODE_START_SOUND: + var startSounds = frame.startSounds || (frame.startSounds = []); + startSounds.push(tag); + break; + case SWF_TAG_CODE_SOUND_STREAM_HEAD: + try { + soundStream = createSoundStream(tag); + frame.soundStream = soundStream.info; + } catch (e) { + } + break; + case SWF_TAG_CODE_SOUND_STREAM_BLOCK: + if (soundStream) { + frame.soundStreamBlock = soundStream.decode(tag.data); + } + break; + case SWF_TAG_CODE_FRAME_LABEL: + frame.labelName = tag.name; + break; + case SWF_TAG_CODE_PLACE_OBJECT: + case SWF_TAG_CODE_PLACE_OBJECT2: + case SWF_TAG_CODE_PLACE_OBJECT3: + depths[tag.depth] = tag; + break; + case SWF_TAG_CODE_REMOVE_OBJECT: + case SWF_TAG_CODE_REMOVE_OBJECT2: + depths[tag.depth] = null; + break; + case SWF_TAG_CODE_SHOW_FRAME: + frameIndex += tag.repeat; + frame.repeat = tag.repeat; + frame.depths = depths; + frames.push(frame); + depths = {}; + frame = { + type: 'frame' + }; + break; + } } - var isWorker = typeof window === 'undefined'; - function loadFromWorker(loader, request, context) { - var symbols = {}; - var commitData; - if (loader) { - commitData = function (data) { - return loader._commitData(data); - }; - } else { - commitData = function (data) { - self.postMessage(data); - }; - } - function defineSymbol(swfTag) { - var symbol; - switch (swfTag.code) { - case SWF_TAG_CODE_DEFINE_BITS: - case SWF_TAG_CODE_DEFINE_BITS_JPEG2: - case SWF_TAG_CODE_DEFINE_BITS_JPEG3: - case SWF_TAG_CODE_DEFINE_BITS_JPEG4: - case SWF_TAG_CODE_JPEG_TABLES: - symbol = defineImage(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS: - case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2: - symbol = defineBitmap(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_BUTTON: - case SWF_TAG_CODE_DEFINE_BUTTON2: - symbol = defineButton(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_EDIT_TEXT: - symbol = defineText(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_FONT: - case SWF_TAG_CODE_DEFINE_FONT2: - case SWF_TAG_CODE_DEFINE_FONT3: - case SWF_TAG_CODE_DEFINE_FONT4: - symbol = defineFont(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_MORPH_SHAPE: - case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2: - case SWF_TAG_CODE_DEFINE_SHAPE: - case SWF_TAG_CODE_DEFINE_SHAPE2: - case SWF_TAG_CODE_DEFINE_SHAPE3: - case SWF_TAG_CODE_DEFINE_SHAPE4: - symbol = defineShape(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_SOUND: - symbol = defineSound(swfTag, symbols); - break; - case SWF_TAG_CODE_DEFINE_BINARY_DATA: - symbol = { - type: 'binary', - id: swfTag.id, - data: swfTag.data - }; - break; - case SWF_TAG_CODE_DEFINE_SPRITE: - var depths = {}; - var frame = { - type: 'frame' - }; - var frames = []; - var tags = swfTag.tags; - var frameScripts = null; - var frameIndex = 0; - var soundStream = null; - for (var i = 0, n = tags.length; i < n; i++) { - var tag = tags[i]; - switch (tag.code) { - case SWF_TAG_CODE_DO_ACTION: - if (!frameScripts) - frameScripts = []; - frameScripts.push(frameIndex); - frameScripts.push(tag.actionsData); - break; - case SWF_TAG_CODE_START_SOUND: - var startSounds = frame.startSounds || (frame.startSounds = []); - startSounds.push(tag); - break; - case SWF_TAG_CODE_SOUND_STREAM_HEAD: - try { - soundStream = createSoundStream(tag); - frame.soundStream = soundStream.info; - } catch (e) { - } - break; - case SWF_TAG_CODE_SOUND_STREAM_BLOCK: - if (soundStream) { - frame.soundStreamBlock = soundStream.decode(tag.data); - } - break; - case SWF_TAG_CODE_FRAME_LABEL: - frame.labelName = tag.name; - break; - case SWF_TAG_CODE_PLACE_OBJECT: - case SWF_TAG_CODE_PLACE_OBJECT2: - case SWF_TAG_CODE_PLACE_OBJECT3: - depths[tag.depth] = tag; - break; - case SWF_TAG_CODE_REMOVE_OBJECT: - case SWF_TAG_CODE_REMOVE_OBJECT2: - depths[tag.depth] = null; - break; - case SWF_TAG_CODE_SHOW_FRAME: - var repeat = 1; - while (i < n - 1) { - var nextTag = tags[i + 1]; - if (nextTag.code !== SWF_TAG_CODE_SHOW_FRAME) - break; - i++; - repeat++; - } - frameIndex += repeat; - frame.repeat = repeat; - frame.depths = depths; - frames.push(frame); - depths = {}; - frame = { - type: 'frame' - }; - break; - } + symbol = { + type: 'sprite', + id: swfTag.id, + frameCount: swfTag.frameCount, + frames: frames, + frameScripts: frameScripts + }; + break; + case SWF_TAG_CODE_DEFINE_TEXT: + case SWF_TAG_CODE_DEFINE_TEXT2: + symbol = defineLabel(swfTag, symbols); + break; + } + if (!symbol) { + return { + command: 'error', + message: 'unknown symbol type: ' + swfTag.code + }; + } + symbol.isSymbol = true; + symbols[swfTag.id] = symbol; + return symbol; +} +function createParsingContext(commitData) { + var depths = {}; + var symbols = {}; + var frame = { + type: 'frame' + }; + var tagsProcessed = 0; + var soundStream = null; + var lastProgressSent = 0; + return { + onstart: function (result) { + commitData({ + command: 'init', + result: result + }); + }, + onprogress: function (result) { + if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) { + commitData({ + command: 'progress', + result: { + bytesLoaded: result.bytesLoaded, + bytesTotal: result.bytesTotal } - symbol = { - type: 'sprite', - id: swfTag.id, - frameCount: swfTag.frameCount, - frames: frames, - frameScripts: frameScripts - }; - break; - case SWF_TAG_CODE_DEFINE_TEXT: - case SWF_TAG_CODE_DEFINE_TEXT2: - symbol = defineLabel(swfTag, symbols); - break; - } - if (!symbol) { - commitData({ - command: 'error', - message: 'unknown symbol type: ' + swfTag.code - }); - return; - } - symbol.isSymbol = true; - symbols[swfTag.id] = symbol; - commitData(symbol); + }); + lastProgressSent = Date.now(); } - function createParsingContext() { - var depths = {}; - var frame = { + var tags = result.tags; + for (var n = tags.length; tagsProcessed < n; tagsProcessed++) { + var tag = tags[tagsProcessed]; + if ('id' in tag) { + var symbol = defineSymbol(tag, symbols); + commitData(symbol, symbol.transferables); + continue; + } + switch (tag.code) { + case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA: + frame.sceneData = tag; + break; + case SWF_TAG_CODE_DEFINE_SCALING_GRID: + var symbolUpdate = { + isSymbol: true, + id: tag.symbolId, + updates: { + scale9Grid: tag.splitter + } + }; + commitData(symbolUpdate); + break; + case SWF_TAG_CODE_DO_ABC: + case SWF_TAG_CODE_DO_ABC_: + var abcBlocks = frame.abcBlocks; + if (abcBlocks) + abcBlocks.push({ + data: tag.data, + flags: tag.flags + }); + else + frame.abcBlocks = [ + { + data: tag.data, + flags: tag.flags + } + ]; + break; + case SWF_TAG_CODE_DO_ACTION: + var actionBlocks = frame.actionBlocks; + if (actionBlocks) + actionBlocks.push(tag.actionsData); + else + frame.actionBlocks = [ + tag.actionsData + ]; + break; + case SWF_TAG_CODE_DO_INIT_ACTION: + var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []); + initActionBlocks.push({ + spriteId: tag.spriteId, + actionsData: tag.actionsData + }); + break; + case SWF_TAG_CODE_START_SOUND: + var startSounds = frame.startSounds; + if (!startSounds) + frame.startSounds = startSounds = []; + startSounds.push(tag); + break; + case SWF_TAG_CODE_SOUND_STREAM_HEAD: + try { + soundStream = createSoundStream(tag); + frame.soundStream = soundStream.info; + } catch (e) { + } + break; + case SWF_TAG_CODE_SOUND_STREAM_BLOCK: + if (soundStream) { + frame.soundStreamBlock = soundStream.decode(tag.data); + } + break; + case SWF_TAG_CODE_EXPORT_ASSETS: + var exports = frame.exports; + if (exports) + frame.exports = exports.concat(tag.exports); + else + frame.exports = tag.exports.slice(0); + break; + case SWF_TAG_CODE_SYMBOL_CLASS: + var symbolClasses = frame.symbolClasses; + if (symbolClasses) + frame.symbolClasses = symbolClasses.concat(tag.exports); + else + frame.symbolClasses = tag.exports.slice(0); + break; + case SWF_TAG_CODE_FRAME_LABEL: + frame.labelName = tag.name; + break; + case SWF_TAG_CODE_PLACE_OBJECT: + case SWF_TAG_CODE_PLACE_OBJECT2: + case SWF_TAG_CODE_PLACE_OBJECT3: + depths[tag.depth] = tag; + break; + case SWF_TAG_CODE_REMOVE_OBJECT: + case SWF_TAG_CODE_REMOVE_OBJECT2: + depths[tag.depth] = null; + break; + case SWF_TAG_CODE_SET_BACKGROUND_COLOR: + frame.bgcolor = tag.color; + break; + case SWF_TAG_CODE_SHOW_FRAME: + frame.repeat = tag.repeat; + frame.depths = depths; + frame.complete = !(!tag.finalTag); + commitData(frame); + depths = {}; + frame = { type: 'frame' }; - var tagsProcessed = 0; - var soundStream = null; - var lastProgressSent = 0; - return { - onstart: function (result) { - commitData({ - command: 'init', - result: result - }); - }, - onprogress: function (result) { - if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) { - commitData({ - command: 'progress', - result: { - bytesLoaded: result.bytesLoaded, - bytesTotal: result.bytesTotal - } - }); - lastProgressSent = Date.now(); - } - var tags = result.tags; - for (var n = tags.length; tagsProcessed < n; tagsProcessed++) { - var tag = tags[tagsProcessed]; - if ('id' in tag) { - defineSymbol(tag); - continue; - } - switch (tag.code) { - case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA: - frame.sceneData = tag; - break; - case SWF_TAG_CODE_DEFINE_SCALING_GRID: - var symbolUpdate = { - isSymbol: true, - id: tag.symbolId, - updates: { - scale9Grid: tag.splitter - } - }; - commitData(symbolUpdate); - break; - case SWF_TAG_CODE_DO_ABC: - case SWF_TAG_CODE_DO_ABC_: - var abcBlocks = frame.abcBlocks; - if (abcBlocks) - abcBlocks.push({ - data: tag.data, - flags: tag.flags - }); - else - frame.abcBlocks = [ - { - data: tag.data, - flags: tag.flags - } - ]; - break; - case SWF_TAG_CODE_DO_ACTION: - var actionBlocks = frame.actionBlocks; - if (actionBlocks) - actionBlocks.push(tag.actionsData); - else - frame.actionBlocks = [ - tag.actionsData - ]; - break; - case SWF_TAG_CODE_DO_INIT_ACTION: - var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []); - initActionBlocks.push({ - spriteId: tag.spriteId, - actionsData: tag.actionsData - }); - break; - case SWF_TAG_CODE_START_SOUND: - var startSounds = frame.startSounds; - if (!startSounds) - frame.startSounds = startSounds = []; - startSounds.push(tag); - break; - case SWF_TAG_CODE_SOUND_STREAM_HEAD: - try { - soundStream = createSoundStream(tag); - frame.soundStream = soundStream.info; - } catch (e) { - } - break; - case SWF_TAG_CODE_SOUND_STREAM_BLOCK: - if (soundStream) { - frame.soundStreamBlock = soundStream.decode(tag.data); - } - break; - case SWF_TAG_CODE_SYMBOL_CLASS: - var exports = frame.exports; - if (exports) - frame.exports = exports.concat(tag.exports); - else - frame.exports = tag.exports.slice(0); - break; - case SWF_TAG_CODE_FRAME_LABEL: - frame.labelName = tag.name; - break; - case SWF_TAG_CODE_PLACE_OBJECT: - case SWF_TAG_CODE_PLACE_OBJECT2: - case SWF_TAG_CODE_PLACE_OBJECT3: - depths[tag.depth] = tag; - break; - case SWF_TAG_CODE_REMOVE_OBJECT: - case SWF_TAG_CODE_REMOVE_OBJECT2: - depths[tag.depth] = null; - break; - case SWF_TAG_CODE_SET_BACKGROUND_COLOR: - frame.bgcolor = tag.color; - break; - case SWF_TAG_CODE_SHOW_FRAME: - var repeat = 1; - while (tagsProcessed < n) { - var nextTag = tags[tagsProcessed + 1]; - if (!nextTag || nextTag.code !== SWF_TAG_CODE_SHOW_FRAME) - break; - tagsProcessed++; - repeat++; - } - frame.repeat = repeat; - frame.depths = depths; - commitData(frame); - depths = {}; - frame = { - type: 'frame' - }; - break; - } - } - }, - oncomplete: function (result) { - commitData(result); - var stats; - if (typeof result.swfVersion === 'number') { - var bbox = result.bbox; - stats = { - topic: 'parseInfo', - parseTime: result.parseTime, - bytesTotal: result.bytesTotal, - swfVersion: result.swfVersion, - frameRate: result.frameRate, - width: (bbox.xMax - bbox.xMin) / 20, - height: (bbox.yMax - bbox.yMin) / 20, - isAvm2: !(!result.fileAttributes.doAbc) - }; - } - commitData({ - command: 'complete', - stats: stats - }); - } - }; - } - function parseBytes(bytes) { - SWF.parse(bytes, createParsingContext()); - } - if (isWorker || !flash.net.URLRequest.class.isInstanceOf(request)) { - var input = request; - if (input instanceof ArrayBuffer) { - parseBytes(input); - } else if ('subscribe' in input) { - var pipe = SWF.parseAsync(createParsingContext()); - input.subscribe(function (data, progress) { - if (data) { - pipe.push(data, progress); - } else { - pipe.close(); - } - }); - } else if (typeof FileReaderSync !== 'undefined') { - var reader = new FileReaderSync(); - var buffer = reader.readAsArrayBuffer(input); - parseBytes(buffer); - } else { - var reader = new FileReader(); - reader.onload = function () { - parseBytes(this.result); - }; - reader.readAsArrayBuffer(input); + break; } - } else { - var session = FileLoadingService.createSession(); - var pipe = SWF.parseAsync(createParsingContext()); - session.onprogress = function (data, progressState) { - pipe.push(data, progressState); - var data = { - command: 'progress', - result: { - bytesLoaded: progressState.bytesLoaded, - bytesTotal: progressState.bytesTotal - } - }; - loader._commitData(data); - }; - session.onerror = function (error) { - loader._commitData({ - command: 'error', - error: error - }); - }; - session.onopen = function () { - }; - session.onclose = function () { - pipe.close(); - }; - session.open(request._toFileRequest()); } + }, + oncomplete: function (result) { + commitData(result); + var stats; + if (typeof result.swfVersion === 'number') { + var bbox = result.bbox; + stats = { + topic: 'parseInfo', + parseTime: result.parseTime, + bytesTotal: result.bytesTotal, + swfVersion: result.swfVersion, + frameRate: result.frameRate, + width: (bbox.xMax - bbox.xMin) / 20, + height: (bbox.yMax - bbox.yMin) / 20, + isAvm2: !(!result.fileAttributes.doAbc) + }; + } + commitData({ + command: 'complete', + stats: stats + }); } - if (isWorker) { - if (workerScripts) { - importScripts.apply(null, workerScripts); - } - var subscription = null; - self.onmessage = function (evt) { - if (subscription) { - subscription.callback(evt.data.data, evt.data.progress); - } else if (evt.data === 'pipe:') { - subscription = { - subscribe: function (callback) { - this.callback = callback; - } - }; - loadFromWorker(null, subscription); - } else { - loadFromWorker(null, evt.data); - } - }; - return; - } - var head = document.head; - head.insertBefore(document.createElement('style'), head.firstChild); - var style = document.styleSheets[0]; - var def = { - __class__: 'flash.display.Loader', - initialize: function () { - this._contentLoaderInfo = new flash.display.LoaderInfo(); - this._contentLoaderInfo._loader = this; - this._dictionary = {}; - this._displayList = null; - this._timeline = []; - this._lastPromise = null; - this._uncaughtErrorEvents = null; - this._worker = null; - }, - _commitData: function (data) { - switch (data.command) { - case 'init': - this._init(data.result); - break; - case 'progress': - this._updateProgress(data.result); - break; - case 'complete': - var frameConstructed = new Promise(); - avm2.systemDomain.onMessage.register('frameConstructed', function waitForFrame(type) { - if (type === 'frameConstructed') { - frameConstructed.resolve(); - avm2.systemDomain.onMessage.unregister('frameConstructed', waitForFrame); - } - }); - Promise.when(frameConstructed, this._lastPromise).then(function () { - this.contentLoaderInfo._dispatchEvent('complete'); - }.bind(this)); - var stats = data.stats; - if (stats) { - TelemetryService.reportTelemetry(stats); - } - this._worker && this._worker.terminate(); - break; - case 'empty': - this._lastPromise = new Promise(); - this._lastPromise.resolve(); - break; - case 'error': - this.contentLoaderInfo._dispatchEvent('ioError', flash.events.IOErrorEvent); - break; - default: - if (data.id === 0) - break; - if (data.isSymbol) - this._commitSymbol(data); - else if (data.type === 'frame') - this._commitFrame(data); - else if (data.type === 'image') - this._commitImage(data); - break; - } - }, - _updateProgress: function (state) { - var loaderInfo = this.contentLoaderInfo; - loaderInfo._bytesLoaded = state.bytesLoaded || 0; - loaderInfo._bytesTotal = state.bytesTotal || 0; - var event = new flash.events.ProgressEvent('progress', false, false, loaderInfo._bytesLoaded, loaderInfo._bytesTotal); - loaderInfo._dispatchEvent(event); - }, - _buildFrame: function (currentDisplayList, timeline, promiseQueue, frame, frameNum) { - var loader = this; - var dictionary = loader._dictionary; - var displayList = {}; - var depths = []; - var cmds = frame.depths; - if (currentDisplayList) { - var currentDepths = currentDisplayList.depths; - for (var i = 0; i < currentDepths.length; i++) { - var depth = currentDepths[i]; - if (cmds[depth] === null) { - continue; - } - displayList[depth] = currentDisplayList[depth]; - depths.push(depth); - } - } - for (var depth in cmds) { - var cmd = cmds[depth]; - if (!cmd) { - continue; - } - if (cmd.move) { - var oldCmd = cmd; - cmd = cloneObject(currentDisplayList[depth]); - for (var prop in oldCmd) { - var val = oldCmd[prop]; - if (val) { - cmd[prop] = val; - } - } - } - if (cmd.symbolId) { - var itemPromise = dictionary[cmd.symbolId]; - if (itemPromise && !itemPromise.resolved) { - promiseQueue.push(itemPromise); - } - cmd = cloneObject(cmd); - cmd.promise = itemPromise; - } - if (!displayList[depth]) { - depths.push(depth); - } - displayList[depth] = cmd; - } - depths.sort(sortNumeric); - displayList.depths = depths; - var i = frame.repeat; - while (i--) { - timeline.push(displayList); - } - return displayList; - }, - _commitFrame: function (frame) { - var abcBlocks = frame.abcBlocks; - var actionBlocks = frame.actionBlocks; - var initActionBlocks = frame.initActionBlocks; - var exports = frame.exports; - var sceneData = frame.sceneData; - var loader = this; - var dictionary = loader._dictionary; - var loaderInfo = loader.contentLoaderInfo; - var timeline = loader._timeline; - var frameNum = timeline.length + 1; - var framePromise = new Promise(); - var labelName = frame.labelName; - var prevPromise = this._lastPromise; - this._lastPromise = framePromise; - var promiseQueue = [ - prevPromise - ]; - this._displayList = this._buildFrame(this._displayList, timeline, promiseQueue, frame, frameNum); - if (frame.bgcolor) - loaderInfo._backgroundColor = frame.bgcolor; - else if (isNullOrUndefined(loaderInfo._backgroundColor)) - loaderInfo._backgroundColor = { - red: 255, - green: 255, - blue: 255, - alpha: 255 - }; - Promise.when.apply(Promise, promiseQueue).then(function () { - if (abcBlocks && loader._isAvm2Enabled) { - var appDomain = avm2.applicationDomain; - for (var i = 0, n = abcBlocks.length; i < n; i++) { - var abc = new AbcFile(abcBlocks[i].data, 'abc_block_' + i); - if (abcBlocks[i].flags) { - appDomain.loadAbc(abc); - } else { - appDomain.executeAbc(abc); - } - } - } - if (exports && loader._isAvm2Enabled) { - var exportPromises = []; - for (var i = 0, n = exports.length; i < n; i++) { - var asset = exports[i]; - var symbolPromise = dictionary[asset.symbolId]; - if (!symbolPromise) - continue; - symbolPromise.then(function (symbolPromise, className) { - return function symbolPromiseResolved() { - var symbolInfo = symbolPromise.value; - symbolInfo.className = className; - avm2.applicationDomain.getClass(className).setSymbol(symbolInfo.props); - }; - }(symbolPromise, asset.className)); - exportPromises.push(symbolPromise); - } - return Promise.when.apply(Promise, exportPromises); - } - }).then(function () { - var root = loader._content; - var labelMap; - if (!root) { - var parent = loader._parent; - true; - var rootInfo = dictionary[0].value; - var rootClass = avm2.applicationDomain.getClass(rootInfo.className); - root = rootClass.createAsSymbol({ - framesLoaded: timeline.length, - loader: loader, - parent: parent || loader, - index: parent ? 0 : -1, - level: parent ? 0 : -1, - timeline: timeline, - totalFrames: rootInfo.props.totalFrames, - stage: loader._stage - }); - var isRootMovie = parent && parent == loader._stage && loader._stage._children.length === 0; - if (isRootMovie) { - parent._frameRate = loaderInfo._frameRate; - parent._stageHeight = loaderInfo._height; - parent._stageWidth = loaderInfo._width; - parent._root = root; - parent._setup(); - } else { - loader._children.push(root); - } - var labels; - labelMap = root.symbol.labelMap = createEmptyObject(); - if (sceneData) { - var scenes = []; - var startFrame; - var endFrame = root.symbol.totalFrames - 1; - var sd = sceneData.scenes; - var ld = sceneData.labels; - var i = sd.length; - while (i--) { - var s = sd[i]; - startFrame = s.offset; - labels = []; - var j = ld.length; - while (j--) { - var lbl = ld[j]; - if (lbl.frame >= startFrame && lbl.frame <= endFrame) { - labelMap[lbl.name] = lbl.frame + 1; - labels.unshift(new flash.display.FrameLabel(lbl.name, lbl.frame - startFrame + 1)); - } - } - var scene = new flash.display.Scene(s.name, labels, endFrame - startFrame + 1); - scene._startFrame = startFrame + 1; - scene._endFrame = endFrame + 1; - scenes.unshift(scene); - endFrame = startFrame - 1; - } - root.symbol.scenes = scenes; - } else { - labels = []; - if (labelName) { - labelMap[labelName] = frameNum; - labels.push(new flash.display.FrameLabel(labelName, frameNum)); - } - var scene = new flash.display.Scene('Scene 1', labels, root.symbol.totalFrames); - scene._endFrame = root.symbol.totalFrames; - root.symbol.scenes = [ - scene - ]; - } - if (!loader._isAvm2Enabled) { - var avm1Context = loader._avm1Context; - var _root = root; - if (parent && parent !== loader._stage) { - var parentLoader = parent._loader; - while (parentLoader._parent && parentLoader._parent !== loader._stage) { - parentLoader = parentLoader._parent._loader; - } - _root = parentLoader._content; - } - var as2Object = _root._getAS2Object(); - avm1Context.globals.asSetPublicProperty('_root', as2Object); - avm1Context.globals.asSetPublicProperty('_level0', as2Object); - avm1Context.globals.asSetPublicProperty('_level1', as2Object); - var parameters = loader.loaderInfo._parameters; - for (var paramName in parameters) { - if (!(paramName in as2Object)) { - as2Object[paramName] = parameters[paramName]; - } - } - } - rootClass.instanceConstructor.call(root); - loader._content = root; - } else { - root._framesLoaded += frame.repeat; - if (labelName && root._labelMap) { - if (root._labelMap[labelName] === undefined) { - root._labelMap[labelName] = frameNum; - for (var i = 0, n = root.symbol.scenes.length; i < n; i++) { - var scene = root.symbol.scenes[i]; - if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) { - scene.labels.push(new flash.display.FrameLabel(labelName, frameNum - scene._startFrame)); - break; - } - } - } - } - } - if (frame.startSounds) { - root._registerStartSounds(frameNum, frame.startSounds); - } - if (frame.soundStream) { - root._initSoundStream(frame.soundStream); - } - if (frame.soundStreamBlock) { - root._addSoundStreamBlock(frameNum, frame.soundStreamBlock); - } - if (!loader._isAvm2Enabled) { - var avm1Context = loader._avm1Context; - if (initActionBlocks) { - for (var i = 0; i < initActionBlocks.length; i++) { - var spriteId = initActionBlocks[i].spriteId; - var actionsData = initActionBlocks[i].actionsData; - root.addFrameScript(frameNum - 1, function (actionsData, spriteId, state) { - if (state.executed) - return; - state.executed = true; - return executeActions(actionsData, avm1Context, this._getAS2Object(), exports); - }.bind(root, actionsData, spriteId, { - executed: false - })); - } - } - if (actionBlocks) { - for (var i = 0; i < actionBlocks.length; i++) { - var block = actionBlocks[i]; - root.addFrameScript(frameNum - 1, function (block) { - return function () { - return executeActions(block, avm1Context, this._getAS2Object(), exports); - }; - }(block)); - } - } - } - if (frameNum === 1) - loaderInfo._dispatchEvent(new flash.events.Event('init', false, false)); - framePromise.resolve(frame); - }); - }, - _commitImage: function (imageInfo) { - var loader = this; - var imgPromise = this._lastPromise = new Promise(); - var img = new Image(); - imageInfo.props.img = img; - img.onload = function () { - var props = imageInfo.props; - props.parent = loader._parent; - props.stage = loader._stage; - props.skipCopyToCanvas = true; - var Bitmap = avm2.systemDomain.getClass('flash.display.Bitmap'); - var BitmapData = avm2.systemDomain.getClass('flash.display.BitmapData'); - var bitmapData = BitmapData.createAsSymbol(props); - BitmapData.instanceConstructor.call(bitmapData, 0, 0, true, 4294967295); - var image = Bitmap.createAsSymbol(bitmapData); - loader._children.push(image); - Bitmap.instanceConstructor.call(image, bitmapData); - image._parent = loader; - loader._content = image; - imgPromise.resolve(imageInfo); - loader.contentLoaderInfo._dispatchEvent('init'); - }; - img.src = URL.createObjectURL(imageInfo.data); - delete imageInfo.data; - }, - _commitSymbol: function (symbol) { - var dictionary = this._dictionary; - if ('updates' in symbol) { - dictionary[symbol.id].then(function (s) { - for (var i in symbol.updates) { - s.props[i] = symbol.updates[i]; - } - }); - return; - } - var className = 'flash.display.DisplayObject'; - var dependencies = symbol.require; - var promiseQueue = []; - var props = { - symbolId: symbol.id, - loader: this - }; - var symbolPromise = new Promise(); - if (dependencies && dependencies.length) { - for (var i = 0, n = dependencies.length; i < n; i++) { - var dependencyId = dependencies[i]; - var dependencyPromise = dictionary[dependencyId]; - if (dependencyPromise && !dependencyPromise.resolved) - promiseQueue.push(dependencyPromise); - } - } - switch (symbol.type) { - case 'button': - var states = {}; - for (var stateName in symbol.states) { - var characters = []; - var displayList = {}; - var state = symbol.states[stateName]; - var depths = Object.keys(state); - for (var i = 0; i < depths.length; i++) { - var depth = depths[i]; - var cmd = state[depth]; - var characterPromise = dictionary[cmd.symbolId]; - if (characterPromise && !characterPromise.resolved) - promiseQueue.push(characterPromise); - characters.push(characterPromise); - displayList[depth] = Object.create(cmd, { - promise: { - value: characterPromise - } - }); - } - depths.sort(sortNumeric); - displayList.depths = depths; - var statePromise = new Promise(); - statePromise.resolve({ - className: 'flash.display.Sprite', - props: { - loader: this, - timeline: [ - displayList - ] - } - }); - states[stateName] = statePromise; - } - className = 'flash.display.SimpleButton'; - props.states = states; - props.buttonActions = symbol.buttonActions; - break; - case 'font': - var charset = fromCharCode.apply(null, symbol.codes); - if (charset) { - style.insertRule('@font-face{font-family:"' + symbol.uniqueName + '";' + 'src:url(data:font/opentype;base64,' + btoa(symbol.data) + ')' + '}', style.cssRules.length); - if (!/Mozilla\/5.0.*?rv:(\d+).*? Gecko/.test(window.navigator.userAgent)) { - var testDiv = document.createElement('div'); - testDiv.setAttribute('style', 'position: absolute; top: 0; right: 0;visibility: hidden; z-index: -500;font-family:"' + symbol.uniqueName + '";'); - testDiv.textContent = 'font test'; - document.body.appendChild(testDiv); - var fontPromise = new Promise(); - setTimeout(function () { - fontPromise.resolve(); - document.body.removeChild(testDiv); - }, 200); - promiseQueue.push(fontPromise); - } - } - className = 'flash.text.Font'; - props.name = symbol.name; - props.uniqueName = symbol.uniqueName; - props.charset = symbol.charset; - props.bold = symbol.bold; - props.italic = symbol.italic; - props.metrics = symbol.metrics; - this._registerFont(className, props); - break; - case 'image': - var img = new Image(); - var imgPromise = new Promise(); - img.onload = function () { - if (symbol.mask) { - var maskCanvas = document.createElement('canvas'); - maskCanvas.width = symbol.width; - maskCanvas.height = symbol.height; - var maskContext = maskCanvas.getContext('2d'); - maskContext.drawImage(img, 0, 0); - var maskImageData = maskContext.getImageData(0, 0, symbol.width, symbol.height); - var maskImageDataBytes = maskImageData.data; - var symbolMaskBytes = symbol.mask; - var length = maskImageData.width * maskImageData.height; - for (var i = 0, j = 3; i < length; i++, j += 4) { - maskImageDataBytes[j] = symbolMaskBytes[i]; - } - maskContext.putImageData(maskImageData, 0, 0); - props.img = maskCanvas; - } - imgPromise.resolve(); - }; - img.src = URL.createObjectURL(symbol.data); - promiseQueue.push(imgPromise); - className = 'flash.display.Bitmap'; - props.img = img; - props.width = symbol.width; - props.height = symbol.height; - break; - case 'label': - var drawFn = new Function('c,r,ct', symbol.data); - className = 'flash.text.StaticText'; - props.bbox = symbol.bbox; - props.draw = drawFn; - break; - case 'text': - props.bbox = symbol.bbox; - props.html = symbol.html; - if (symbol.type === 'label') { - className = 'flash.text.StaticText'; - } else { - className = 'flash.text.TextField'; - props.tag = symbol.tag; - props.variableName = symbol.variableName; - } - break; - case 'shape': - className = symbol.morph ? 'flash.display.MorphShape' : 'flash.display.Shape'; - props.bbox = symbol.bbox; - props.strokeBbox = symbol.strokeBbox; - props.paths = symbol.paths; - props.dictionary = dictionary; - break; - case 'sound': - if (!symbol.pcm && !PLAY_USING_AUDIO_TAG) { - var decodePromise = new Promise(); - MP3DecoderSession.processAll(symbol.packaged.data, function (props, pcm, id3tags, error) { - props.pcm = pcm || new Uint8Array(0); - decodePromise.resolve(); - if (error) { - console.error('ERROR: ' + error); - } - }.bind(null, props)); - promiseQueue.push(decodePromise); - } - className = 'flash.media.Sound'; - props.sampleRate = symbol.sampleRate; - props.channels = symbol.channels; - props.pcm = symbol.pcm; - props.packaged = symbol.packaged; - break; - case 'binary': - props.data = symbol.data; - break; - case 'sprite': - var displayList = null; - var frameCount = symbol.frameCount; - var labelMap = {}; - var frameNum = 1; - var frames = symbol.frames; - var timeline = []; - var startSoundRegistrations = []; - for (var i = 0, n = frames.length; i < n; i++) { - var frame = frames[i]; - var frameNum = timeline.length + 1; - if (frame.labelName) { - labelMap[frame.labelName] = frameNum; - } - if (frame.startSounds) { - startSoundRegistrations[frameNum] = frame.startSounds; - for (var j = 0; j < frame.startSounds.length; j++) { - var itemPromise = dictionary[frame.startSounds[j].soundId]; - if (itemPromise && !itemPromise.resolved) - promiseQueue.push(itemPromise); - } - } - displayList = this._buildFrame(displayList, timeline, promiseQueue, frame, frameNum); - } - var frameScripts = {}; - if (!this._isAvm2Enabled) { - if (symbol.frameScripts) { - var data = symbol.frameScripts; - for (var i = 0; i < data.length; i += 2) { - var frameNum = data[i] + 1; - var block = data[i + 1]; - var script = function (block, loader) { - return function () { - var avm1Context = loader._avm1Context; - return executeActions(block, avm1Context, this._getAS2Object()); - }; - }(block, this); - if (!frameScripts[frameNum]) - frameScripts[frameNum] = [ - script - ]; - else - frameScripts[frameNum].push(script); - } - } - } - className = 'flash.display.MovieClip'; - props.timeline = timeline; - props.framesLoaded = frameCount; - props.labelMap = labelMap; - props.frameScripts = frameScripts; - props.totalFrames = frameCount; - props.startSoundRegistrations = startSoundRegistrations; - break; - } - dictionary[symbol.id] = symbolPromise; - Promise.when.apply(Promise, promiseQueue).then(function () { - symbolPromise.resolve({ - className: className, - props: props - }); - }); - }, - _registerFont: function (className, props) { - this._vmPromise.then(function () { - var fontClass = avm2.applicationDomain.getClass(className); - var font = fontClass.createAsSymbol(props); - fontClass.instanceConstructor.call(font); - }); - }, - _init: function (info) { - var loader = this; - var loaderInfo = loader.contentLoaderInfo; - loaderInfo._swfVersion = info.swfVersion; - var bbox = info.bbox; - loaderInfo._width = bbox.xMax - bbox.xMin; - loaderInfo._height = bbox.yMax - bbox.yMin; - loaderInfo._frameRate = info.frameRate; - var documentPromise = new Promise(); - var vmPromise = new Promise(); - vmPromise.then(function () { - documentPromise.resolve({ - className: 'flash.display.MovieClip', - props: { - totalFrames: info.frameCount - } - }); - }); - loader._dictionary[0] = documentPromise; - loader._lastPromise = documentPromise; - loader._vmPromise = vmPromise; - loader._isAvm2Enabled = info.fileAttributes.doAbc; - this._setup(); - }, - _load: function (request, checkPolicyFile, applicationDomain, securityDomain, deblockingFilter) { - if (!isWorker && flash.net.URLRequest.class.isInstanceOf(request)) { - this._contentLoaderInfo._url = request._url; - } - if (!isWorker && WORKERS_ENABLED) { - var loader = this; - var worker = loader._worker = new Worker(SHUMWAY_ROOT + LOADER_PATH); - worker.onmessage = function (evt) { - loader._commitData(evt.data); - }; - if (flash.net.URLRequest.class.isInstanceOf(request)) { - var session = FileLoadingService.createSession(); - session.onprogress = function (data, progress) { - worker.postMessage({ - data: data, - progress: progress - }); - }; - session.onerror = function (error) { - loader._commitData({ - command: 'error', - error: error - }); - }; - session.onopen = function () { - worker.postMessage('pipe:'); - }; - session.onclose = function () { - worker.postMessage({ - data: null - }); - }; - session.open(request._toFileRequest()); - } else { - worker.postMessage(request); - } - } else { - loadFromWorker(this, request); - } - }, - _setup: function () { - var loader = this; - var stage = loader._stage; - if (loader._isAvm2Enabled) { - var mouseClass = avm2.systemDomain.getClass('flash.ui.Mouse'); - mouseClass._stage = stage; - loader._vmPromise.resolve(); - return; - } - if (!avm2.loadAVM1) { - loader._vmPromise.reject('AVM1 loader is not found'); - return; - } - var loaded = function () { - var loaderInfo = loader.contentLoaderInfo; - var avm1Context = new AS2Context(loaderInfo._swfVersion); - avm1Context.stage = stage; - loader._avm1Context = avm1Context; - avm1lib.AS2Key.class.$bind(stage); - avm1lib.AS2Mouse.class.$bind(stage); - stage._addEventListener('frameConstructed', avm1Context.flushPendingScripts.bind(avm1Context), false, Number.MAX_VALUE); - loader._vmPromise.resolve(); - }; - if (avm2.isAVM1Loaded) { - loaded(); - } else { - avm2.isAVM1Loaded = true; - avm2.loadAVM1(loaded); - } - }, - get contentLoaderInfo() { - return this._contentLoaderInfo; - }, - get content() { - somewhatImplemented('Loader.content'); - return this._content; - } - }; - def.__glue__ = { - native: { - instance: { - content: Object.getOwnPropertyDescriptor(def, 'content'), - contentLoaderInfo: Object.getOwnPropertyDescriptor(def, 'contentLoaderInfo'), - _getJPEGLoaderContextdeblockingfilter: function (context) { - return 0; - }, - _load: def._load, - _loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) { - def._load(bytes.a); - }, - _unload: function _unload(halt, gc) { - somewhatImplemented('Loader._unload, do we even need to do anything here?'); - }, - _close: function _close() { - somewhatImplemented('Loader._close'); - }, - _getUncaughtErrorEvents: function _getUncaughtErrorEvents() { - somewhatImplemented('Loader._getUncaughtErrorEvents'); - return this._uncaughtErrorEvents; - }, - _setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) { - somewhatImplemented('Loader._setUncaughtErrorEvents'); - this._uncaughtErrorEvents = value; - } - } + }; +} +function parseBytes(bytes, commitData) { + SWF.parse(bytes, createParsingContext(commitData)); +} +function ResourceLoader(scope) { + this.subscription = null; + var self = this; + if (!isWorker) { + this.messenger = { + postMessage: function (data) { + self.onmessage({ + data: data + }); } }; - return def; - }.call(this); + } else { + this.messenger = scope; + scope.onmessage = function (event) { + self.listener(event.data); + }; + } +} +ResourceLoader.prototype = { + terminate: function () { + this.messenger = null; + this.listener = null; + }, + onmessage: function (event) { + this.listener(event.data); + }, + postMessage: function (data) { + this.listener && this.listener(data); + }, + listener: function (data) { + if (this.subscription) { + this.subscription.callback(data.data, data.progress); + } else if (data === 'pipe:') { + this.subscription = { + subscribe: function (callback) { + this.callback = callback; + } + }; + this.parseLoadedData(this.messenger, this.subscription); + } else { + this.parseLoadedData(this.messenger, data); + } + }, + parseLoadedData: function (loader, request, context) { + function commitData(data, transferables) { + try { + loader.postMessage(data, transferables); + } catch (ex) { + if (ex != 'DataCloneError') { + throw ex; + } + loader.postMessage(data); + } + } + if (request instanceof ArrayBuffer) { + parseBytes(request, commitData); + } else if ('subscribe' in request) { + var pipe = SWF.parseAsync(createParsingContext(commitData)); + request.subscribe(function (data, progress) { + if (data) { + pipe.push(data, progress); + } else { + pipe.close(); + } + }); + } else if (typeof FileReaderSync !== 'undefined') { + var reader = new FileReaderSync(); + var buffer = reader.readAsArrayBuffer(request); + parseBytes(buffer, commitData); + } else { + var reader = new FileReader(); + reader.onload = function () { + parseBytes(this.result, commitData); + }; + reader.readAsArrayBuffer(request); + } + } +}; +if (isWorker) { + var loader = new ResourceLoader(this); +} var codeLengthOrder = [ 16, 17, @@ -5226,6 +4631,19 @@ var tagHandler = function (global) { $.data = readBinary($bytes, $stream, 0); return $; } + function exportAssets($bytes, $stream, $, swfVersion, tagCode) { + $ || ($ = {}); + var exportsCount = readUi16($bytes, $stream); + var $0 = $.exports = []; + var $1 = exportsCount; + while ($1--) { + var $2 = {}; + $2.symbolId = readUi16($bytes, $stream); + $2.className = readString($bytes, $stream, 0); + $0.push($2); + } + return $; + } function symbolClass($bytes, $stream, $, swfVersion, tagCode) { $ || ($ = {}); var symbolCount = readUi16($bytes, $stream); @@ -6041,7 +5459,7 @@ var tagHandler = function (global) { 45: soundStreamHead, 46: defineShape, 48: defineFont2, - 56: undefined, + 56: exportAssets, 57: undefined, 58: undefined, 59: doAction, @@ -6095,58 +5513,79 @@ var readHeader = function readHeader($bytes, $stream, $, swfVersion, tagCode) { global['tagHandler'] = tagHandler; global['readHeader'] = readHeader; }(this)); -function readTags(context, stream, swfVersion, onprogress) { +function readTags(context, stream, swfVersion, final, onprogress) { var tags = context.tags; var bytes = stream.bytes; var lastSuccessfulPosition; + var tag = null; + if (context._readTag) { + tag = context._readTag; + delete context._readTag; + } try { - do { + while (stream.pos < stream.end) { lastSuccessfulPosition = stream.pos; stream.ensure(2); var tagCodeAndLength = readUi16(bytes, stream); + if (!tagCodeAndLength) { + final = true; + break; + } var tagCode = tagCodeAndLength >> 6; var length = tagCodeAndLength & 63; if (length === 63) { stream.ensure(4); length = readUi32(bytes, stream); } - stream.ensure(length); - if (tagCode === 0) { - break; + if (tag) { + if (tagCode === 1 && tag.code === 1) { + tag.repeat++; + stream.pos += length; + continue; + } + tags.push(tag); + if (onprogress && tag.id !== undefined) { + onprogress(context); + } + tag = null; } + stream.ensure(length); var substream = stream.substream(stream.pos, stream.pos += length); var subbytes = substream.bytes; - var tag = { + var nextTag = { code: tagCode }; if (tagCode === 39) { - tag.type = 'sprite'; - tag.id = readUi16(subbytes, substream); - tag.frameCount = readUi16(subbytes, substream); - tag.tags = []; - readTags(tag, substream, swfVersion); + nextTag.type = 'sprite'; + nextTag.id = readUi16(subbytes, substream); + nextTag.frameCount = readUi16(subbytes, substream); + nextTag.tags = []; + readTags(nextTag, substream, swfVersion, true); + } else if (tagCode === 1) { + nextTag.repeat = 1; } else { var handler = tagHandler[tagCode]; if (handler) { - handler(subbytes, substream, tag, swfVersion, tagCode); + handler(subbytes, substream, nextTag, swfVersion, tagCode); } } + tag = nextTag; + } + if (tag && final) { + tag.finalTag = true; tags.push(tag); - if (tagCode === 1) { - while (stream.pos + 2 <= stream.end && stream.getUint16(stream.pos, true) >> 6 === 1) { - tags.push(tag); - stream.pos += 2; - } - if (onprogress) - onprogress(context); - } else if (onprogress && tag.id !== undefined) { + if (onprogress) { onprogress(context); } - } while (stream.pos < stream.end); + } else { + context._readTag = tag; + } } catch (e) { - if (e !== StreamNoDataError) + if (e !== StreamNoDataError) { throw e; + } stream.pos = lastSuccessfulPosition; + context._readTag = tag; } } function HeadTailBuffer(defaultSize) { @@ -6295,12 +5734,14 @@ BodyParser.prototype = { buffer.push(data); stream = buffer.createStream(); } + var finalBlock = false; if (progressInfo) { swf.bytesLoaded = progressInfo.bytesLoaded; swf.bytesTotal = progressInfo.bytesTotal; + finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal; } var readStartTime = performance.now(); - readTags(swf, stream, swfVersion, options.onprogress); + readTags(swf, stream, swfVersion, finalBlock, options.onprogress); swf.parseTime += performance.now() - readStartTime; var read = stream.pos; buffer.removeHead(read); diff --git a/browser/extensions/shumway/content/shumway.js b/browser/extensions/shumway/content/shumway.js index ff7281e7f745..0381bb3ca8e9 100644 --- a/browser/extensions/shumway/content/shumway.js +++ b/browser/extensions/shumway/content/shumway.js @@ -244,6 +244,9 @@ } else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') { argument = nonPositionalArgumentMap[argString]; true; + if (!argument) { + continue; + } if (argument.type !== 'boolean') { value = args.shift(); true; @@ -325,6 +328,44 @@ function assert(cond, msg, context) { if (!cond) fail(msg, context); } +function scriptProperties(namespace, props) { + return props.reduce(function (o, p) { + o[p] = namespace + ' ' + p; + return o; + }, {}); +} +function cloneObject(obj) { + var clone = Object.create(null); + for (var prop in obj) + clone[prop] = obj[prop]; + return clone; +} +function sortByDepth(a, b) { + var levelA = a._level; + var levelB = b._level; + if (a._parent !== b._parent && a._index > -1 && b._index > -1) { + while (a._level > levelB) { + a = a._parent; + } + while (b._level > levelA) { + b = b._parent; + } + while (a._level > 1) { + if (a._parent === b._parent) { + break; + } + a = a._parent; + b = b._parent; + } + } + if (a === b) { + return levelA - levelB; + } + return a._index - b._index; +} +function sortNumeric(a, b) { + return a - b; +} function rgbaObjToStr(color) { return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')'; } @@ -364,14 +405,301 @@ function argbUintToStr(argb) { }); }()); var randomStyleCache; +var nextStyle = 0; function randomStyle() { if (!randomStyleCache) { - randomStyleCache = []; - for (var i = 0; i < 50; i++) { - randomStyleCache.push('#' + ('00000' + (Math.random() * (1 << 24) | 0).toString(16)).slice(-6)); + randomStyleCache = [ + '#ff5e3a', + '#ff9500', + '#ffdb4c', + '#87fc70', + '#52edc7', + '#1ad6fd', + '#c644fc', + '#ef4db6', + '#4a4a4a', + '#dbddde', + '#ff3b30', + '#ff9500', + '#ffcc00', + '#4cd964', + '#34aadc', + '#007aff', + '#5856d6', + '#ff2d55', + '#8e8e93', + '#c7c7cc', + '#5ad427', + '#c86edf', + '#d1eefc', + '#e0f8d8', + '#fb2b69', + '#f7f7f7', + '#1d77ef', + '#d6cec3', + '#55efcb', + '#ff4981', + '#ffd3e0', + '#f7f7f7', + '#ff1300', + '#1f1f21', + '#bdbec2', + '#ff3a2d' + ]; + } + return randomStyleCache[nextStyle++ % randomStyleCache.length]; +} +var Promise = function PromiseClosure() { + function isPromise(obj) { + return typeof obj === 'object' && obj !== null && typeof obj.then === 'function'; + } + function defaultOnFulfilled(value) { + return value; + } + function defaultOnRejected(reason) { + throw reason; + } + function propagateFulfilled(subject, value) { + subject.subpromisesValue = value; + var subpromises = subject.subpromises; + if (!subpromises) { + return; + } + for (var i = 0; i < subpromises.length; i++) { + subpromises[i].fulfill(value); + } + delete subject.subpromises; + } + function propagateRejected(subject, reason) { + subject.subpromisesReason = reason; + var subpromises = subject.subpromises; + if (!subpromises) { + if (!true) { + console.warn(reason); + } + return; + } + for (var i = 0; i < subpromises.length; i++) { + subpromises[i].reject(reason); + } + delete subject.subpromises; + } + function performCall(callback, arg, subject) { + try { + var value = callback(arg); + if (isPromise(value)) { + value.then(function Promise_queueCall_onFulfilled(value) { + propagateFulfilled(subject, value); + }, function Promise_queueCall_onRejected(reason) { + propagateRejected(subject, reason); + }); + return; + } + propagateFulfilled(subject, value); + } catch (ex) { + propagateRejected(subject, ex); + } + } + var queue = []; + function processQueue() { + while (queue.length > 0) { + var task = queue[0]; + if (task.directCallback) { + task.callback.call(task.subject, task.arg); + } else { + performCall(task.callback, task.arg, task.subject); + } + queue.shift(); + } + } + function queueCall(callback, arg, subject, directCallback) { + if (queue.length === 0) { + setTimeout(processQueue, 0); + } + queue.push({ + callback: callback, + arg: arg, + subject: subject, + directCallback: directCallback + }); + } + function Promise(onFulfilled, onRejected) { + this.state = 'pending'; + this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : defaultOnFulfilled; + this.onRejected = typeof onRejected === 'function' ? onRejected : defaultOnRejected; + } + Promise.prototype = { + fulfill: function Promise_resolve(value) { + if (this.state !== 'pending') { + return; + } + this.state = 'fulfilled'; + this.value = value; + queueCall(this.onFulfilled, value, this, false); + }, + reject: function Promise_reject(reason) { + if (this.state !== 'pending') { + return; + } + this.state = 'rejected'; + this.reason = reason; + queueCall(this.onRejected, reason, this, false); + }, + then: function Promise_then(onFulfilled, onRejected) { + var promise = new Promise(onFulfilled, onRejected); + if ('subpromisesValue' in this) { + queueCall(promise.fulfill, this.subpromisesValue, promise, true); + } else if ('subpromisesReason' in this) { + queueCall(promise.reject, this.subpromisesReason, promise, true); + } else { + var subpromises = this.subpromises || (this.subpromises = []); + subpromises.push(promise); + } + return promise; + }, + get resolved() { + return this.state === 'fulfilled'; + }, + resolve: function (value) { + this.fulfill(value); + } + }; + Promise.when = function Promise_when() { + var promise = new Promise(); + if (arguments.length === 0) { + promise.resolve(); + return promise; + } + var promises = slice.call(arguments, 0); + var result = []; + var i = 1; + function fulfill(value) { + result.push(value); + if (i < promises.length) { + promises[i++].then(fulfill, reject); + } else { + promise.resolve(result); + } + return value; + } + function reject(reason) { + promise.reject(reason); + } + promises[0].then(fulfill, reject); + return promise; + }; + return Promise; + }(); +var QuadTree = function (x, y, width, height, level) { + this.x = x | 0; + this.y = y | 0; + this.width = width | 0; + this.height = height | 0; + this.level = level | 0; + this.stuckObjects = []; + this.objects = []; + this.nodes = []; +}; +QuadTree.prototype._findIndex = function (xMin, yMin, xMax, yMax) { + var midX = this.x + (this.width / 2 | 0); + var midY = this.y + (this.height / 2 | 0); + var top = yMin < midY && yMax < midY; + var bottom = yMin > midY; + if (xMin < midX && xMax < midX) { + if (top) { + return 1; + } else if (bottom) { + return 2; + } + } else if (xMin > midX) { + if (top) { + return 0; + } else if (bottom) { + return 3; } } - return randomStyleCache[Math.random() * randomStyleCache.length | 0]; + return -1; +}; +QuadTree.prototype.insert = function (obj) { + var nodes = this.nodes; + if (nodes.length) { + var index = this._findIndex(obj.xMin, obj.yMin, obj.xMax, obj.yMax); + if (index > -1) { + nodes[index].insert(obj); + } else { + this.stuckObjects.push(obj); + obj._qtree = this; + } + return; + } + var objects = this.objects; + objects.push(obj); + if (objects.length > 4 && this.level < 10) { + this._subdivide(); + while (objects.length) { + this.insert(objects.shift()); + } + return; + } + obj._qtree = this; +}; +QuadTree.prototype.delete = function (obj) { + if (obj._qtree !== this) { + return; + } + var index = this.objects.indexOf(obj); + if (index > -1) { + this.objects.splice(index, 1); + } else { + index = this.stuckObjects.indexOf(obj); + this.stuckObjects.splice(index, 1); + } + obj._qtree = null; +}; +QuadTree.prototype._stack = []; +QuadTree.prototype._out = []; +QuadTree.prototype.retrieve = function (xMin, yMin, xMax, yMax) { + var stack = this._stack; + var out = this._out; + out.length = 0; + var node = this; + do { + if (node.nodes.length) { + var index = node._findIndex(xMin, yMin, xMax, yMax); + if (index > -1) { + stack.push(node.nodes[index]); + } else { + stack.push.apply(stack, node.nodes); + } + } + out.push.apply(out, node.stuckObjects); + out.push.apply(out, node.objects); + node = stack.pop(); + } while (node); + return out; +}; +QuadTree.prototype._subdivide = function () { + var halfWidth = this.width / 2 | 0; + var halfHeight = this.height / 2 | 0; + var midX = this.x + halfWidth; + var midY = this.y + halfHeight; + var level = this.level + 1; + this.nodes[0] = new QuadTree(midX, this.y, halfWidth, halfHeight, level); + this.nodes[1] = new QuadTree(this.x, this.y, halfWidth, halfHeight, level); + this.nodes[2] = new QuadTree(this.x, midY, halfWidth, halfHeight, level); + this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, level); +}; +var EXTERNAL_INTERFACE_FEATURE = 1; +var CLIPBOARD_FEATURE = 2; +var SHAREDOBJECT_FEATURE = 3; +var VIDEO_FEATURE = 4; +var SOUND_FEATURE = 5; +var NETCONNECTION_FEATURE = 6; +if (!this.performance) { + this.performance = {}; +} +if (!this.performance.now) { + this.performance.now = Date.now; } var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74; var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87; @@ -1517,7 +1845,7 @@ function applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph) { path.addSegment(commands, data, morphData); } } -function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph) { +function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) { var isMorph = recordsMorph !== null; var styles = { fill0: 0, @@ -1525,8 +1853,8 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, line: 0 }; var segment = null; - var allFillPaths = fillPaths; - var allLinePaths = linePaths; + var allPaths; + var defaultPath; var numRecords = records.length - 1; var x = 0; var y = 0; @@ -1544,10 +1872,17 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); } if (record.hasNewStyles) { + if (!allPaths) { + allPaths = []; + } + push.apply(allPaths, fillPaths); fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies); - push.apply(allFillPaths, fillPaths); + push.apply(allPaths, linePaths); linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies); - push.apply(allLinePaths, linePaths); + if (defaultPath) { + allPaths.push(defaultPath); + defaultPath = null; + } styles = { fill0: 0, fill1: 0, @@ -1591,7 +1926,33 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, } } } else { + if (!segment) { + if (!defaultPath) { + var style = { + color: { + red: 0, + green: 0, + blue: 0, + alpha: 255 + }, + width: 20 + }; + defaultPath = new SegmentedPath(null, processStyle(style, true)); + } + segment = defaultPath.addSegment([], [], isMorph ? [] : null); + segment.commands.push(SHAPE_MOVE_TO); + segment.data.push(x, y); + if (isMorph) { + segment.morphData.push(morphX, morphY); + } + } if (isMorph) { + while (morphRecord && morphRecord.type === 0) { + morphRecord = recordsMorph[j++]; + } + if (!morphRecord) { + morphRecord = record; + } } if (record.isStraight && (!isMorph || morphRecord.isStraight)) { x += record.deltaX | 0; @@ -1641,20 +2002,28 @@ function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, } } applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); - push.apply(allFillPaths, allLinePaths); + if (allPaths) { + push.apply(allPaths, fillPaths); + } else { + allPaths = fillPaths; + } + push.apply(allPaths, linePaths); + if (defaultPath) { + allPaths.push(defaultPath); + } var removeCount = 0; - for (i = 0; i < allFillPaths.length; i++) { - path = allFillPaths[i]; + for (i = 0; i < allPaths.length; i++) { + path = allPaths[i]; if (!path.head()) { removeCount++; continue; } - allFillPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph); + allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables); } - allFillPaths.length -= removeCount; - return allFillPaths; + allPaths.length -= removeCount; + return allPaths; } -function segmentedPathToShapePath(path, isMorph) { +function segmentedPathToShapePath(path, isMorph, transferables) { var start = path.head(); var end = start; var finalRoot = null; @@ -1709,7 +2078,7 @@ function segmentedPathToShapePath(path, isMorph) { totalDataLength += current.data.length; current = current.next; } - var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph); + var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables); var allCommands = shape.commands; var allData = shape.data; var allMorphData = shape.morphData; @@ -1717,13 +2086,10 @@ function segmentedPathToShapePath(path, isMorph) { var dataIndex = 0; current = finalRoot; while (current) { - var offset = 0; var commands = current.commands; var data = current.data; var morphData = current.morphData; - if (data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]) { - offset = 1; - } + var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]); for (var i = offset; i < commands.length; i++, commandsIndex++) { allCommands[commandsIndex] = commands[i]; } @@ -1751,7 +2117,7 @@ function processStyle(style, isLineStyle, dictionary, dependencies) { if (isLineStyle) { style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0]; style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0]; - style.miterLimit = style.miterLimitFactor * 2; + style.miterLimit = (style.miterLimitFactor || 1.5) * 2; if (!style.color && style.hasFill) { var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies); style.style = fillStyle.style; @@ -1820,9 +2186,10 @@ function createPathsList(styles, isLineStyle, dictionary, dependencies) { } function defineShape(tag, dictionary) { var dependencies = []; + var transferables = []; var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies); var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies); - var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null); + var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables); if (tag.bboxMorph) { var mbox = tag.bboxMorph; extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin); @@ -1842,9 +2209,16 @@ function defineShape(tag, dictionary) { bboxMorph: tag.bboxMorph, isMorph: tag.isMorph, paths: paths, - require: dependencies.length ? dependencies : null + require: dependencies.length ? dependencies : null, + transferables: transferables }; } +function logShape(paths, bbox) { + var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) { + return path.serialize(); + }).join() + ']}'; + console.log(output); +} function SegmentedPath(fillStyle, lineStyle) { this.fillStyle = fillStyle; this.lineStyle = lineStyle; @@ -1898,7 +2272,7 @@ var SHAPE_WIDE_LINE_TO = 5; var SHAPE_CUBIC_CURVE_TO = 6; var SHAPE_CIRCLE = 7; var SHAPE_ELLIPSE = 8; -function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) { +function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) { this.fillStyle = fillStyle; this.lineStyle = lineStyle; if (commandsCount) { @@ -1911,8 +2285,21 @@ function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) { } this.bounds = null; this.strokeBounds = null; - this.isMorph = isMorph; + this.isMorph = !(!isMorph); this.fullyInitialized = false; + if (inWorker) { + this.buffers = [ + this.commands.buffer, + this.data.buffer + ]; + transferables.push(this.commands.buffer, this.data.buffer); + if (isMorph) { + this.buffers.push(this.morphData.buffer); + transferables.push(this.morphData.buffer); + } + } else { + this.buffers = null; + } } ShapePath.prototype = { moveTo: function (x, y) { @@ -1961,8 +2348,8 @@ ShapePath.prototype = { var formOpen = false; var formOpenX = 0; var formOpenY = 0; - for (var j = 0, k = 0; j < commands.length; j++) { - if (!this.isMorph) { + if (!this.isMorph) { + for (var j = 0, k = 0; j < commands.length; j++) { switch (commands[j]) { case SHAPE_MOVE_TO: formOpen = true; @@ -2027,9 +2414,14 @@ ShapePath.prototype = { } break; default: + if (commands[j] === 0 && j === commands.length - 1) { + break; + } console.warn('Unknown drawing command encountered: ' + commands[j]); } - } else { + } + } else { + for (var j = 0, k = 0; j < commands.length; j++) { switch (commands[j]) { case SHAPE_MOVE_TO: ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio)); @@ -2512,8 +2904,29 @@ ShapePath.prototype = { this.strokeBounds = bounds; } return bounds; + }, + serialize: function () { + var output = '{'; + if (this.fillStyle) { + output += '"fill":' + JSON.stringify(this.fillStyle) + ','; + } + if (this.lineStyle) { + output += '"stroke":' + JSON.stringify(this.lineStyle) + ','; + } + output += '"commands":[' + Array.apply([], this.commands).join() + '],'; + output += '"data":[' + Array.apply([], this.data).join() + ']'; + return output + '}'; } }; +ShapePath.fromPlainObject = function (obj) { + var path = new ShapePath(obj.fill || null, obj.stroke || null); + path.commands = new Uint8Array(obj.commands); + path.data = new Int32Array(obj.data); + if (!inWorker) { + finishShapePath(path); + } + return path; +}; function distanceSq(x1, y1, x2, y2) { var dX = x2 - x1; var dY = y2 - y1; @@ -2731,23 +3144,24 @@ function extendBoundsByY(bounds, y) { function morph(start, end, ratio) { return start + (end - start) * ratio; } -function finishShapePaths(paths, dictionary) { - for (var i = 0; i < paths.length; i++) { - var path = paths[i]; - if (path.fullyInitialized) { - continue; - } - if (!(path instanceof ShapePath)) { - var untypedPath = path; - path = paths[i] = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph); - path.commands = untypedPath.commands; - path.data = untypedPath.data; - path.morphData = untypedPath.morphData; - } - path.fillStyle && initStyle(path.fillStyle, dictionary); - path.lineStyle && initStyle(path.lineStyle, dictionary); - path.fullyInitialized = true; +function finishShapePath(path, dictionary) { + if (path.fullyInitialized) { + return path; } + if (!(path instanceof ShapePath)) { + var untypedPath = path; + path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph); + path.commands = new Uint8Array(untypedPath.buffers[0]); + path.data = new Int32Array(untypedPath.buffers[1]); + if (untypedPath.isMorph) { + path.morphData = new Int32Array(untypedPath.buffers[2]); + } + path.buffers = null; + } + path.fillStyle && initStyle(path.fillStyle, dictionary); + path.lineStyle && initStyle(path.lineStyle, dictionary); + path.fullyInitialized = true; + return path; } var inWorker = typeof window === 'undefined'; var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null; @@ -2763,7 +3177,7 @@ function buildLinearGradientFactory(colorStops) { } return gradient; }; - fn.defaultGradient = defaultGradient; + fn.defaultFillStyle = defaultGradient; return fn; } function buildRadialGradientFactory(focalPoint, colorStops) { @@ -2778,7 +3192,31 @@ function buildRadialGradientFactory(focalPoint, colorStops) { } return gradient; }; - fn.defaultGradient = defaultGradient; + fn.defaultFillStyle = defaultGradient; + return fn; +} +function buildBitmapPatternFactory(img, repeat) { + var defaultPattern = factoryCtx.createPattern(img, repeat); + var cachedTransform, cachedTransformKey; + var fn = function createBitmapPattern(ctx, colorTransform) { + if (!colorTransform.mode) { + return defaultPattern; + } + var key = colorTransform.getTransformFingerprint(); + if (key === cachedTransformKey) { + return cachedTransform; + } + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + colorTransform.setAlpha(ctx, true); + ctx.drawImage(img, 0, 0); + cachedTransform = ctx.createPattern(canvas, repeat); + cachedTransformKey = key; + return cachedTransform; + }; + fn.defaultFillStyle = defaultPattern; return fn; } function initStyle(style, dictionary) { @@ -2815,7 +3253,7 @@ function initStyle(style, dictionary) { case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP: var bitmap = dictionary[style.bitmapId]; var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP; - style.style = factoryCtx.createPattern(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat'); + style.style = buildBitmapPatternFactory(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat'); break; default: fail('invalid fill style', 'shape'); @@ -3462,47 +3900,46 @@ SWF.embed = function (file, doc, container, options) { var canvas = doc.createElement('canvas'); var ctx = canvas.getContext('2d'); var loader = new flash.display.Loader(); - var loaderInfo = loader.contentLoaderInfo; + var loaderInfo = loader._contentLoaderInfo; var stage = new flash.display.Stage(); + var pixelRatio = 1; + var forceHidpiSetting = forceHidpi.value; stage._loader = loader; loaderInfo._parameters = options.movieParams; loaderInfo._url = options.url || (typeof file === 'string' ? file : null); loaderInfo._loaderURL = options.loaderURL || loaderInfo._url; - var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; - var canvasHolder = null; - canvas._pixelRatio = pixelRatio; - if (pixelRatio > 1) { - var cssScale = 'scale(' + 1 / pixelRatio + ', ' + 1 / pixelRatio + ')'; - canvas.setAttribute('style', '-moz-transform: ' + cssScale + ';' + '-webkit-transform: ' + cssScale + ';' + 'transform: ' + cssScale + ';' + '-moz-transform-origin: 0% 0%;' + '-webkit-transform-origin: 0% 0%;' + 'transform-origin: 0% 0%;'); - canvasHolder = doc.createElement('div'); - canvasHolder.setAttribute('style', 'display: inline-block; overflow: hidden;'); - canvasHolder.appendChild(canvas); - } - stage._contentsScaleFactor = pixelRatio; loader._parent = stage; loader._stage = stage; - function fitCanvas(container, canvas) { - if (canvasHolder) { - canvasHolder.style.width = container.clientWidth + 'px'; - canvasHolder.style.height = container.clientHeight + 'px'; + function setCanvasSize(width, height) { + if (pixelRatio === 1) { + canvas.width = width | 0; + canvas.height = height | 0; + return; } - canvas.width = container.clientWidth * pixelRatio; - canvas.height = container.clientHeight * pixelRatio; + var canvasWidth = Math.floor(width * pixelRatio); + var canvasHeight = Math.floor(height * pixelRatio); + canvas.style.width = canvasWidth / pixelRatio + 'px'; + canvas.style.height = canvasHeight / pixelRatio + 'px'; + canvas.width = canvasWidth; + canvas.height = canvasHeight; + } + function fitCanvas(container) { + setCanvasSize(container.clientWidth, container.clientHeight); stage._invalid = true; } loaderInfo._addEventListener('init', function () { + if (forceHidpiSetting || loaderInfo._swfVersion >= 18) { + pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; + } + canvas._pixelRatio = pixelRatio; + stage._contentsScaleFactor = pixelRatio; if (container.clientHeight) { - fitCanvas(container, canvas); + fitCanvas(container); window.addEventListener('resize', function () { - fitCanvas(container, canvas); + fitCanvas(container); }); } else { - if (canvasHolder) { - canvasHolder.style.width = stage._stageWidth / 20 + 'px'; - canvasHolder.style.height = stage._stageHeight / 20 + 'px'; - } - canvas.width = stage._stageWidth * pixelRatio / 20; - canvas.height = stage._stageHeight * pixelRatio / 20; + setCanvasSize(stage._stageWidth / 20, stage._stageHeight / 20); } container.setAttribute('style', 'position: relative'); canvas.addEventListener('click', function () { @@ -3515,10 +3952,7 @@ SWF.embed = function (file, doc, container, options) { } }); canvas.addEventListener('mousedown', function () { - if (stage._mouseTarget._buttonMode) { - stage._mouseTarget._gotoButtonState('down'); - } - stage._mouseTarget._dispatchEvent('mouseDown'); + stage._mouseEvents.push('mousedown'); }); canvas.addEventListener('mousemove', function (domEvt) { var node = this; @@ -3531,8 +3965,8 @@ SWF.embed = function (file, doc, container, options) { } while (node = node.offsetParent); } var m = stage._concatenatedTransform; - var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx) / m.a; - var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty) / m.d; + var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx / 20) / m.a; + var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty / 20) / m.d; if (mouseX !== stage._mouseX || mouseY !== stage._mouseY) { stage._mouseMoved = true; stage._mouseX = mouseX * 20; @@ -3540,10 +3974,7 @@ SWF.embed = function (file, doc, container, options) { } }); canvas.addEventListener('mouseup', function () { - if (stage._mouseTarget._buttonMode) { - stage._mouseTarget._gotoButtonState('over'); - } - stage._mouseTarget._dispatchEvent('mouseUp'); + stage._mouseEvents.push('mouseup'); }); canvas.addEventListener('mouseover', function () { stage._mouseMoved = true; @@ -3553,6 +3984,36 @@ SWF.embed = function (file, doc, container, options) { stage._mouseMoved = true; stage._mouseOver = false; }); + window.addEventListener('message', function (evt) { + var data = evt.data; + if (typeof data !== 'object' || data === null) { + return; + } + var type = data.type; + switch (type) { + case 'mousemove': + case 'mouseup': + case 'mousedown': + var isMouseMove = type === 'mousemove'; + stage._mouseMoved = true; + stage._mouseOver = true; + stage._mouseX = data.x * 20; + stage._mouseY = data.y * 20; + if (!isMouseMove) { + stage._mouseEvents.push(type); + } + break; + case 'mouseover': + case 'mouseout': + stage._mouseMoved = true; + stage._mouseOver = type === 'mouseover'; + break; + case 'keyup': + case 'keydown': + stage._dispatchEvent(new flash.events.KeyboardEvent(type === 'keyup' ? 'keyUp' : 'keyDown', true, false, data.charCode, data.keyCode, data.keyLocation, data.ctrlKey || false, data.altKey || false, data.shiftKey || false)); + break; + } + }, false); var bgcolor = loaderInfo._backgroundColor; if (options.objectParams) { var m; @@ -3578,10 +4039,9 @@ SWF.embed = function (file, doc, container, options) { ctx.fillStyle = rgbaObjToStr(bgcolor); ctx.fillRect(0, 0, canvas.width, canvas.height); var root = loader._content; - stage._children[0] = root; - root._dispatchEvent('added'); + root._dispatchEvent('added', undefined, true); root._dispatchEvent('addedToStage'); - container.appendChild(canvasHolder || canvas); + container.appendChild(canvas); if (options.onStageInitialized) { options.onStageInitialized(stage); } @@ -3604,11 +4064,19 @@ var showRedrawRegions = rendererOptions.register(new Option('rr', 'showRedrawReg var renderAsWireframe = rendererOptions.register(new Option('raw', 'renderAsWireframe', 'boolean', false, 'render as wireframe')); var showQuadTree = rendererOptions.register(new Option('qt', 'showQuadTree', 'boolean', false, 'show quad tree')); var turboMode = rendererOptions.register(new Option('', 'turbo', 'boolean', false, 'turbo mode')); +var forceHidpi = rendererOptions.register(new Option('', 'forceHidpi', 'boolean', false, 'force hidpi')); +var enableConstructChildren = rendererOptions.register(new Option('', 'constructChildren', 'boolean', true, 'Construct Children')); +var enableEnterFrame = rendererOptions.register(new Option('', 'enterFrame', 'boolean', true, 'Enter Frame')); +var enableAdvanceFrame = rendererOptions.register(new Option('', 'advanceFrame', 'boolean', true, 'Advance Frame')); if (typeof FirefoxCom !== 'undefined') { turboMode.value = FirefoxCom.requestSync('getBoolPref', { pref: 'shumway.turboMode', def: false }); + forceHidpi.value = FirefoxCom.requestSync('getBoolPref', { + pref: 'shumway.force_hidpi', + def: false + }); } var CanvasCache = { cache: [], @@ -3648,8 +4116,7 @@ function visitContainer(container, visitor, context) { continue; } if (visitor.ignoreVisibleAttribute || child._visible && !child._maskedObject) { - var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child) || flash.display.SimpleButton.class.isInstanceOf(child); - visitor.visit(child, isContainer, visitContainer, context); + visitor.visit(child, visitContainer, context); } } visitor.childrenEnd(container); @@ -3681,9 +4148,21 @@ RenderVisitor.prototype = { start: function () { visitContainer(this.root, this, new RenderingContext(this.refreshStage, this.invalidPath)); }, - startFragment: function () { - var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(this.root) || flash.display.SimpleButton.class.isInstanceOf(this.root); - var t = this.root._currentTransform; + startFragment: function (matrix) { + var root = this.root; + var currentTransform = root._currentTransform; + var t = currentTransform; + if (matrix) { + t = root._currentTransform = { + a: matrix.a, + b: matrix.b, + c: matrix.c, + d: matrix.d, + tx: matrix.tx * 20 | 0, + ty: matrix.ty * 20 | 0 + }; + root._invalidateTransform(); + } var inverse; if (t) { inverse = new flash.geom.Matrix(t.a, t.b, t.c, t.d, t.tx / 20, t.ty / 20); @@ -3691,10 +4170,14 @@ RenderVisitor.prototype = { this.ctx.save(); this.ctx.transform(inverse.a, inverse.b, inverse.c, inverse.d, inverse.tx, inverse.ty); } - this.visit(this.root, isContainer, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath)); + this.visit(root, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath)); if (t) { this.ctx.restore(); } + if (matrix) { + root._currentTransform = currentTransform; + root._invalidateTransform(); + } }, childrenStart: function (parent) { if (this.depth === 0) { @@ -3733,8 +4216,9 @@ RenderVisitor.prototype = { childrenEnd: function (parent) { if (this.clipDepth) { while (this.clipDepth.length > 0) { - this.clipDepth.pop(); - this.ctx.restore(); + var clipDepthInfo = this.clipDepth.pop(); + this.clipEnd(clipDepthInfo); + this.ctx = clipDepthInfo.ctx; } this.clipDepth = null; } @@ -3748,7 +4232,7 @@ RenderVisitor.prototype = { this.invalidPath = null; } }, - visit: function (child, isContainer, visitContainer, context) { + visit: function (child, visitContainer, context) { var ctx = this.ctx; var parentHasClippingMask = context.isClippingMask; var parentColorTransform = context.colorTransform; @@ -3757,20 +4241,29 @@ RenderVisitor.prototype = { context.colorTransform = parentColorTransform.applyCXForm(child._cxform); } if (!clippingMask) { - while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0]) { - this.clipDepth.shift(); - ctx.restore(); + while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0].clipDepth) { + var clipDepthInfo = this.clipDepth.shift(); + this.clipEnd(clipDepthInfo); + ctx = this.ctx = clipDepthInfo.ctx; } if (child._clipDepth) { - if (!this.clipDepth) { - this.clipDepth = []; - } context.isClippingMask = clippingMask = true; - this.clipDepth.unshift(child._clipDepth); - ctx.save(); + var clipDepthInfo = this.clipStart(child); + if (!this.clipDepth) { + this.clipDepth = [ + clipDepthInfo + ]; + } else { + this.clipDepth.unshift(clipDepthInfo); + } + ctx = this.ctx = clipDepthInfo.mask.ctx; + } else { + if (this.clipDepth && this.clipDepth.length > 0 && child._depth <= this.clipDepth[0].clipDepth) { + ctx = this.ctx = this.clipDepth[0].maskee.ctx; + } } } - if (clippingMask && isContainer) { + if (clippingMask && child._isContainer) { ctx.save(); renderDisplayObject(child, ctx, context); for (var i = 0, n = child._children.length; i < n; i++) { @@ -3779,12 +4272,11 @@ RenderVisitor.prototype = { continue; } if (this.ignoreVisibleAttribute || child1._visible && !child1._maskedObject) { - var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child1) || flash.display.SimpleButton.class.isInstanceOf(child1); - this.visit(child1, isContainer, visitContainer, context); + this.visit(child1, visitContainer, context); } } ctx.restore(); - ctx.clip(); + ctx.fill(); context.isClippingMask = parentHasClippingMask; context.colorTransform = parentColorTransform; return; @@ -3792,45 +4284,64 @@ RenderVisitor.prototype = { ctx.save(); ctx.globalCompositeOperation = getBlendModeName(child._blendMode); if (child._mask) { - var m = child._parent._getConcatenatedTransform(true); - var tempCanvas, tempCtx, maskCanvas, maskCtx; - maskCanvas = CanvasCache.getCanvas(ctx.canvas); - maskCtx = maskCanvas.ctx; - maskCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty); - var isMaskContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child._mask) || flash.display.SimpleButton.class.isInstanceOf(child._mask); - this.ctx = maskCtx; - this.visit(child._mask, isMaskContainer, visitContainer, new RenderingContext(this.refreshStage)); + var clipInfo = this.clipStart(child); + var mask = clipInfo.mask; + var maskee = clipInfo.maskee; + var savedClipDepth = this.clipDepth; + this.clipDepth = null; + this.ctx = mask.ctx; + this.visit(child._mask, visitContainer, new RenderingContext(this.refreshStage)); this.ctx = ctx; - tempCanvas = CanvasCache.getCanvas(ctx.canvas); - tempCtx = tempCanvas.ctx; - tempCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty); - renderDisplayObject(child, tempCtx, context); - if (isContainer) { - this.ctx = tempCtx; + this.clipDepth = savedClipDepth; + renderDisplayObject(child, maskee.ctx, context); + if (child._isContainer) { + this.ctx = maskee.ctx; visitContainer(child, this, context); this.ctx = ctx; } - tempCtx.globalCompositeOperation = 'destination-in'; - tempCtx.setTransform(1, 0, 0, 1, 0, 0); - tempCtx.drawImage(maskCanvas.canvas, 0, 0); - ctx.save(); - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.drawImage(tempCanvas.canvas, 0, 0); - ctx.restore(); - CanvasCache.releaseCanvas(tempCanvas); - CanvasCache.releaseCanvas(maskCanvas); + this.clipEnd(clipInfo); } else { renderDisplayObject(child, ctx, context); - if (isContainer) { + if (child._isContainer) { visitContainer(child, this, context); } } ctx.restore(); if (clippingMask) { - ctx.clip(); + ctx.fill(); } context.isClippingMask = parentHasClippingMask; context.colorTransform = parentColorTransform; + }, + clipStart: function (child) { + var m = child._parent._getConcatenatedTransform(true); + var tx = m.tx / 20; + var ty = m.ty / 20; + var mask = CanvasCache.getCanvas(this.ctx.canvas); + mask.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty); + var maskee = CanvasCache.getCanvas(this.ctx.canvas); + maskee.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty); + var clipInfo = { + ctx: this.ctx, + mask: mask, + maskee: maskee, + clipDepth: child._clipDepth + }; + return clipInfo; + }, + clipEnd: function (clipInfo) { + var ctx = clipInfo.ctx; + var mask = clipInfo.mask; + var maskee = clipInfo.maskee; + maskee.ctx.globalCompositeOperation = 'destination-in'; + maskee.ctx.setTransform(1, 0, 0, 1, 0, 0); + maskee.ctx.drawImage(mask.canvas, 0, 0); + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.drawImage(maskee.canvas, 0, 0); + ctx.restore(); + CanvasCache.releaseCanvas(mask); + CanvasCache.releaseCanvas(maskee); } }; function RenderingColorTransform() { @@ -3877,7 +4388,7 @@ RenderingColorTransform.prototype = { } else if (typeof style === 'number') { style = this.convertNumericColor(style); } else if (typeof style === 'function') { - style = style.defaultGradient; + style = style.defaultFillStyle; } ctx.fillStyle = style; }, @@ -3887,7 +4398,7 @@ RenderingColorTransform.prototype = { } else if (typeof style === 'number') { style = this.convertNumericColor(style); } else if (typeof style === 'function') { - style = style.defaultGradient; + style = style.defaultFillStyle; } ctx.strokeStyle = style; }, @@ -3944,6 +4455,9 @@ RenderingColorTransform.prototype = { var b = Math.min(255, Math.max(0, m[3] * t[2] + t[6])) | 0; var a = Math.min(1, Math.max(0, m[4] * t[3] + t[7] / 256)); return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; + }, + getTransformFingerprint: function () { + return this.transform.join('|'); } }; function RenderingContext(refreshStage, invalidPath) { @@ -4013,7 +4527,6 @@ function renderQuadTree(ctx, qtree) { renderQuadTree(ctx, nodes[i]); } } -var fps; var renderingTerminated = false; var samplesLeftPlusOne = 0; function triggerSampling(count) { @@ -4040,6 +4553,18 @@ function sampleEnd() { console.profileEnd('Sample'); } } +var timeline; +function timelineEnter(name) { + timeline && timeline.enter(name); +} +function timelineLeave(name) { + timeline && timeline.leave(name); +} +function timelineWrapBroadcastMessage(domain, message) { + timelineEnter(message); + domain.broadcastMessage(message); + timelineLeave(message); +} function renderStage(stage, ctx, events) { var frameWidth, frameHeight; function updateRenderTransform() { @@ -4090,8 +4615,8 @@ function renderStage(stage, ctx, events) { var m = stage._concatenatedTransform; m.a = scaleX; m.d = scaleY; - m.tx = offsetX; - m.ty = offsetY; + m.tx = offsetX * 20; + m.ty = offsetY * 20; } updateRenderTransform(); var frameTime = 0; @@ -4180,6 +4705,8 @@ function renderStage(stage, ctx, events) { if (stage._mouseMoved) { stage._mouseMoved = false; mouseMoved = stage._mouseOver; + } else { + stage._handleMouseButtons(); } if (renderFrame || refreshStage || mouseMoved) { FrameCounter.clear(); @@ -4194,18 +4721,18 @@ function renderStage(stage, ctx, events) { nextRenderAt += maxDelay; } } - fps && fps.enter('EVENTS'); + timelineEnter('EVENTS'); if (firstRun) { firstRun = false; } else { - domain.broadcastMessage('advanceFrame'); - domain.broadcastMessage('enterFrame'); - domain.broadcastMessage('constructChildren'); + enableAdvanceFrame.value && timelineWrapBroadcastMessage(domain, 'advanceFrame'); + enableEnterFrame.value && timelineWrapBroadcastMessage(domain, 'enterFrame'); + enableConstructChildren.value && timelineWrapBroadcastMessage(domain, 'constructChildren'); } - domain.broadcastMessage('frameConstructed'); - domain.broadcastMessage('executeFrame'); - domain.broadcastMessage('exitFrame'); - fps && fps.leave('EVENTS'); + timelineWrapBroadcastMessage(domain, 'frameConstructed'); + timelineWrapBroadcastMessage(domain, 'executeFrame'); + timelineWrapBroadcastMessage(domain, 'exitFrame'); + timelineLeave('EVENTS'); } if (stage._deferRenderEvent) { stage._deferRenderEvent = false; @@ -4215,19 +4742,19 @@ function renderStage(stage, ctx, events) { var invalidPath = null; if (!disablePreVisitor.value) { traceRenderer.value && frameWriter.enter('> Pre Visitor'); - fps && fps.enter('PRE'); + timelineEnter('PRE'); invalidPath = stage._processInvalidRegions(true); - fps && fps.leave('PRE'); + timelineLeave('PRE'); traceRenderer.value && frameWriter.leave('< Pre Visitor'); } else { stage._processInvalidRegions(false); } if (!disableRenderVisitor.value) { - fps && fps.enter('RENDER'); + timelineEnter('RENDER'); traceRenderer.value && frameWriter.enter('> Render Visitor'); new RenderVisitor(stage, ctx, invalidPath, refreshStage).start(); traceRenderer.value && frameWriter.leave('< Render Visitor'); - fps && fps.leave('RENDER'); + timelineLeave('RENDER'); } if (showQuadTree.value) { ctx.strokeStyle = 'green'; @@ -4240,20 +4767,22 @@ function renderStage(stage, ctx, events) { } } if (mouseMoved && !disableMouseVisitor.value) { - fps && renderFrame && fps.enter('MOUSE'); + renderFrame && timelineEnter('MOUSE'); traceRenderer.value && frameWriter.enter('> Mouse Visitor'); stage._handleMouse(); traceRenderer.value && frameWriter.leave('< Mouse Visitor'); - fps && renderFrame && fps.leave('MOUSE'); + renderFrame && timelineLeave('MOUSE'); ctx.canvas.style.cursor = stage._cursor; } if (renderFrame && events.onAfterFrame) { events.onAfterFrame(); } if (traceRenderer.value) { + frameWriter.enter('> Frame Counters'); for (var name in FrameCounter.counts) { - appendToFrameTerminal(name + ': ' + FrameCounter.counts[name], 'gray'); + frameWriter.writeLn(name + ': ' + FrameCounter.counts[name]); } + frameWriter.leave('< Frame Counters'); var frameElapsedTime = performance.now() - frameStartTime; var frameFPS = 1000 / frameElapsedTime; frameFPSAverage.push(frameFPS); @@ -4824,6 +5353,19 @@ var tagHandler = function (global) { $.data = readBinary($bytes, $stream, 0); return $; } + function exportAssets($bytes, $stream, $, swfVersion, tagCode) { + $ || ($ = {}); + var exportsCount = readUi16($bytes, $stream); + var $0 = $.exports = []; + var $1 = exportsCount; + while ($1--) { + var $2 = {}; + $2.symbolId = readUi16($bytes, $stream); + $2.className = readString($bytes, $stream, 0); + $0.push($2); + } + return $; + } function symbolClass($bytes, $stream, $, swfVersion, tagCode) { $ || ($ = {}); var symbolCount = readUi16($bytes, $stream); @@ -5639,7 +6181,7 @@ var tagHandler = function (global) { 45: soundStreamHead, 46: defineShape, 48: defineFont2, - 56: undefined, + 56: exportAssets, 57: undefined, 58: undefined, 59: doAction, @@ -5689,58 +6231,79 @@ var readHeader = function readHeader($bytes, $stream, $, swfVersion, tagCode) { $.frameCount = readUi16($bytes, $stream); return $; }; -function readTags(context, stream, swfVersion, onprogress) { +function readTags(context, stream, swfVersion, final, onprogress) { var tags = context.tags; var bytes = stream.bytes; var lastSuccessfulPosition; + var tag = null; + if (context._readTag) { + tag = context._readTag; + delete context._readTag; + } try { - do { + while (stream.pos < stream.end) { lastSuccessfulPosition = stream.pos; stream.ensure(2); var tagCodeAndLength = readUi16(bytes, stream); + if (!tagCodeAndLength) { + final = true; + break; + } var tagCode = tagCodeAndLength >> 6; var length = tagCodeAndLength & 63; if (length === 63) { stream.ensure(4); length = readUi32(bytes, stream); } - stream.ensure(length); - if (tagCode === 0) { - break; + if (tag) { + if (tagCode === 1 && tag.code === 1) { + tag.repeat++; + stream.pos += length; + continue; + } + tags.push(tag); + if (onprogress && tag.id !== undefined) { + onprogress(context); + } + tag = null; } + stream.ensure(length); var substream = stream.substream(stream.pos, stream.pos += length); var subbytes = substream.bytes; - var tag = { + var nextTag = { code: tagCode }; if (tagCode === 39) { - tag.type = 'sprite'; - tag.id = readUi16(subbytes, substream); - tag.frameCount = readUi16(subbytes, substream); - tag.tags = []; - readTags(tag, substream, swfVersion); + nextTag.type = 'sprite'; + nextTag.id = readUi16(subbytes, substream); + nextTag.frameCount = readUi16(subbytes, substream); + nextTag.tags = []; + readTags(nextTag, substream, swfVersion, true); + } else if (tagCode === 1) { + nextTag.repeat = 1; } else { var handler = tagHandler[tagCode]; if (handler) { - handler(subbytes, substream, tag, swfVersion, tagCode); + handler(subbytes, substream, nextTag, swfVersion, tagCode); } } + tag = nextTag; + } + if (tag && final) { + tag.finalTag = true; tags.push(tag); - if (tagCode === 1) { - while (stream.pos + 2 <= stream.end && stream.getUint16(stream.pos, true) >> 6 === 1) { - tags.push(tag); - stream.pos += 2; - } - if (onprogress) - onprogress(context); - } else if (onprogress && tag.id !== undefined) { + if (onprogress) { onprogress(context); } - } while (stream.pos < stream.end); + } else { + context._readTag = tag; + } } catch (e) { - if (e !== StreamNoDataError) + if (e !== StreamNoDataError) { throw e; + } stream.pos = lastSuccessfulPosition; + context._readTag = tag; } } function HeadTailBuffer(defaultSize) { @@ -5889,12 +6452,14 @@ BodyParser.prototype = { buffer.push(data); stream = buffer.createStream(); } + var finalBlock = false; if (progressInfo) { swf.bytesLoaded = progressInfo.bytesLoaded; swf.bytesTotal = progressInfo.bytesTotal; + finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal; } var readStartTime = performance.now(); - readTags(swf, stream, swfVersion, options.onprogress); + readTags(swf, stream, swfVersion, finalBlock, options.onprogress); swf.parseTime += performance.now() - readStartTime; var read = stream.pos; buffer.removeHead(read); @@ -6007,6 +6572,408 @@ SWF.parse = function (buffer, options) { }; pipe.push(bytes, progressInfo); }; +var $RELEASE = false; +var isWorker = typeof window === 'undefined'; +if (isWorker && !true) { + importScripts.apply(null, [ + '../../lib/DataView.js/DataView.js', + '../flash/util.js', + 'config.js', + 'swf.js', + 'types.js', + 'structs.js', + 'tags.js', + 'inflate.js', + 'stream.js', + 'templates.js', + 'generator.js', + 'handlers.js', + 'parser.js', + 'bitmap.js', + 'button.js', + 'font.js', + 'image.js', + 'label.js', + 'shape.js', + 'sound.js', + 'text.js' + ]); +} +function defineSymbol(swfTag, symbols) { + var symbol; + switch (swfTag.code) { + case SWF_TAG_CODE_DEFINE_BITS: + case SWF_TAG_CODE_DEFINE_BITS_JPEG2: + case SWF_TAG_CODE_DEFINE_BITS_JPEG3: + case SWF_TAG_CODE_DEFINE_BITS_JPEG4: + case SWF_TAG_CODE_JPEG_TABLES: + symbol = defineImage(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS: + case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2: + symbol = defineBitmap(swfTag); + break; + case SWF_TAG_CODE_DEFINE_BUTTON: + case SWF_TAG_CODE_DEFINE_BUTTON2: + symbol = defineButton(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_EDIT_TEXT: + symbol = defineText(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_FONT: + case SWF_TAG_CODE_DEFINE_FONT2: + case SWF_TAG_CODE_DEFINE_FONT3: + case SWF_TAG_CODE_DEFINE_FONT4: + symbol = defineFont(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_MORPH_SHAPE: + case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2: + case SWF_TAG_CODE_DEFINE_SHAPE: + case SWF_TAG_CODE_DEFINE_SHAPE2: + case SWF_TAG_CODE_DEFINE_SHAPE3: + case SWF_TAG_CODE_DEFINE_SHAPE4: + symbol = defineShape(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_SOUND: + symbol = defineSound(swfTag, symbols); + break; + case SWF_TAG_CODE_DEFINE_BINARY_DATA: + symbol = { + type: 'binary', + id: swfTag.id, + data: swfTag.data + }; + break; + case SWF_TAG_CODE_DEFINE_SPRITE: + var depths = {}; + var frame = { + type: 'frame' + }; + var frames = []; + var tags = swfTag.tags; + var frameScripts = null; + var frameIndex = 0; + var soundStream = null; + for (var i = 0, n = tags.length; i < n; i++) { + var tag = tags[i]; + switch (tag.code) { + case SWF_TAG_CODE_DO_ACTION: + if (!frameScripts) + frameScripts = []; + frameScripts.push(frameIndex); + frameScripts.push(tag.actionsData); + break; + case SWF_TAG_CODE_START_SOUND: + var startSounds = frame.startSounds || (frame.startSounds = []); + startSounds.push(tag); + break; + case SWF_TAG_CODE_SOUND_STREAM_HEAD: + try { + soundStream = createSoundStream(tag); + frame.soundStream = soundStream.info; + } catch (e) { + } + break; + case SWF_TAG_CODE_SOUND_STREAM_BLOCK: + if (soundStream) { + frame.soundStreamBlock = soundStream.decode(tag.data); + } + break; + case SWF_TAG_CODE_FRAME_LABEL: + frame.labelName = tag.name; + break; + case SWF_TAG_CODE_PLACE_OBJECT: + case SWF_TAG_CODE_PLACE_OBJECT2: + case SWF_TAG_CODE_PLACE_OBJECT3: + depths[tag.depth] = tag; + break; + case SWF_TAG_CODE_REMOVE_OBJECT: + case SWF_TAG_CODE_REMOVE_OBJECT2: + depths[tag.depth] = null; + break; + case SWF_TAG_CODE_SHOW_FRAME: + frameIndex += tag.repeat; + frame.repeat = tag.repeat; + frame.depths = depths; + frames.push(frame); + depths = {}; + frame = { + type: 'frame' + }; + break; + } + } + symbol = { + type: 'sprite', + id: swfTag.id, + frameCount: swfTag.frameCount, + frames: frames, + frameScripts: frameScripts + }; + break; + case SWF_TAG_CODE_DEFINE_TEXT: + case SWF_TAG_CODE_DEFINE_TEXT2: + symbol = defineLabel(swfTag, symbols); + break; + } + if (!symbol) { + return { + command: 'error', + message: 'unknown symbol type: ' + swfTag.code + }; + } + symbol.isSymbol = true; + symbols[swfTag.id] = symbol; + return symbol; +} +function createParsingContext(commitData) { + var depths = {}; + var symbols = {}; + var frame = { + type: 'frame' + }; + var tagsProcessed = 0; + var soundStream = null; + var lastProgressSent = 0; + return { + onstart: function (result) { + commitData({ + command: 'init', + result: result + }); + }, + onprogress: function (result) { + if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) { + commitData({ + command: 'progress', + result: { + bytesLoaded: result.bytesLoaded, + bytesTotal: result.bytesTotal + } + }); + lastProgressSent = Date.now(); + } + var tags = result.tags; + for (var n = tags.length; tagsProcessed < n; tagsProcessed++) { + var tag = tags[tagsProcessed]; + if ('id' in tag) { + var symbol = defineSymbol(tag, symbols); + commitData(symbol, symbol.transferables); + continue; + } + switch (tag.code) { + case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA: + frame.sceneData = tag; + break; + case SWF_TAG_CODE_DEFINE_SCALING_GRID: + var symbolUpdate = { + isSymbol: true, + id: tag.symbolId, + updates: { + scale9Grid: tag.splitter + } + }; + commitData(symbolUpdate); + break; + case SWF_TAG_CODE_DO_ABC: + case SWF_TAG_CODE_DO_ABC_: + var abcBlocks = frame.abcBlocks; + if (abcBlocks) + abcBlocks.push({ + data: tag.data, + flags: tag.flags + }); + else + frame.abcBlocks = [ + { + data: tag.data, + flags: tag.flags + } + ]; + break; + case SWF_TAG_CODE_DO_ACTION: + var actionBlocks = frame.actionBlocks; + if (actionBlocks) + actionBlocks.push(tag.actionsData); + else + frame.actionBlocks = [ + tag.actionsData + ]; + break; + case SWF_TAG_CODE_DO_INIT_ACTION: + var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []); + initActionBlocks.push({ + spriteId: tag.spriteId, + actionsData: tag.actionsData + }); + break; + case SWF_TAG_CODE_START_SOUND: + var startSounds = frame.startSounds; + if (!startSounds) + frame.startSounds = startSounds = []; + startSounds.push(tag); + break; + case SWF_TAG_CODE_SOUND_STREAM_HEAD: + try { + soundStream = createSoundStream(tag); + frame.soundStream = soundStream.info; + } catch (e) { + } + break; + case SWF_TAG_CODE_SOUND_STREAM_BLOCK: + if (soundStream) { + frame.soundStreamBlock = soundStream.decode(tag.data); + } + break; + case SWF_TAG_CODE_EXPORT_ASSETS: + var exports = frame.exports; + if (exports) + frame.exports = exports.concat(tag.exports); + else + frame.exports = tag.exports.slice(0); + break; + case SWF_TAG_CODE_SYMBOL_CLASS: + var symbolClasses = frame.symbolClasses; + if (symbolClasses) + frame.symbolClasses = symbolClasses.concat(tag.exports); + else + frame.symbolClasses = tag.exports.slice(0); + break; + case SWF_TAG_CODE_FRAME_LABEL: + frame.labelName = tag.name; + break; + case SWF_TAG_CODE_PLACE_OBJECT: + case SWF_TAG_CODE_PLACE_OBJECT2: + case SWF_TAG_CODE_PLACE_OBJECT3: + depths[tag.depth] = tag; + break; + case SWF_TAG_CODE_REMOVE_OBJECT: + case SWF_TAG_CODE_REMOVE_OBJECT2: + depths[tag.depth] = null; + break; + case SWF_TAG_CODE_SET_BACKGROUND_COLOR: + frame.bgcolor = tag.color; + break; + case SWF_TAG_CODE_SHOW_FRAME: + frame.repeat = tag.repeat; + frame.depths = depths; + frame.complete = !(!tag.finalTag); + commitData(frame); + depths = {}; + frame = { + type: 'frame' + }; + break; + } + } + }, + oncomplete: function (result) { + commitData(result); + var stats; + if (typeof result.swfVersion === 'number') { + var bbox = result.bbox; + stats = { + topic: 'parseInfo', + parseTime: result.parseTime, + bytesTotal: result.bytesTotal, + swfVersion: result.swfVersion, + frameRate: result.frameRate, + width: (bbox.xMax - bbox.xMin) / 20, + height: (bbox.yMax - bbox.yMin) / 20, + isAvm2: !(!result.fileAttributes.doAbc) + }; + } + commitData({ + command: 'complete', + stats: stats + }); + } + }; +} +function parseBytes(bytes, commitData) { + SWF.parse(bytes, createParsingContext(commitData)); +} +function ResourceLoader(scope) { + this.subscription = null; + var self = this; + if (!isWorker) { + this.messenger = { + postMessage: function (data) { + self.onmessage({ + data: data + }); + } + }; + } else { + this.messenger = scope; + scope.onmessage = function (event) { + self.listener(event.data); + }; + } +} +ResourceLoader.prototype = { + terminate: function () { + this.messenger = null; + this.listener = null; + }, + onmessage: function (event) { + this.listener(event.data); + }, + postMessage: function (data) { + this.listener && this.listener(data); + }, + listener: function (data) { + if (this.subscription) { + this.subscription.callback(data.data, data.progress); + } else if (data === 'pipe:') { + this.subscription = { + subscribe: function (callback) { + this.callback = callback; + } + }; + this.parseLoadedData(this.messenger, this.subscription); + } else { + this.parseLoadedData(this.messenger, data); + } + }, + parseLoadedData: function (loader, request, context) { + function commitData(data, transferables) { + try { + loader.postMessage(data, transferables); + } catch (ex) { + if (ex != 'DataCloneError') { + throw ex; + } + loader.postMessage(data); + } + } + if (request instanceof ArrayBuffer) { + parseBytes(request, commitData); + } else if ('subscribe' in request) { + var pipe = SWF.parseAsync(createParsingContext(commitData)); + request.subscribe(function (data, progress) { + if (data) { + pipe.push(data, progress); + } else { + pipe.close(); + } + }); + } else if (typeof FileReaderSync !== 'undefined') { + var reader = new FileReaderSync(); + var buffer = reader.readAsArrayBuffer(request); + parseBytes(buffer, commitData); + } else { + var reader = new FileReader(); + reader.onload = function () { + parseBytes(this.result, commitData); + }; + reader.readAsArrayBuffer(request); + } + } +}; +if (isWorker) { + var loader = new ResourceLoader(this); +} function ActionsDataStream(array, swfVersion) { this.array = array; this.position = 0; @@ -6162,12 +7129,8 @@ function AS2Context(swfVersion) { } AS2Context.instance = null; AS2Context.prototype = { - addAssets: function (assets) { - for (var i = 0; i < assets.length; i++) { - if (assets[i].className) { - this.assets[assets[i].className] = assets[i]; - } - } + addAsset: function (className, symbolProps) { + this.assets[className] = symbolProps; }, resolveTarget: function (target) { if (!target) { @@ -6257,10 +7220,6 @@ function as2ToNumber(value) { case 'undefined': case 'null': return AS2Context.instance.swfVersion >= 7 ? NaN : 0; - default: - return AS2Context.instance.swfVersion >= 5 ? NaN : 0; - case 'null': - return NaN; case 'boolean': return value ? 1 : +0; case 'number': @@ -6270,6 +7229,8 @@ function as2ToNumber(value) { return 0; } return +value; + default: + return AS2Context.instance.swfVersion >= 5 ? NaN : 0; } } function as2ToInteger(value) { @@ -6298,8 +7259,6 @@ function as2ToString(value) { return value.toString(); case 'string': return value; - case 'undefined': - return 'undefined'; case 'movieclip': return value.$targetPath; case 'object': @@ -6396,7 +7355,7 @@ function as2CreatePrototypeProxy(obj) { } }); } -function executeActions(actionsData, context, scope, assets) { +function executeActions(actionsData, context, scope) { var actionTracer = ActionTracerFactory.get(); var scopeContainer = context.initialScope.create(scope); var savedContext = AS2Context.instance; @@ -6404,9 +7363,6 @@ function executeActions(actionsData, context, scope, assets) { AS2Context.instance = context; context.defaultTarget = scope; context.globals.asSetPublicProperty('this', scope); - if (assets) { - context.addAssets(assets); - } actionTracer.message('ActionScript Execution Starts'); actionTracer.indent(); interpretActions(actionsData, scopeContainer, null, []); @@ -7645,10 +8601,9 @@ if (typeof GLOBAL !== 'undefined') { GLOBAL.executeActions = executeActions; GLOBAL.AS2Context = AS2Context; } -var debug = true; var $DEBUG; -var release = false; -var compatibility = true; +var release = true; +var checkArguments = true; var useSurrogates = true; var useAsAdd = true; var sealConstTraits = false; @@ -7656,21 +8611,11 @@ var c4CoerceNonPrimitiveParameters = false; var c4CoerceNonPrimitive = false; var c4AsTypeLate = true; var inBrowser = typeof console != 'undefined'; -if (!inBrowser) { - console = { - info: print, - warn: function (x) { - if (traceWarnings.value) { - print(x); - } - } - }; -} if (!this.performance) { this.performance = {}; } if (!this.performance.now) { - this.performance.now = Date.now; + this.performance.now = dateNow; } function backtrace() { try { @@ -7681,7 +8626,7 @@ function backtrace() { } function error(message) { if (!inBrowser) { - console.info(backtrace()); + console.warn(backtrace()); } throw new Error(message); } @@ -7695,11 +8640,6 @@ function assert(condition) { error(message.join('')); } } -function assertFalse(condition, message) { - if (condition) { - error(message); - } -} function assertNotImplemented(condition, message) { if (!condition) { error('NotImplemented: ' + message); @@ -7708,6 +8648,9 @@ function assertNotImplemented(condition, message) { function warning(message) { true; } +function notUsed(message) { + true; +} function notImplemented(message) { true; } @@ -7896,23 +8839,26 @@ function isNumeric(x) { if (typeof x === 'number') { return x === (x | 0); } - if (typeof x === 'string' && x.length) { - if (x === '0') { - return true; - } - if (x[0] >= '1' && x[0] <= '9') { - for (var i = 1; i < x.length; i++) { - if (!(x[i] >= '1' && x[i] <= '9')) { - return false; - } + if (typeof x !== 'string' || x.length === 0) { + return false; + } + if (x === '0') { + return true; + } + var c = x.charCodeAt(0); + if (c >= 49 && c <= 57) { + for (var i = 1, j = x.length; i < j; i++) { + c = x.charCodeAt(i); + if (!(c >= 48 && c <= 57)) { + return false; } - return true; } + return true; } return false; } function boxValue(value) { - if (isNullOrUndefined(value)) { + if (isNullOrUndefined(value) || isObject(value)) { return value; } return Object(value); @@ -8178,6 +9124,9 @@ function bitCount(i) { function escapeString(str) { if (str !== undefined) { str = str.replace(/[^\w$]/gi, '$'); + if (/^\d/.test(str)) { + str = '$' + str; + } } return str; } @@ -8847,23 +9796,6 @@ var Callback = function () { }; return callback; }(); -function dumpBytes(buffer, start, length) { - var s = ''; - bytes = new Uint8Array(buffer, start, length); - var end = length; - for (var i = 0; i < end; i++) { - if (i % 16 === 0) { - s += '\n' + (start + i) + ': '; - } - s += bytes[i] + ' '; - } - return s; -} -function addProfileMarker(marker) { - if (typeof FirefoxCom !== 'undefined') { - FirefoxCom.requestSync('addProfilerMarker', marker); - } -} var CircularBuffer = function () { var mask = 4095, size = 4096; function circularBuffer(Type) { @@ -8901,12 +9833,25 @@ var CircularBuffer = function () { }; return circularBuffer; }(); +function lazyClass(holder, name, initialize) { + Object.defineProperty(holder, name, { + get: function () { + var start = performance.now(); + var value = initialize(); + print('Initialized Class: ' + name + ' ' + (performance.now() - start).toFixed(4)); + Object.defineProperty(holder, name, { + value: value, + writable: true + }); + return value; + }, + configurable: true + }); +} +function createNewCompartment() { + return newGlobal('new-compartment'); +} (function (exports) { - if (!performance) { - performance = { - now: Date.now - }; - } var Timer = function () { var base = new timer(null, 'Total'), top = base; var flat = new timer(null, 'Flat'), flatStack = []; @@ -8965,7 +9910,7 @@ var CircularBuffer = function () { })); return; } - writer.enter(this.name + ': ' + this.total + ' ms' + ', count: ' + this.count + ', average: ' + (this.total / this.count).toFixed(2) + ' ms'); + writer.enter(this.name + ': ' + this.total.toFixed(2) + ' ms' + ', count: ' + this.count + ', average: ' + (this.total / this.count).toFixed(2) + ' ms'); for (var name in this.timers) { this.timers[name].trace(writer); } @@ -9314,42 +10259,10 @@ var SORT_UNIQUESORT = 4; var SORT_RETURNINDEXEDARRAY = 8; var SORT_NUMERIC = 16; var Errors = { - OutOfMemoryError: { - code: 1000, - message: 'The system is out of memory.' - }, - NotImplementedError: { - code: 1001, - message: 'The method %1 is not implemented.' - }, - InvalidPrecisionError: { - code: 1002, - message: 'Number.toPrecision has a range of 1 to 21. Number.toFixed and Number.toExponential have a range of 0 to 20. Specified value is not within expected range.' - }, - InvalidRadixError: { - code: 1003, - message: 'The radix argument must be between 2 and 36; got %1.' - }, - InvokeOnIncompatibleObjectError: { - code: 1004, - message: 'Method %1 was invoked on an incompatible object.' - }, - ArrayIndexNotIntegerError: { - code: 1005, - message: 'Array index is not a positive integer (%1).' - }, CallOfNonFunctionError: { code: 1006, message: '%1 is not a function.' }, - ConstructOfNonFunctionError: { - code: 1007, - message: 'Instantiation attempted on a non-constructor.' - }, - AmbiguousBindingError: { - code: 1008, - message: '%1 is ambiguous; Found more than one matching binding.' - }, ConvertNullToObjectError: { code: 1009, message: 'Cannot access a property or method of a null object reference.' @@ -9358,434 +10271,22 @@ var Errors = { code: 1010, message: 'A term is undefined and has no properties.' }, - IllegalOpcodeError: { - code: 1011, - message: 'Method %1 contained illegal opcode %2 at offset %3.' - }, - LastInstExceedsCodeSizeError: { - code: 1012, - message: 'The last instruction exceeded code size.' - }, - FindVarWithNoScopeError: { - code: 1013, - message: 'Cannot call OP_findproperty when scopeDepth is 0.' - }, ClassNotFoundError: { code: 1014, message: 'Class %1 could not be found.' }, - IllegalSetDxns: { - code: 1015, - message: 'Method %1 cannot set default xml namespace' - }, - DescendentsError: { - code: 1016, - message: 'Descendants operator (..) not supported on type %1.' - }, - ScopeStackOverflowError: { - code: 1017, - message: 'Scope stack overflow occurred.' - }, - ScopeStackUnderflowError: { - code: 1018, - message: 'Scope stack underflow occurred.' - }, - GetScopeObjectBoundsError: { - code: 1019, - message: 'Getscopeobject %1 is out of bounds.' - }, - CannotFallOffMethodError: { - code: 1020, - message: 'Code cannot fall off the end of a method.' - }, - InvalidBranchTargetError: { - code: 1021, - message: 'At least one branch target was not on a valid instruction in the method.' - }, - IllegalVoidError: { - code: 1022, - message: 'Type void may only be used as a function return type.' - }, - StackOverflowError: { - code: 1023, - message: 'Stack overflow occurred.' - }, - StackUnderflowError: { - code: 1024, - message: 'Stack underflow occurred.' - }, - InvalidRegisterError: { - code: 1025, - message: 'An invalid register %1 was accessed.' - }, - SlotExceedsCountError: { - code: 1026, - message: 'Slot %1 exceeds slotCount=%2 of %3.' - }, - MethodInfoExceedsCountError: { - code: 1027, - message: 'Method_info %1 exceeds method_count=%2.' - }, - DispIdExceedsCountError: { - code: 1028, - message: 'Disp_id %1 exceeds max_disp_id=%2 of %3.' - }, - DispIdUndefinedError: { - code: 1029, - message: 'Disp_id %1 is undefined on %2.' - }, - StackDepthUnbalancedError: { - code: 1030, - message: 'Stack depth is unbalanced. %1 != %2.' - }, - ScopeDepthUnbalancedError: { - code: 1031, - message: 'Scope depth is unbalanced. %1 != %2.' - }, - CpoolIndexRangeError: { - code: 1032, - message: 'Cpool index %1 is out of range %2.' - }, - CpoolEntryWrongTypeError: { - code: 1033, - message: 'Cpool entry %1 is wrong type.' - }, CheckTypeFailedError: { code: 1034, message: 'Type Coercion failed: cannot convert %1 to %2.' }, - IllegalSuperCallError: { - code: 1035, - message: 'Illegal super expression found in method %1.' - }, - CannotAssignToMethodError: { - code: 1037, - message: 'Cannot assign to a method %1 on %2.' - }, - RedefinedError: { - code: 1038, - message: '%1 is already defined.' - }, - CannotVerifyUntilReferencedError: { - code: 1039, - message: 'Cannot verify method until it is referenced.' - }, - CantUseInstanceofOnNonObjectError: { - code: 1040, - message: 'The right-hand side of instanceof must be a class or function.' - }, - IsTypeMustBeClassError: { - code: 1041, - message: 'The right-hand side of operator must be a class.' - }, - InvalidMagicError: { - code: 1042, - message: 'Not an ABC file. major_version=%1 minor_version=%2.' - }, - InvalidCodeLengthError: { - code: 1043, - message: 'Invalid code_length=%1.' - }, - InvalidMethodInfoFlagsError: { - code: 1044, - message: 'MethodInfo-%1 unsupported flags=%2.' - }, - UnsupportedTraitsKindError: { - code: 1045, - message: 'Unsupported traits kind=%1.' - }, - MethodInfoOrderError: { - code: 1046, - message: 'MethodInfo-%1 referenced before definition.' - }, - MissingEntryPointError: { - code: 1047, - message: 'No entry point was found.' - }, - PrototypeTypeError: { - code: 1049, - message: 'Prototype objects must be vanilla Objects.' - }, - ConvertToPrimitiveError: { - code: 1050, - message: 'Cannot convert %1 to primitive.' - }, - IllegalEarlyBindingError: { - code: 1051, - message: 'Illegal early binding access to %1.' - }, - InvalidURIError: { - code: 1052, - message: 'Invalid URI passed to %1 function.' - }, - IllegalOverrideError: { - code: 1053, - message: 'Illegal override of %1 in %2.' - }, - IllegalExceptionHandlerError: { - code: 1054, - message: 'Illegal range or target offsets in exception handler.' - }, - WriteSealedError: { - code: 1056, - message: 'Cannot create property %1 on %2.' - }, - IllegalSlotError: { - code: 1057, - message: '%1 can only contain methods.' - }, - IllegalOperandTypeError: { - code: 1058, - message: 'Illegal operand type: %1 must be %2.' - }, - ClassInfoOrderError: { - code: 1059, - message: 'ClassInfo-%1 is referenced before definition.' - }, - ClassInfoExceedsCountError: { - code: 1060, - message: 'ClassInfo %1 exceeds class_count=%2.' - }, - NumberOutOfRangeError: { - code: 1061, - message: 'The value %1 cannot be converted to %2 without losing precision.' - }, WrongArgumentCountError: { code: 1063, message: 'Argument count mismatch on %1. Expected %2, got %3.' }, - CannotCallMethodAsConstructor: { - code: 1064, - message: 'Cannot call method %1 as constructor.' - }, - UndefinedVarError: { - code: 1065, - message: 'Variable %1 is not defined.' - }, - FunctionConstructorError: { - code: 1066, - message: 'The form function(\'function body\') is not supported.' - }, - IllegalNativeMethodBodyError: { - code: 1067, - message: 'Native method %1 has illegal method body.' - }, - CannotMergeTypesError: { - code: 1068, - message: '%1 and %2 cannot be reconciled.' - }, - ReadSealedError: { - code: 1069, - message: 'Property %1 not found on %2 and there is no default value.' - }, - CallNotFoundError: { - code: 1070, - message: 'Method %1 not found on %2' - }, - AlreadyBoundError: { - code: 1071, - message: 'Function %1 has already been bound to %2.' - }, - ZeroDispIdError: { - code: 1072, - message: 'Disp_id 0 is illegal.' - }, - DuplicateDispIdError: { - code: 1073, - message: 'Non-override method %1 replaced because of duplicate disp_id %2.' - }, - ConstWriteError: { - code: 1074, - message: 'Illegal write to read-only property %1 on %2.' - }, - MathNotFunctionError: { - code: 1075, - message: 'Math is not a function.' - }, - MathNotConstructorError: { - code: 1076, - message: 'Math is not a constructor.' - }, - WriteOnlyError: { - code: 1077, - message: 'Illegal read of write-only property %1 on %2.' - }, - IllegalOpMultinameError: { - code: 1078, - message: 'Illegal opcode/multiname combination: %1<%2>.' - }, - IllegalNativeMethodError: { - code: 1079, - message: 'Native methods are not allowed in loaded code.' - }, - IllegalNamespaceError: { - code: 1080, - message: 'Illegal value for namespace.' - }, - ReadSealedErrorNs: { - code: 1081, - message: 'Property %1 not found on %2 and there is no default value.' - }, - NoDefaultNamespaceError: { - code: 1082, - message: 'No default namespace has been set.' - }, - XMLPrefixNotBound: { - code: 1083, - message: 'The prefix "%1" for element "%2" is not bound.' - }, - XMLBadQName: { - code: 1084, - message: 'Element or attribute ("%1") does not match QName production: QName::=(NCName\':\')?NCName.' - }, - XMLUnterminatedElementTag: { - code: 1085, - message: 'The element type "%1" must be terminated by the matching end-tag "%2>".' - }, - XMLOnlyWorksWithOneItemLists: { - code: 1086, - message: 'The %1 method only works on lists containing one item.' - }, - XMLAssignmentToIndexedXMLNotAllowed: { - code: 1087, - message: 'Assignment to indexed XML is not allowed.' - }, XMLMarkupMustBeWellFormed: { code: 1088, message: 'The markup in the document following the root element must be well-formed.' }, - XMLAssigmentOneItemLists: { - code: 1089, - message: 'Assignment to lists with more than one item is not supported.' - }, - XMLMalformedElement: { - code: 1090, - message: 'XML parser failure: element is malformed.' - }, - XMLUnterminatedCData: { - code: 1091, - message: 'XML parser failure: Unterminated CDATA section.' - }, - XMLUnterminatedXMLDecl: { - code: 1092, - message: 'XML parser failure: Unterminated XML declaration.' - }, - XMLUnterminatedDocTypeDecl: { - code: 1093, - message: 'XML parser failure: Unterminated DOCTYPE declaration.' - }, - XMLUnterminatedComment: { - code: 1094, - message: 'XML parser failure: Unterminated comment.' - }, - XMLUnterminatedAttribute: { - code: 1095, - message: 'XML parser failure: Unterminated attribute.' - }, - XMLUnterminatedElement: { - code: 1096, - message: 'XML parser failure: Unterminated element.' - }, - XMLUnterminatedProcessingInstruction: { - code: 1097, - message: 'XML parser failure: Unterminated processing instruction.' - }, - XMLNamespaceWithPrefixAndNoURI: { - code: 1098, - message: 'Illegal prefix %1 for no namespace.' - }, - RegExpFlagsArgumentError: { - code: 1100, - message: 'Cannot supply flags when constructing one RegExp from another.' - }, - NoScopeError: { - code: 1101, - message: 'Cannot verify method %1 with unknown scope.' - }, - IllegalDefaultValue: { - code: 1102, - message: 'Illegal default value for type %1.' - }, - CannotExtendFinalClass: { - code: 1103, - message: 'Class %1 cannot extend final base class.' - }, - XMLDuplicateAttribute: { - code: 1104, - message: 'Attribute "%1" was already specified for element "%2".' - }, - CorruptABCError: { - code: 1107, - message: 'The ABC data is corrupt, attempt to read out of bounds.' - }, - InvalidBaseClassError: { - code: 1108, - message: 'The OP_newclass opcode was used with the incorrect base class.' - }, - DanglingFunctionError: { - code: 1109, - message: 'Attempt to directly call unbound function %1 from method %2.' - }, - CannotExtendError: { - code: 1110, - message: '%1 cannot extend %2.' - }, - CannotImplementError: { - code: 1111, - message: '%1 cannot implement %2.' - }, - CoerceArgumentCountError: { - code: 1112, - message: 'Argument count mismatch on class coercion. Expected 1, got %1.' - }, - InvalidNewActivationError: { - code: 1113, - message: 'OP_newactivation used in method without NEED_ACTIVATION flag.' - }, - NoGlobalScopeError: { - code: 1114, - message: 'OP_getglobalslot or OP_setglobalslot used with no global scope.' - }, - NotConstructorError: { - code: 1115, - message: '%1 is not a constructor.' - }, - ApplyError: { - code: 1116, - message: 'second argument to Function.prototype.apply must be an array.' - }, - XMLInvalidName: { - code: 1117, - message: 'Invalid XML name: %1.' - }, - XMLIllegalCyclicalLoop: { - code: 1118, - message: 'Illegal cyclical loop between nodes.' - }, - DeleteTypeError: { - code: 1119, - message: 'Delete operator is not supported with operand of type %1.' - }, - DeleteSealedError: { - code: 1120, - message: 'Cannot delete property %1 on %2.' - }, - DuplicateMethodBodyError: { - code: 1121, - message: 'Method %1 has a duplicate method body.' - }, - IllegalInterfaceMethodBodyError: { - code: 1122, - message: 'Interface method %1 has illegal method body.' - }, - FilterError: { - code: 1123, - message: 'Filter operator not supported on type %1.' - }, - InvalidHasNextError: { - code: 1124, - message: 'OP_hasnext2 requires object and index to be distinct registers.' - }, OutOfRangeError: { code: 1125, message: 'The index %1 is out of range %2.' @@ -9794,66 +10295,6 @@ var Errors = { code: 1126, message: 'Cannot change the length of a fixed Vector.' }, - TypeAppOfNonParamType: { - code: 1127, - message: 'Type application attempted on a non-parameterized type.' - }, - WrongTypeArgCountError: { - code: 1128, - message: 'Incorrect number of type parameters for %1. Expected %2, got %3.' - }, - JSONCyclicStructure: { - code: 1129, - message: 'Cyclic structure cannot be converted to JSON string.' - }, - JSONInvalidReplacer: { - code: 1131, - message: 'Replacer argument to JSON stringifier must be an array or a two parameter function.' - }, - JSONInvalidParseInput: { - code: 1132, - message: 'Invalid JSON parse input.' - }, - FileOpenError: { - code: 1500, - message: 'Error occurred opening file %1.' - }, - FileWriteError: { - code: 1501, - message: 'Error occurred writing to file %1.' - }, - ScriptTimeoutError: { - code: 1502, - message: 'A script has executed for longer than the default timeout period of 15 seconds.' - }, - ScriptTerminatedError: { - code: 1503, - message: 'A script failed to exit after 30 seconds and was terminated.' - }, - EndOfFileError: { - code: 1504, - message: 'End of file.' - }, - StringIndexOutOfBoundsError: { - code: 1505, - message: 'The string index %1 is out of bounds; must be in range %2 to %3.' - }, - InvalidRangeError: { - code: 1506, - message: 'The specified range is invalid.' - }, - NullArgumentError: { - code: 1507, - message: 'Argument %1 cannot be null.' - }, - InvalidArgumentError: { - code: 1508, - message: 'The value specified for argument %1 is invalid.' - }, - ArrayFilterNonNullObjectError: { - code: 1510, - message: 'When the callback argument is a method of a class, the optional this argument must be null.' - }, InvalidParamError: { code: 2004, message: 'One of the parameters is invalid.' @@ -9870,142 +10311,10 @@ var Errors = { code: 2008, message: 'Parameter %1 must be one of the accepted values.' }, - CantInstantiateError: { - code: 2012, - message: '%1 class cannot be instantiated.' - }, ArgumentError: { code: 2015, message: 'Invalid BitmapData.' }, - EOFError: { - code: 2030, - message: 'End of file was encountered.' - }, - CompressedDataError: { - code: 2058, - message: 'There was an error decompressing the data.' - }, - EmptyStringError: { - code: 2085, - message: 'Parameter %1 must be non-empty string.' - }, - ProxyGetPropertyError: { - code: 2088, - message: 'The Proxy class does not implement getProperty. It must be overridden by a subclass.' - }, - ProxySetPropertyError: { - code: 2089, - message: 'The Proxy class does not implement setProperty. It must be overridden by a subclass.' - }, - ProxyCallPropertyError: { - code: 2090, - message: 'The Proxy class does not implement callProperty. It must be overridden by a subclass.' - }, - ProxyHasPropertyError: { - code: 2091, - message: 'The Proxy class does not implement hasProperty. It must be overridden by a subclass.' - }, - ProxyDeletePropertyError: { - code: 2092, - message: 'The Proxy class does not implement deleteProperty. It must be overridden by a subclass.' - }, - ProxyGetDescendantsError: { - code: 2093, - message: 'The Proxy class does not implement getDescendants. It must be overridden by a subclass.' - }, - ProxyNextNameIndexError: { - code: 2105, - message: 'The Proxy class does not implement nextNameIndex. It must be overridden by a subclass.' - }, - ProxyNextNameError: { - code: 2106, - message: 'The Proxy class does not implement nextName. It must be overridden by a subclass.' - }, - ProxyNextValueError: { - code: 2107, - message: 'The Proxy class does not implement nextValue. It must be overridden by a subclass.' - }, - InvalidArrayLengthError: { - code: 2108, - message: 'The value %1 is not a valid Array length.' - }, - ReadExternalNotImplementedError: { - code: 2173, - message: 'Unable to read object in stream. The class %1 does not implement flash.utils.IExternalizable but is aliased to an externalizable class.' - }, - NoSecurityContextError: { - code: 2000, - message: 'No active security context.' - }, - TooFewArgumentsError: { - code: 2001, - message: 'Too few arguments were specified; got %1, %2 expected.' - }, - InvalidSocketError: { - code: 2002, - message: 'Operation attempted on invalid socket.' - }, - InvalidSocketPortError: { - code: 2003, - message: 'Invalid socket port number specified.' - }, - ParamTypeError: { - code: 2005, - message: 'Parameter %1 is of the incorrect type. Should be type %2.' - }, - HasStyleSheetError: { - code: 2009, - message: 'This method cannot be used on a text field with a style sheet.' - }, - SocketLocalFileSecurityError: { - code: 2010, - message: 'Local-with-filesystem SWF files are not permitted to use sockets.' - }, - SocketConnectError: { - code: 2011, - message: 'Socket connection failed to %1:%2.' - }, - AuthoringOnlyFeatureError: { - code: 2013, - message: 'Feature can only be used in Flash Authoring.' - }, - FeatureNotAvailableError: { - code: 2014, - message: 'Feature is not available at this time.' - }, - InvalidBitmapDataError: { - code: 2015, - message: 'Invalid BitmapData.' - }, - SystemExitSecurityError: { - code: 2017, - message: 'Only trusted local files may cause the Flash Player to exit.' - }, - SystemExitUnsupportedError: { - code: 2018, - message: 'System.exit is only available in the standalone Flash Player.' - }, - InvalidDepthError: { - code: 2019, - message: 'Depth specified is invalid.' - }, - MovieClipSwapError: { - code: 2020, - message: 'MovieClips objects with different parents cannot be swapped.' - }, - ObjectCreationError: { - code: 2021, - message: 'Object creation failed.' - }, - NotDisplayObjectError: { - code: 2022, - message: 'Class %1 must inherit from DisplayObject to link to a symbol.' - }, - NotSpriteError: { - code: 2023, - message: 'Class %1 must inherit from Sprite to link to the root.' - }, CantAddSelfError: { code: 2024, message: 'An object cannot be added as a child of itself.' @@ -10013,1678 +10322,6 @@ var Errors = { NotAChildError: { code: 2025, message: 'The supplied DisplayObject must be a child of the caller.' - }, - NavigateURLError: { - code: 2026, - message: 'An error occurred navigating to the URL %1.' - }, - MustBeNonNegativeError: { - code: 2027, - message: 'Parameter %1 must be a non-negative number; got %2.' - }, - LocalSecurityError: { - code: 2028, - message: 'Local-with-filesystem SWF file %1 cannot access Internet URL %2.' - }, - InvalidStreamError: { - code: 2029, - message: 'This URLStream object does not have a stream opened.' - }, - SocketError: { - code: 2031, - message: 'Socket Error.' - }, - StreamError: { - code: 2032, - message: 'Stream Error.' - }, - KeyGenerationError: { - code: 2033, - message: 'Key Generation Failed.' - }, - InvalidKeyError: { - code: 2034, - message: 'An invalid digest was supplied.' - }, - URLNotFoundError: { - code: 2035, - message: 'URL Not Found.' - }, - LoadNeverCompletedError: { - code: 2036, - message: 'Load Never Completed.' - }, - InvalidCallError: { - code: 2037, - message: 'Functions called in incorrect sequence, or earlier call was unsuccessful.' - }, - FileIOError: { - code: 2038, - message: 'File I/O Error.' - }, - RemoteURLError: { - code: 2039, - message: 'Invalid remote URL protocol. The remote URL protocol must be HTTP or HTTPS.' - }, - BrowseInProgressError: { - code: 2041, - message: 'Only one file browsing session may be performed at a time.' - }, - DigestNotSupportedError: { - code: 2042, - message: 'The digest property is not supported by this load operation.' - }, - UnhandledError: { - code: 2044, - message: 'Unhandled %1:.' - }, - FileVerificationError: { - code: 2046, - message: 'The loaded file did not have a valid signature.' - }, - DisplayListSecurityError: { - code: 2047, - message: 'Security sandbox violation: %1: %2 cannot access %3.' - }, - DownloadSecurityError: { - code: 2048, - message: 'Security sandbox violation: %1 cannot load data from %2.' - }, - UploadSecurityError: { - code: 2049, - message: 'Security sandbox violation: %1 cannot upload data to %2.' - }, - OutboundScriptingSecurityError: { - code: 2051, - message: 'Security sandbox violation: %1 cannot evaluate scripting URLs within %2 (allowScriptAccess is %3). Attempted URL was %4.' - }, - AllowDomainArgumentError: { - code: 2052, - message: 'Only String arguments are permitted for allowDomain and allowInsecureDomain.' - }, - IntervalSecurityError: { - code: 2053, - message: 'Security sandbox violation: %1 cannot clear an interval timer set by %2.' - }, - ExactSettingsError: { - code: 2054, - message: 'The value of Security.exactSettings cannot be changed after it has been used.' - }, - PrintJobStartError: { - code: 2055, - message: 'The print job could not be started.' - }, - PrintJobSendError: { - code: 2056, - message: 'The print job could not be sent to the printer.' - }, - PrintJobAddPageError: { - code: 2057, - message: 'The page could not be added to the print job.' - }, - ExternalCallbackSecurityError: { - code: 2059, - message: 'Security sandbox violation: %1 cannot overwrite an ExternalInterface callback added by %2.' - }, - ExternalInterfaceSecurityError: { - code: 2060, - message: 'Security sandbox violation: ExternalInterface caller %1 cannot access %2.' - }, - ExternalInterfaceNoCallbackError: { - code: 2061, - message: 'No ExternalInterface callback %1 registered.' - }, - NoCloneMethodError: { - code: 2062, - message: 'Children of Event must override clone() {return new MyEventClass (...);}.' - }, - IMEError: { - code: 2063, - message: 'Error attempting to execute IME command.' - }, - FocusNotSetError: { - code: 2065, - message: 'The focus cannot be set for this target.' - }, - DelayRangeError: { - code: 2066, - message: 'The Timer delay specified is out of range.' - }, - ExternalInterfaceNotAvailableError: { - code: 2067, - message: 'The ExternalInterface is not available in this container. ExternalInterface requires Internet Explorer ActiveX, Firefox, Mozilla 1.7.5 and greater, or other browsers that support NPRuntime.' - }, - InvalidSoundError: { - code: 2068, - message: 'Invalid sound.' - }, - InvalidLoaderMethodError: { - code: 2069, - message: 'The Loader class does not implement this method.' - }, - StageOwnerSecurityError: { - code: 2070, - message: 'Security sandbox violation: caller %1 cannot access Stage owned by %2.' - }, - InvalidStageMethodError: { - code: 2071, - message: 'The Stage class does not implement this property or method.' - }, - ProductManagerDiskError: { - code: 2073, - message: 'There was a problem saving the application to disk.' - }, - ProductManagerStageError: { - code: 2074, - message: 'The stage is too small to fit the download ui.' - }, - ProductManagerVerifyError: { - code: 2075, - message: 'The downloaded file is invalid.' - }, - FilterFailedError: { - code: 2077, - message: 'This filter operation cannot be performed with the specified input parameters.' - }, - TimelineObjectNameSealedError: { - code: 2078, - message: 'The name property of a Timeline-placed object cannot be modified.' - }, - BitmapNotAssociatedWithBitsCharError: { - code: 2079, - message: 'Classes derived from Bitmap can only be associated with defineBits characters (bitmaps).' - }, - AlreadyConnectedError: { - code: 2082, - message: 'Connect failed because the object is already connected.' - }, - CloseNotConnectedError: { - code: 2083, - message: 'Close failed because the object is not connected.' - }, - ArgumentSizeError: { - code: 2084, - message: 'The AMF encoding of the arguments cannot exceed 40K.' - }, - FileReferenceProhibitedError: { - code: 2086, - message: 'A setting in the mms.cfg file prohibits this FileReference request.' - }, - DownloadFileNameProhibitedError: { - code: 2087, - message: 'The FileReference.download() file name contains prohibited characters.' - }, - EventDispatchRecursionError: { - code: 2094, - message: 'Event dispatch recursion overflow.' - }, - AsyncError: { - code: 2095, - message: '%1 was unable to invoke callback %2.' - }, - DisallowedHTTPHeaderError: { - code: 2096, - message: 'The HTTP request header %1 cannot be set via ActionScript.' - }, - FileFilterError: { - code: 2097, - message: 'The FileFilter Array is not in the correct format.' - }, - LoadingObjectNotSWFError: { - code: 2098, - message: 'The loading object is not a .swf file, you cannot request SWF properties from it.' - }, - LoadingObjectNotInitializedError: { - code: 2099, - message: 'The loading object is not sufficiently loaded to provide this information.' - }, - EmptyByteArrayError: { - code: 2100, - message: 'The ByteArray parameter in Loader.loadBytes() must have length greater than 0.' - }, - DecodeParamError: { - code: 2101, - message: 'The String passed to URLVariables.decode() must be a URL-encoded query string containing name/value pairs.' - }, - NotAnXMLChildError: { - code: 2102, - message: 'The before XMLNode parameter must be a child of the caller.' - }, - XMLRecursionError: { - code: 2103, - message: 'XML recursion failure: new child would create infinite loop.' - }, - SceneNotFoundError: { - code: 2108, - message: 'Scene %1 was not found.' - }, - FrameLabelNotFoundError: { - code: 2109, - message: 'Frame label %1 not found in scene %2.' - }, - DisableAVM1LoadingError: { - code: 2110, - message: 'The value of Security.disableAVM1Loading cannot be set unless the caller can access the stage and is in an ActionScript 3.0 SWF file.' - }, - AVM1LoadingError: { - code: 2111, - message: 'Security.disableAVM1Loading is true so the current load of the ActionScript 1.0/2.0 SWF file has been blocked.' - }, - ApplicationDomainSecurityError: { - code: 2112, - message: 'Provided parameter LoaderContext.ApplicationDomain is from a disallowed domain.' - }, - SecurityDomainSecurityError: { - code: 2113, - message: 'Provided parameter LoaderContext.SecurityDomain is from a disallowed domain.' - }, - NonNullPointerError: { - code: 2114, - message: 'Parameter %1 must be null.' - }, - TrueParamError: { - code: 2115, - message: 'Parameter %1 must be false.' - }, - FalseParamError: { - code: 2116, - message: 'Parameter %1 must be true.' - }, - InvalidLoaderInfoMethodError: { - code: 2118, - message: 'The LoaderInfo class does not implement this method.' - }, - LoaderInfoAppDomainSecurityError: { - code: 2119, - message: 'Security sandbox violation: caller %1 cannot access LoaderInfo.applicationDomain owned by %2.' - }, - SecuritySwfNotAllowedError: { - code: 2121, - message: 'Security sandbox violation: %1: %2 cannot access %3. This may be worked around by calling Security.allowDomain.' - }, - SecurityNonSwfIncompletePolicyFilesError: { - code: 2122, - message: 'Security sandbox violation: %1: %2 cannot access %3. A policy file is required, but the checkPolicyFile flag was not set when this media was loaded.' - }, - SecurityNonSwfNotAllowedError: { - code: 2123, - message: 'Security sandbox violation: %1: %2 cannot access %3. No policy files granted access.' - }, - UnknownFileTypeError: { - code: 2124, - message: 'Loaded file is an unknown type.' - }, - SecurityCrossVMNotAllowedError: { - code: 2125, - message: 'Security sandbox violation: %1 cannot use Runtime Shared Library %2 because crossing the boundary between ActionScript 3.0 and ActionScript 1.0/2.0 objects is not allowed.' - }, - NotConnectedError: { - code: 2126, - message: 'NetConnection object must be connected.' - }, - FileRefBadPostDataTypeError: { - code: 2127, - message: 'FileReference POST data cannot be type ByteArray.' - }, - NetConnectionConnectError: { - code: 2129, - message: 'Connection to %1 failed.' - }, - SharedObjectFlushFailedError: { - code: 2130, - message: 'Unable to flush SharedObject.' - }, - DefinitionNotFoundError: { - code: 2131, - message: 'Definition %1 cannot be found.' - }, - NetConnectionInvalidConnectFromNetStatusEventError: { - code: 2132, - message: 'NetConnection.connect cannot be called from a netStatus event handler.' - }, - CallbackNotRegisteredError: { - code: 2133, - message: 'Callback %1 is not registered.' - }, - SharedObjectCreateError: { - code: 2134, - message: 'Cannot create SharedObject.' - }, - InvalidSWFError: { - code: 2136, - message: 'The SWF file %1 contains invalid data.' - }, - NavigationSecurityError: { - code: 2137, - message: 'Security sandbox violation: %1 cannot navigate window %2 within %3 (allowScriptAccess is %4). Attempted URL was %5.' - }, - NonParsableRichTextXMLError: { - code: 2138, - message: 'Rich text XML could not be parsed.' - }, - SharedObjectConnectError: { - code: 2139, - message: 'SharedObject could not connect.' - }, - LocalSecurityLoadingError: { - code: 2140, - message: 'Security sandbox violation: %1 cannot load %2. Local-with-filesystem and local-with-networking SWF files cannot load each other.' - }, - MultiplePrintJobsError: { - code: 2141, - message: 'Only one PrintJob may be in use at a time.' - }, - LocalImportSecurityError: { - code: 2142, - message: 'Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property. %1 was attempting to load %2.' - }, - AccOverrideRole: { - code: 2143, - message: 'AccessibilityImplementation.get_accRole() must be overridden from its default.' - }, - AccOverrideState: { - code: 2144, - message: 'AccessibilityImplementation.get_accState() must be overridden from its default.' - }, - URLRequestHeaderInvalidLengthError: { - code: 2145, - message: 'Cumulative length of requestHeaders must be less than 8192 characters.' - }, - AllowNetworkingSecurityError: { - code: 2146, - message: 'Security sandbox violation: %1 cannot call %2 because the HTML/container parameter allowNetworking has the value %3.' - }, - ForbiddenProtocolError: { - code: 2147, - message: 'Forbidden protocol in URL %1.' - }, - RemoteToLocalSecurityError: { - code: 2148, - message: 'SWF file %1 cannot access local resource %2. Only local-with-filesystem and trusted local SWF files may access local resources.' - }, - FsCommandSecurityError: { - code: 2149, - message: 'Security sandbox violation: %1 cannot make fscommand calls to %2 (allowScriptAccess is %3).' - }, - CantAddParentError: { - code: 2150, - message: 'An object cannot be added as a child to one of it\'s children (or children\'s children, etc.).' - }, - FullScreenSecurityError: { - code: 2151, - message: 'You cannot enter full screen mode when the settings dialog is visible.' - }, - FullScreenNotAllowedError: { - code: 2152, - message: 'Full screen mode is not allowed.' - }, - URLRequestInvalidHeader: { - code: 2153, - message: 'The URLRequest.requestHeaders array must contain only non-NULL URLRequestHeader objects.' - }, - InvalidNetStreamObject: { - code: 2154, - message: 'The NetStream Object is invalid. This may be due to a failed NetConnection.' - }, - InvalidFunctionName: { - code: 2155, - message: 'The ExternalInterface.call functionName parameter is invalid. Only alphanumeric characters are supported.' - }, - ForbiddenPortForProtocolError: { - code: 2156, - message: 'Port %1 may not be accessed using protocol %2. Calling SWF was %3.' - }, - NoAsfunctionErrror: { - code: 2157, - message: 'Rejecting URL %1 because the \'asfunction:\' protocol may only be used for link targets, not for networking APIs.' - }, - InvalidNetConnectionObject: { - code: 2158, - message: 'The NetConnection Object is invalid. This may be due to a dropped NetConnection.' - }, - InvalidSharedObject: { - code: 2159, - message: 'The SharedObject Object is invalid.' - }, - InvalidTextLineError: { - code: 2160, - message: 'The TextLine is INVALID and cannot be used to access the current state of the TextBlock.' - }, - TextLayoutError: { - code: 2161, - message: 'An internal error occured while laying out the text.' - }, - FragmentOutputType: { - code: 2162, - message: 'The Shader output type is not compatible for this operation.' - }, - FragmentInputType: { - code: 2163, - message: 'The Shader input type %1 is not compatible for this operation.' - }, - FragmentInputMissing: { - code: 2164, - message: 'The Shader input %1 is missing or an unsupported type.' - }, - FragmentInputTooSmall: { - code: 2165, - message: 'The Shader input %1 does not have enough data.' - }, - FragmentInputNoDimension: { - code: 2166, - message: 'The Shader input %1 lacks valid dimensions.' - }, - FragmentNotEnoughInput: { - code: 2167, - message: 'The Shader does not have the required number of inputs for this operation.' - }, - StaticTextLineError: { - code: 2168, - message: 'Static text lines have no atoms and no reference to a text block.' - }, - SecurityQuestionableBrowserScriptingError: { - code: 2169, - message: 'The method %1 may not be used for browser scripting. The URL %2 requested by %3 is being ignored. If you intend to call browser script, use navigateToURL instead.' - }, - HeaderSecurityError: { - code: 2170, - message: 'Security sandbox violation: %1 cannot send HTTP headers to %2.' - }, - FragmentMissing: { - code: 2171, - message: 'The Shader object contains no byte code to execute.' - }, - FragmentAlreadyRunning: { - code: 2172, - message: 'The ShaderJob is already running or finished.' - }, - FileReferenceBusyError: { - code: 2174, - message: 'Only one download, upload, load or save operation can be active at a time on each FileReference.' - }, - UnformattedElementError: { - code: 2175, - message: 'One or more elements of the content of the TextBlock has a null ElementFormat.' - }, - UserActionRequiredError: { - code: 2176, - message: 'Certain actions, such as those that display a pop-up window, may only be invoked upon user interaction, for example by a mouse click or button press.' - }, - FragmentInputTooLarge: { - code: 2177, - message: 'The Shader input %1 is too large.' - }, - ClipboardConstNotAllowed: { - code: 2178, - message: 'The Clipboard.generalClipboard object must be used instead of creating a new Clipboard.' - }, - ClipboardDisallowedRead: { - code: 2179, - message: 'The Clipboard.generalClipboard object may only be read while processing a flash.events.Event.PASTE event.' - }, - CantMoveAVM1ContentLoadedIntoAVM2: { - code: 2180, - message: 'It is illegal to move AVM1 content (AS1 or AS2) to a different part of the displayList when it has been loaded into AVM2 (AS3) content.' - }, - InvalidTextLineMethodError: { - code: 2181, - message: 'The TextLine class does not implement this property or method.' - }, - PerspectiveFieldOfViewValueInvalid: { - code: 2182, - message: 'Invalid fieldOfView value. The value must be greater than 0 and less than 180.' - }, - Invalid3DScale: { - code: 2183, - message: 'Scale values must not be zero.' - }, - LockedElementFormatError: { - code: 2184, - message: 'The ElementFormat object is locked and cannot be modified.' - }, - LockedFontDescriptionError: { - code: 2185, - message: 'The FontDescription object is locked and cannot be modified.' - }, - PerspectiveFocalLengthInvalid: { - code: 2186, - message: 'Invalid focalLength %1.' - }, - Matrix3DDecomposeTypeInvalid: { - code: 2187, - message: 'Invalid orientation style %1. Value must be one of \'Orientation3D.EULER_ANGLES\', \'Orientation3D.AXIS_ANGLE\', or \'Orientation3D.QUATERNION\'.' - }, - MatrixNonInvertibleError: { - code: 2188, - message: 'Invalid raw matrix. Matrix must be invertible.' - }, - Matrix3DRefCannontBeShared: { - code: 2189, - message: 'A Matrix3D can not be assigned to more than one DisplayObject.' - }, - ForceDownloadSecurityError: { - code: 2190, - message: 'The attempted load of %1 failed as it had a Content-Disposition of attachment set.' - }, - ClipboardDisallowedWrite: { - code: 2191, - message: 'The Clipboard.generalClipboard object may only be written to as the result of user interaction, for example by a mouse click or button press.' - }, - MalformedUnicodeError: { - code: 2192, - message: 'An unpaired Unicode surrogate was encountered in the input.' - }, - SecurityContentAccessDeniedError: { - code: 2193, - message: 'Security sandbox violation: %1: %2 cannot access %3.' - }, - LoaderParamError: { - code: 2194, - message: 'Parameter %1 cannot be a Loader.' - }, - LoaderAsyncError: { - code: 2195, - message: 'Error thrown as Loader called %1.' - }, - ObjectWithStringsParamError: { - code: 2196, - message: 'Parameter %1 must be an Object with only String values.' - }, - SystemUpdaterPlayerNotSupportedError: { - code: 2200, - message: 'The SystemUpdater class is not supported by this player.' - }, - SystemUpdaterOSNotSupportedError: { - code: 2201, - message: 'The requested update type is not supported on this operating system.' - }, - SystemUpdaterBusy: { - code: 2202, - message: 'Only one SystemUpdater action is allowed at a time.' - }, - SystemUpdaterFailed: { - code: 2203, - message: 'The requested SystemUpdater action cannot be completed.' - }, - SystemUpdaterCannotCancel: { - code: 2204, - message: 'This operation cannot be canceled because it is waiting for user interaction.' - }, - SystemUpdaterUnknownTarget: { - code: 2205, - message: 'Invalid update type %1.' - }, - SignedSWfLoadingError: { - code: 2500, - message: 'An error occurred decrypting the signed swf file. The swf will not be loaded.' - }, - NotScreenSharingError: { - code: 2501, - message: 'This property can only be accessed during screen sharing.' - }, - NotSharingMonitorError: { - code: 2502, - message: 'This property can only be accessed if sharing the entire screen.' - }, - FileBadPathName: { - code: 3000, - message: 'Illegal path name.' - }, - FileAccessDenied: { - code: 3001, - message: 'File or directory access denied.' - }, - FileExists: { - code: 3002, - message: 'File or directory exists.' - }, - FileDoesNotExist: { - code: 3003, - message: 'File or directory does not exist.' - }, - FileInsufficientSpace: { - code: 3004, - message: 'Insufficient file space.' - }, - FileSystemResources: { - code: 3005, - message: 'Insufficient system resources.' - }, - FileNotAFile: { - code: 3006, - message: 'Not a file.' - }, - FileNotADir: { - code: 3007, - message: 'Not a directory.' - }, - FileReadOnlyFileSys: { - code: 3008, - message: 'Read-only or write-protected media.' - }, - FileNotSameDevice: { - code: 3009, - message: 'Cannot move file or directory to a different device.' - }, - DirNotEmpty: { - code: 3010, - message: 'Directory is not empty.' - }, - FileDestinationExists: { - code: 3011, - message: 'Move or copy destination already exists.' - }, - FileCantDelete: { - code: 3012, - message: 'Cannot delete file or directory.' - }, - FileInUse: { - code: 3013, - message: 'File or directory is in use.' - }, - FileCopyMoveAncestor: { - code: 3014, - message: 'Cannot copy or move a file or directory to overwrite a containing directory.' - }, - LoadBytesCodeExecutionSecurityError: { - code: 3015, - message: 'Loader.loadBytes() is not permitted to load content with executable code.' - }, - FileApplicationNotFound: { - code: 3016, - message: 'No application was found that can open this file.' - }, - SQLConnectionCannotClose: { - code: 3100, - message: 'A SQLConnection cannot be closed while statements are still executing.' - }, - SQLConnectionAlreadyOpen: { - code: 3101, - message: 'Database connection is already open.' - }, - SQLConnectionInvalidName: { - code: 3102, - message: 'Name argument specified was invalid. It must not be null or empty.' - }, - SQLConnectionInTransaction: { - code: 3103, - message: 'Operation cannot be performed while there is an open transaction on this connection.' - }, - SQLConnectionNotOpen: { - code: 3104, - message: 'A SQLConnection must be open to perform this operation.' - }, - SQLConnectionNoOpenTransaction: { - code: 3105, - message: 'Operation is only allowed if a connection has an open transaction.' - }, - SQLStatementIsExecutingProperty: { - code: 3106, - message: 'Property cannot be changed while SQLStatement.executing is true.' - }, - SQLStatementIvalidCall: { - code: 3107, - message: '%1 may not be called unless SQLResult.complete is false.' - }, - SQLStatementInvalidText: { - code: 3108, - message: 'Operation is not permitted when the SQLStatement.text property is not set.' - }, - SQLStatementInvalidConnection: { - code: 3109, - message: 'Operation is not permitted when the SQLStatement.sqlConnection property is not set.' - }, - SQLStatementIsExecutingCall: { - code: 3110, - message: 'Operation cannot be performed while SQLStatement.executing is true.' - }, - SQLStatementInvalidSchemaType: { - code: 3111, - message: 'An invalid schema type was specified.' - }, - SQLConnectionInvalidLockType: { - code: 3112, - message: 'An invalid transaction lock type was specified.' - }, - SQLConnectionNotFileReference: { - code: 3113, - message: 'Reference specified is not of type File.' - }, - SQLConnectionInvalidModeSpecified: { - code: 3114, - message: 'An invalid open mode was specified.' - }, - SQLGeneralEngineError: { - code: 3115, - message: 'SQL Error.' - }, - SQLInternalEngineError: { - code: 3116, - message: 'An internal logic error occurred.' - }, - SQLPermissionError: { - code: 3117, - message: 'Access permission denied.' - }, - SQLOperationAbortedError: { - code: 3118, - message: 'Operation aborted.' - }, - SQLDatabaseLockedError: { - code: 3119, - message: 'Database file is currently locked.' - }, - SQLTableLockedError: { - code: 3120, - message: 'Table is locked.' - }, - SQLOutOfMemoryError: { - code: 3121, - message: 'Out of memory.' - }, - SQLDatabaseIsReadonlyError: { - code: 3122, - message: 'Attempt to write a readonly database.' - }, - SQLDatabaseCorruptError: { - code: 3123, - message: 'Database disk image is malformed.' - }, - SQLDatabaseFullError: { - code: 3124, - message: 'Insertion failed because database is full.' - }, - SQLCannotOpenDatabaseError: { - code: 3125, - message: 'Unable to open the database file.' - }, - SQLLockingProtocolError: { - code: 3126, - message: 'Database lock protocol error.' - }, - SQLDatabaseEmptyError: { - code: 3127, - message: 'Database is empty.' - }, - SQLDiskIOError: { - code: 3128, - message: 'Disk I/O error occurred.' - }, - SQLSchemaChangedError: { - code: 3129, - message: 'The database schema changed.' - }, - SQLTooMuchDataError: { - code: 3130, - message: 'Too much data for one row of a table.' - }, - SQLConstraintError: { - code: 3131, - message: 'Abort due to constraint violation.' - }, - SQLDataTypeMismatchError: { - code: 3132, - message: 'Data type mismatch.' - }, - SQLConcurrencyError: { - code: 3133, - message: 'An internal error occurred.' - }, - SQLNotSupportedOnOSError: { - code: 3134, - message: 'Feature not supported on this operating system.' - }, - SQLAuthorizationDeniedError: { - code: 3135, - message: 'Authorization denied.' - }, - SQLAuxDatabaseFormatError: { - code: 3136, - message: 'Auxiliary database format error.' - }, - SQLBindingRangeError: { - code: 3137, - message: 'An index specified for a parameter was out of range.' - }, - SQLInvalidDatabaseFileError: { - code: 3138, - message: 'File opened is not a database file.' - }, - SQLInvalidPageSizeError: { - code: 3139, - message: 'The page size specified was not valid for this operation.' - }, - SQLInvalidKeySizeError: { - code: 3140, - message: 'The encryption key size specified was not valid for this operation. Keys must be exactly 16 bytes in length' - }, - SQLInvalidConfigurationError: { - code: 3141, - message: 'The requested database configuration is not supported.' - }, - SQLCannotRekeyNonKeyedDatabase: { - code: 3143, - message: 'Unencrypted databases may not be reencrypted.' - }, - NativeWindowClosedError: { - code: 3200, - message: 'Cannot perform operation on closed window.' - }, - PDFNoReaderInstalled: { - code: 3201, - message: 'Adobe Reader cannot be found.' - }, - PDFOldReaderInstalled: { - code: 3202, - message: 'Adobe Reader 8.1 or later cannot be found.' - }, - PDFOldDefaultText: { - code: 3203, - message: 'Default Adobe Reader must be version 8.1 or later.' - }, - PDFCannotLoadReader: { - code: 3204, - message: 'An error ocurred trying to load Adobe Reader.' - }, - ApplicationFeatureSecurityError: { - code: 3205, - message: 'Only application-sandbox content can access this feature.' - }, - LoaderInfoDoorSecurityError: { - code: 3206, - message: 'Caller %1 cannot set LoaderInfo property %2.' - }, - ApplicationNonFeatureSecurityError: { - code: 3207, - message: 'Application-sandbox content cannot access this feature.' - }, - InvalidClipboardAccess: { - code: 3208, - message: 'Attempt to access invalid clipboard.' - }, - DeadClipboardAccess: { - code: 3209, - message: 'Attempt to access dead clipboard.' - }, - DeadJavaScriptObjectAccess: { - code: 3210, - message: 'The application attempted to reference a JavaScript object in a HTML page that is no longer loaded.' - }, - FilePromiseIOError: { - code: 3211, - message: 'Drag and Drop File Promise error: %1' - }, - NativeProcessNotRunning: { - code: 3212, - message: 'Cannot perform operation on a NativeProcess that is not running.' - }, - NativeProcessAlreadyRunning: { - code: 3213, - message: 'Cannot perform operation on a NativeProcess that is already running.' - }, - NativeProcessBadExecutable: { - code: 3214, - message: 'NativeProcessStartupInfo.executable does not specify a valid executable file.' - }, - NativeProcessBadWorkingDirectory: { - code: 3215, - message: 'NativeProcessStartupInfo.workingDirectory does not specify a valid directory.' - }, - NativeProcessStdOutReadError: { - code: 3216, - message: 'Error while reading data from NativeProcess.standardOutput.' - }, - NativeProcessStdErrReadError: { - code: 3217, - message: 'Error while reading data from NativeProcess.standardError.' - }, - NativeProcessStdInWriteError: { - code: 3218, - message: 'Error while writing data to NativeProcess.standardInput.' - }, - NativeProcessNotStarted: { - code: 3219, - message: 'The NativeProcess could not be started. \'%1\'' - }, - ActionNotAllowedSecurityError: { - code: 3220, - message: 'Action \'%1\' not allowed in current security context \'%2\'.' - }, - SWFNoPlayerInstalled: { - code: 3221, - message: 'Adobe Flash Player cannot be found.' - }, - SWFOldPlayerInstalled: { - code: 3222, - message: 'The installed version of Adobe Flash Player is too old.' - }, - DNSResolverLookupError: { - code: 3223, - message: 'DNS lookup error: platform error %1' - }, - SocketMessageTooLongError: { - code: 3224, - message: 'Socket message too long' - }, - SocketCannotSendDataToAddressAfterConnect: { - code: 3225, - message: 'Cannot send data to a location when connected.' - }, - AllowCodeImportError: { - code: 3226, - message: 'Cannot import a SWF file when LoaderContext.allowCodeImport is false.' - }, - BackgroundLaunchError: { - code: 3227, - message: 'Cannot launch another application from background.' - }, - StageWebViewLoadError: { - code: 3228, - message: 'StageWebView encountered an error during the load operation.' - }, - StageWebViewProtocolNotSupported: { - code: 3229, - message: 'The protocol is not supported.:' - }, - BrowseOperationUnsupported: { - code: 3230, - message: 'The browse operation is unsupported.' - }, - InvalidVoucher: { - code: 3300, - message: 'Voucher is invalid.' - }, - AuthenticationFailed: { - code: 3301, - message: 'User authentication failed.' - }, - RequireSSLError: { - code: 3302, - message: 'Flash Access server does not support SSL.' - }, - ContentExpiredError: { - code: 3303, - message: 'Content expired.' - }, - AuthorizationFailed: { - code: 3304, - message: 'User authorization failed (for example, the user has not purchased the content).' - }, - ServerConnectionFailed: { - code: 3305, - message: 'Can\'t connect to the server.' - }, - ClientUpdateRequired: { - code: 3306, - message: 'Client update required (Flash Access server requires new client).' - }, - InternalError: { - code: 3307, - message: 'Generic internal Flash Access failure.' - }, - WrongVoucherKey: { - code: 3308, - message: 'Wrong voucher key.' - }, - CorruptedFLV: { - code: 3309, - message: 'Video content is corrupted.' - }, - AppIDMismatch: { - code: 3310, - message: 'The AIR application or Flash Player SWF does not match the one specified in the DRM policy.' - }, - AppVersionMismatch: { - code: 3311, - message: 'The version of the application does not match the one specified in the DRM policy.' - }, - VoucherIntegrityError: { - code: 3312, - message: 'Verification of voucher failed.' - }, - WriteFileSystemFailed: { - code: 3313, - message: 'Write to the file system failed.' - }, - FLVHeaderIntegrityFailed: { - code: 3314, - message: 'Verification of FLV/F4V header file failed.' - }, - PermissionDenied: { - code: 3315, - message: 'The current security context does not allow this operation.' - }, - LocalConnectionUserScopedLocked: { - code: 3316, - message: 'The value of LocalConnection.isPerUser cannot be changed because it has already been locked by a call to LocalConnection.connect, .send, or .close.' - }, - LoadAdobeCPFailed: { - code: 3317, - message: 'Failed to load Flash Access module.' - }, - IncompatibleAdobeCPVersion: { - code: 3318, - message: 'Incompatible version of Flash Access module found.' - }, - MissingAdobeCPEntryPoint: { - code: 3319, - message: 'Missing Flash Access module API entry point.' - }, - InternalErrorHA: { - code: 3320, - message: 'Generic internal Flash Access failure.' - }, - IndividualizationFailed: { - code: 3321, - message: 'Individualization failed.' - }, - DeviceBindingFailed: { - code: 3322, - message: 'Device binding failed.' - }, - CorruptStore: { - code: 3323, - message: 'The internal stores are corrupted.' - }, - MachineTokenInvalid: { - code: 3324, - message: 'Reset license files and the client will fetch a new machine token.' - }, - CorruptServerStateStore: { - code: 3325, - message: 'Internal stores are corrupt.' - }, - TamperingDetected: { - code: 3326, - message: 'Call customer support.' - }, - ClockTamperingDetected: { - code: 3327, - message: 'Clock tampering detected.' - }, - ServerErrorTryAgain: { - code: 3328, - message: 'Server error; retry the request.' - }, - ApplicationSpecificError: { - code: 3329, - message: 'Error in application-specific namespace.' - }, - NeedAuthentication: { - code: 3330, - message: 'Need to authenticate the user and reacquire the voucher.' - }, - ContentNotYetValid: { - code: 3331, - message: 'Content is not yet valid.' - }, - CachedVoucherExpired: { - code: 3332, - message: 'Cached voucher has expired. Reacquire the voucher from the server.' - }, - PlaybackWindowExpired: { - code: 3333, - message: 'The playback window for this policy has expired.' - }, - InvalidDRMPlatform: { - code: 3334, - message: 'This platform is not allowed to play this content.' - }, - InvalidDRMVersion: { - code: 3335, - message: 'Invalid version of Flash Access module. Upgrade AIR or Flash Access module for the Flash Player.' - }, - InvalidRuntimePlatform: { - code: 3336, - message: 'This platform is not allowed to play this content.' - }, - InvalidRuntimeVersion: { - code: 3337, - message: 'Upgrade Flash Player or AIR and retry playback.' - }, - UnknownConnectionType: { - code: 3338, - message: 'Unknown connection type.' - }, - NoAnalogPlaybackAllowed: { - code: 3339, - message: 'Can\'t play back on analog device. Connect to a digital device.' - }, - NoAnalogProtectionAvail: { - code: 3340, - message: 'Can\'t play back because connected analog device doesn\'t have the correct capabilities.' - }, - NoDigitalPlaybackAllowed: { - code: 3341, - message: 'Can\'t play back on digital device.' - }, - NoDigitalProtectionAvail: { - code: 3342, - message: 'The connected digital device doesn\'t have the correct capabilities.' - }, - InternalErrorIV: { - code: 3343, - message: 'Internal Error.' - }, - MissingAdobeCPModule: { - code: 3344, - message: 'Missing Flash Access module.' - }, - DRMNoAccessError: { - code: 3345, - message: 'This operation is not permitted with content protected using Flash Access.' - }, - DRMDataMigrationFailed: { - code: 3346, - message: 'Failed migrating local DRM data, all locally cached DRM vouchers are lost.' - }, - DRMInsufficientDeviceCapabilites: { - code: 3347, - message: 'The device does not meet the Flash Access server\'s playback device constraints.' - }, - DRMHardStopIntervalExpired: { - code: 3348, - message: 'This protected content is expired.' - }, - DRMServerVersionTooHigh: { - code: 3349, - message: 'The Flash Access server is running at a version that\'s higher than the max supported by this runtime.' - }, - DRMServerVersionTooLow: { - code: 3350, - message: 'The Flash Access server is running at a version that\'s lower than the min supported by this runtime.' - }, - DRMDeviceGroupTokenInvalid: { - code: 3351, - message: 'Device Group registration token is corrupted, please refresh the token by registering again to the DRMDeviceGroup.' - }, - DRMDeviceGroupTokenTooOld: { - code: 3352, - message: 'The server is using a newer version of the registration token for this Device Group. Please refresh the token by registering again to the DRMDeviceGroup.' - }, - DRMDeviceGroupTokenTooNew: { - code: 3353, - message: 'the server is using an older version of the registration token for this Device Group.' - }, - DRMDeviceGroupTokenExpired: { - code: 3354, - message: 'Device Group registration is expired, please refresh the token by registering again to the DRMDeviceGroup.' - }, - JoinDRMDeviceGroupFailed: { - code: 3355, - message: 'The server denied this Device Group registration request.' - }, - DRMVoucherHasNoCorrespondingRoot: { - code: 3356, - message: 'The root voucher for this content\'s DRMVoucher was not found.' - }, - NoValidEmbeddedDRMVoucher: { - code: 3357, - message: 'The DRMContentData provides no valid embedded voucher and no Flash Access server url to acquire the voucher from.' - }, - NoACPProtectionAvailable: { - code: 3358, - message: 'ACP protection is not available on the device but required to playback the content.' - }, - NoCGMSAProtectionAvailable: { - code: 3359, - message: 'CGMSA protection is not available on the device but required to playback the content.' - }, - DRMDeviceGroupRegistrationRequired: { - code: 3360, - message: 'Device Group registration is required before doing this operation.' - }, - DeviceIsNotRegisteredToDRMDeviceGroup: { - code: 3361, - message: 'The device is not registered to this Device Group.' - }, - ScriptBridgeError: { - code: 3400, - message: 'An error occured while executing JavaScript code.' - }, - ScriptBridgeNameAccessSecurityError: { - code: 3401, - message: 'Security sandbox violation: An object with this name has already been registered from another security domain.' - }, - ScriptBridgeBrowserAccessSecurityError: { - code: 3402, - message: 'Security sandbox violation: Bridge caller %1 cannot access %2.' - }, - ExtensionContextNoSuchMethod: { - code: 3500, - message: 'The extension context does not have a method with the name %1.' - }, - ExtensionContextAlreadyDisposed: { - code: 3501, - message: 'The extension context has already been disposed.' - }, - ExtensionContextInvalidReturnValue: { - code: 3502, - message: 'The extension returned an invalid value.' - }, - ExtensionContextInvalidState: { - code: 3503, - message: 'The extension was left in an invalid state.' - }, - NoValidProgramSet: { - code: 3600, - message: 'No valid program set.' - }, - NoValidIndexBufferSet: { - code: 3601, - message: 'No valid index buffer set.' - }, - SanityCheckOnParametersFailed: { - code: 3602, - message: 'Sanity check on parameters failed, %1 triangles and %2 index offset.' - }, - NotEnoughIndicesInThisBuffer: { - code: 3603, - message: 'Not enough indices in this buffer. %1 triangles at offset %2, but there are only %3 indices in buffer.' - }, - SampleBindsTextureAlsoBoundToRender: { - code: 3604, - message: 'Sampler %1 binds a texture that is also bound for render to texture.' - }, - SampleBindsInvalidTexture: { - code: 3605, - message: 'Sampler %1 binds an invalid texture.' - }, - SamplerFormatDoesNotMatchTextureFormat: { - code: 3606, - message: 'Sampler %1 format does not match texture format.' - }, - StreamIsNotUsed: { - code: 3607, - message: 'Stream %1 is set but not used by the current vertex program.' - }, - StreamIsInvalid: { - code: 3608, - message: 'Stream %1 is invalid.' - }, - StreamDoesNotHaveEnoughVertices: { - code: 3609, - message: 'Stream %1 does not have enough vertices.' - }, - StreamVertexOffsetOutOfBounds: { - code: 3610, - message: 'Stream %1 vertex offset is out of bounds' - }, - StreamReadButNotSet: { - code: 3611, - message: 'Stream %1 is read by the current vertex program but not set.' - }, - ProgramMustBeLittleEndian: { - code: 3612, - message: 'Programs must be in little endian format.' - }, - NativeShaderCompilationFailed: { - code: 3613, - message: 'The native shader compilation failed.' - }, - NativeShaderCompilationFailedOpenGL: { - code: 3614, - message: 'The native shader compilation failed.enGL specific: %1' - }, - AgalProgramTooSmall: { - code: 3615, - message: 'AGAL validation failed: Program size below minimum length for %1 program.' - }, - NotAnAgalProgram: { - code: 3616, - message: 'AGAL validation failed: Not an AGAL program. Wrong magic byte for %1 program.' - }, - BadAgalVersion: { - code: 3617, - message: 'AGAL validation failed: Bad AGAL version for %1 program. Current version is %2.' - }, - BadAgalProgramType: { - code: 3618, - message: 'AGAL validation failed: Bad AGAL program type identifier for %1 program.' - }, - BadAgalShadertype: { - code: 3619, - message: 'AGAL validation failed: Shader type must be either fragment or vertex for %1 program.' - }, - InvalidAgalOpcodeOutOfRange: { - code: 3620, - message: 'AGAL validation failed: Invalid opcode, value out of range: %2 at token %3 of %1 program.' - }, - InvalidAgalOpcodeNotImplemented: { - code: 3621, - message: 'AGAL validation failed: Invalid opcode, %2 is not implemented in this version at token %3 of %1 program.' - }, - AgalOpcodeOnlyAllowedInFragmentProgram: { - code: 3622, - message: 'AGAL validation failed: Opcode %2 only allowed in fragment programs at token %3 of %1 program.' - }, - OpenConditionNesting: { - code: 3623, - message: 'AGAL validation failed: Open condition nesting (close without open) at token %2 of %1 program.' - }, - ConditionNestingTooDeep: { - code: 3624, - message: 'AGAL validation failed: Condition nesting (%2) too deep at token %3 of %1 program.' - }, - BadAgalSourceOperands: { - code: 3625, - message: 'AGAL validation failed: Bad AGAL source operands. Both are constants (this must be precomputed) at token %2 of %1 program.' - }, - BothOperandsAreIndirectReads: { - code: 3626, - message: 'AGAL validation failed: Opcode %2, both operands are indirect reads at token %3 of %1 program.' - }, - OpcodeDestinationMustBeAllZero: { - code: 3627, - message: 'AGAL validation failed: Opcode %2 destination operand must be all zero at token %3 of %1 program.' - }, - OpcodeDestinationMustUseMask: { - code: 3628, - message: 'AGAL validation failed: The destination operand for the %2 instruction must mask w (use .xyz or less) at token %3 of %1 program.' - }, - TooManyTokens: { - code: 3629, - message: 'AGAL validation failed: Too many tokens (%2) for %1 program.' - }, - FragmentShaderType: { - code: 3630, - message: 'Fragment shader type is not fragment.' - }, - VertexShaderType: { - code: 3631, - message: 'Vertex shader type is not vertex.' - }, - VaryingReadButNotWrittenTo: { - code: 3632, - message: 'AGAL linkage: Varying %1 is read in the fragment shader but not written to by the vertex shader.' - }, - VaryingPartialWrite: { - code: 3633, - message: 'AGAL linkage: Varying %1 is only partially written to. Must write all four components.' - }, - FragmentWriteAllComponents: { - code: 3634, - message: 'AGAL linkage: Fragment output needs to write to all components.' - }, - VertexWriteAllComponents: { - code: 3635, - message: 'AGAL linkage: Vertex output needs to write to all components.' - }, - UnusedOperand: { - code: 3636, - message: 'AGAL validation failed: Unused operand is not set to zero for %2 at token %3 of %1 program.' - }, - SamplerRegisterOnlyInFragment: { - code: 3637, - message: 'AGAL validation failed: Sampler registers only allowed in fragment programs for %2 at token %3 of %1 program.' - }, - SamplerRegisterSecondOperand: { - code: 3638, - message: 'AGAL validation failed: Sampler register only allowed as second operand in texture instructions for %2 at token %3 of %1 program.' - }, - IndirectOnlyAllowedInVertex: { - code: 3639, - message: 'AGAL validation failed: Indirect addressing only allowed in vertex programs for %2 at token %3 of %1 program.' - }, - IndirectOnlyIntoConstantRegisters: { - code: 3640, - message: 'AGAL validation failed: Indirect addressing only allowed into constant registers for %2 at token %3 of %1 program.' - }, - IndirectNotAllowed: { - code: 3641, - message: 'AGAL validation failed: Indirect addressing not allowed for this operand in this instruction for %2 at token %3 of %1 program.' - }, - IndirectSourceType: { - code: 3642, - message: 'AGAL validation failed: Indirect source type must be attribute, constant or temporary for %2 at token %3 of %1 program.' - }, - IndirectAddressingFieldsMustBeZero: { - code: 3643, - message: 'AGAL validation failed: Indirect addressing fields must be zero for direct adressing for %2 at token %3 of %1 program.' - }, - VaryingRegistersOnlyReadInFragment: { - code: 3644, - message: 'AGAL validation failed: Varying registers can only be read in fragment programs for %2 at token %3 of %1 program.' - }, - AttributeRegistersOnlyReadInVertex: { - code: 3645, - message: 'AGAL validation failed: Attribute registers can only be read in vertex programs for %2 at token %3 of %1 program.' - }, - CanNotReadOutputRegister: { - code: 3646, - message: 'AGAL validation failed: Can not read from output register for %2 at token %3 of %1 program.' - }, - TempRegisterReadWithoutWrite: { - code: 3647, - message: 'AGAL validation failed: Temporary register read without being written to for %2 at token %3 of %1 program.' - }, - TempRegisterComponentReadWithoutWrite: { - code: 3648, - message: 'AGAL validation failed: Temporary register component read without being written to for %2 at token %3 of %1 program.' - }, - SamplerRegisterCannotBeWrittenTo: { - code: 3649, - message: 'AGAL validation failed: Sampler registers can not be written to for %2 at token %3 of %1 program.' - }, - VaryingRegistersWrite: { - code: 3650, - message: 'AGAL validation failed: Varying registers can only be written in vertex programs for %2 at token %3 of %1 program.' - }, - AttributeRegisterCannotBeWrittenTo: { - code: 3651, - message: 'AGAL validation failed: Attribute registers can not be written to for %2 at token %3 of %1 program.' - }, - ConstantRegisterCannotBeWrittenTo: { - code: 3652, - message: 'AGAL validation failed: Constant registers can not be written to for %2 at token %3 of %1 program.' - }, - DestinationWritemaskIsZero: { - code: 3653, - message: 'AGAL validation failed: Destination writemask is zero for %2 at token %3 of %1 program.' - }, - AGALReservedBitsShouldBeZero: { - code: 3654, - message: 'AGAL validation failed: Reserve bits should be zero for %2 at token %3 of %1 program.' - }, - UnknownRegisterType: { - code: 3655, - message: 'AGAL validation failed: Unknown register type for %2 at token %3 of %1 program.' - }, - SamplerRegisterOutOfBounds: { - code: 3656, - message: 'AGAL validation failed: Sampler register index out of bounds for %2 at token %3 of %1 program.' - }, - VaryingRegisterOutOfBounds: { - code: 3657, - message: 'AGAL validation failed: Varying register index out of bounds for %2 at token %3 of %1 program.' - }, - AttributeRegisterOutOfBounds: { - code: 3658, - message: 'AGAL validation failed: Attribute register index out of bounds for %2 at token %3 of %1 program.' - }, - ConstantRegisterOutOfBounds: { - code: 3659, - message: 'AGAL validation failed: Constant register index out of bounds for %2 at token %3 of %1 program.' - }, - OutputRegisterOutOfBounds: { - code: 3660, - message: 'AGAL validation failed: Output register index out of bounds for %2 at token %3 of %1 program.' - }, - TemporaryRegisterOutOfBounds: { - code: 3661, - message: 'AGAL validation failed: Temporary register index out of bounds for %2 at token %3 of %1 program.' - }, - CubeMapSamplerMustUseClamp: { - code: 3662, - message: 'AGAL validation failed: Cube map samplers must set wrapping to clamp mode for %2 at token %3 of %1 program.' - }, - SampleBindsUndefinedTexture: { - code: 3663, - message: 'Sampler %1 binds an undefined texture.' - }, - UnknownSamplerDimension: { - code: 3664, - message: 'AGAL validation failed: Unknown sampler dimension %4 for %2 at token %3 of %1 program.' - }, - UnknownFilterMode: { - code: 3665, - message: 'AGAL validation failed: Unknown filter mode in sampler: %4 for %2 at token %3 of %1 program.' - }, - UnknownMipmapMode: { - code: 3666, - message: 'AGAL validation failed: Unknown mipmap mode in sampler: %4 for %2 at token %3 of %1 program.' - }, - UnknownWrappingMode: { - code: 3667, - message: 'AGAL validation failed: Unknown wrapping mode in sampler: %4 for %2 at token %3 of %1 program.' - }, - UnknownSpecialFlag: { - code: 3668, - message: 'AGAL validation failed: Unknown special flag used in sampler: %4 for %2 at token %3 of %1 program.' - }, - BadInputSize: { - code: 3669, - message: 'Bad input size.' - }, - BufferTooBig: { - code: 3670, - message: 'Buffer too big.' - }, - BufferHasZeroSize: { - code: 3671, - message: 'Buffer has zero size.' - }, - BufferCreationFailed: { - code: 3672, - message: 'Buffer creation failed. Internal error.' - }, - InvalidCubeSide: { - code: 3673, - message: 'Cube side must be [0..5].' - }, - MiplevelTooLarge: { - code: 3674, - message: 'Miplevel too large.' - }, - TextureFormatMismatch: { - code: 3675, - message: 'Texture format mismatch.' - }, - PlatformDoesNotSupportTextureFormat: { - code: 3676, - message: 'Platform does not support desired texture format.' - }, - TextureDecodingFailed: { - code: 3677, - message: 'Texture decoding failed. Internal error.' - }, - TextureNeedsToBeSquare: { - code: 3678, - message: 'Texture needs to be square.' - }, - TextureSizeDoesNotMatch: { - code: 3679, - message: 'Texture size does not match.' - }, - DepthTextureNotImplemented: { - code: 3680, - message: 'Depth texture not implemented yet.' - }, - TextureSizeIsZero: { - code: 3681, - message: 'Texture size is zero.' - }, - TextureNotPowerOfTwo: { - code: 3682, - message: 'Texture size not a power of two.' - }, - TextureTooBig: { - code: 3683, - message: 'Texture too big (max is 2048x2048).' - }, - TextureCreationFailed: { - code: 3684, - message: 'Texture creation failed. Internal error.' - }, - CouldNotCreateRenderer: { - code: 3685, - message: 'Could not create renderer.' - }, - DisabledFormatNeedsNullVertexBuffer: { - code: 3686, - message: '\'disabled\' format only valid with a null vertex buffer.' - }, - NullVertexBufferNeedsDisabledFormat: { - code: 3687, - message: 'Null vertex buffers require the \'disabled\' format.' - }, - NeedListenerToRequestContext: { - code: 3688, - message: 'You must add an event listener for the context3DCreate event before requesting a new Context3D.' - }, - CantSwizzle2ndSource: { - code: 3689, - message: 'You can not swizzle second operand for %2 at token %3 of %1 program.' - }, - TooManyDrawCalls: { - code: 3690, - message: 'Too many draw calls before calling present.' - }, - ResourceLimitExceeded: { - code: 3691, - message: 'Resource limit for this resource type exceeded.' - }, - NeedToClearBeforeDraw: { - code: 3692, - message: 'All buffers need to be cleared every frame before drawing.' - }, - SecondOperandMustBeSamplerRegister: { - code: 3693, - message: 'AGAL validation failed: Sampler register must be used for second operand in texture instructions for %2 at token %3 of %1 program.' - }, - ObjectDisposed: { - code: 3694, - message: 'The object was disposed by an earlier call of dispose() on it.' - }, - SameTextureNeedsSameSamplerParams: { - code: 3695, - message: 'A texture can only be bound to multiple samplers if the samplers also have the exact same properties. Mismatch at samplers %1 and %2.' - }, - SecondUseOfSamplerMustHaveSameParams: { - code: 3696, - message: 'AGAL validation failed: Second use of sampler register needs to specify the exact same properties. At token %3 of %1 program.' - }, - TextureBoundButNotUsed: { - code: 3697, - message: 'A texture is bound on sampler %1 but not used by the fragment program.' - }, - BackBufferNotConfigured: { - code: 3698, - message: 'The back buffer is not configured.' - }, - OperationFailed: { - code: 3699, - message: 'Requested Operation failed to complete' - }, - TextureMipchainIsNotComplete: { - code: 3700, - message: 'A texture sampler binds an incomplete texture. Make sure to upload(). All miplevels are required when mipmapping is enabled.' - }, - OutputColorNotMaskable: { - code: 3701, - message: 'The output color register can not use a write mask. All components must be written.' - }, - Context3DNotAvailable: { - code: 3702, - message: 'Context3D not available.' - }, - SwizzleMustBeScalar: { - code: 3703, - message: 'AGAL validation failed: Source swizzle must be scalar (one of: xxxx, yyyy, zzzz, wwww) for %2 at token %3 of %1 program.' - }, - CubeMapSamplerMustUseMipmap: { - code: 3704, - message: 'AGAL validation failed: Cube map samplers must enable mipmapping for %2 at token %3 of %1 program.' } }; function getErrorMessage(index) { @@ -12874,22 +11511,22 @@ var opcodeTable = [ null ]; (function processOpcodeTable() { - function splitter(value) { - var list = value.split(':'); - return { - name: list[0], - size: list[1].substring(0, 3), - type: list[1].substring(3) - }; - } for (var i = 0; i < opcodeTable.length; i++) { var entry = opcodeTable[i]; if (entry && entry.operands !== null) { - if (entry.operands === '') { - entry.operands = []; - } else { - entry.operands = entry.operands.split(',').map(splitter); + var result = []; + if (entry.operands !== '') { + var operands = entry.operands.split(','); + for (var j = 0; j < operands.length; j++) { + var list = operands[j].split(':'); + result.push({ + name: list[0], + size: list[1].substring(0, 3), + type: list[1].substring(3) + }); + } } + entry.operands = result; } } }()); @@ -13355,7 +11992,7 @@ var Multiname = function () { multiname.parse = function parse(constantPool, stream, multinames, patchFactoryTypes) { var index = 0; var kind = stream.readU8(); - var name, namespaces = [], flags = 0, typeParameter; + var name, namespaces = [], flags = 0; switch (kind) { case CONSTANT_QName: case CONSTANT_QNameA: @@ -13424,7 +12061,6 @@ var Multiname = function () { }); } return mn; - break; default: unexpected(); break; @@ -13708,6 +12344,7 @@ var ConstantPool = function constantPool() { for (i = 1; i < n; ++i) { doubles.push(stream.readDouble()); } + Timer.start('Parse Strings'); var strings = [ '' ]; @@ -13716,10 +12353,12 @@ var ConstantPool = function constantPool() { strings.push(stream.readUTFString(stream.readU30())); } this.positionAfterUTFStrings = stream.pos; + Timer.stop(); this.ints = ints; this.uints = uints; this.doubles = doubles; this.strings = strings; + Timer.start('Parse Namespaces'); var namespaces = [ undefined ]; @@ -13729,6 +12368,8 @@ var ConstantPool = function constantPool() { namespace.parse(this, stream); namespaces.push(namespace); } + Timer.stop(); + Timer.start('Parse Namespace Sets'); var namespaceSets = [ undefined ]; @@ -13742,8 +12383,10 @@ var ConstantPool = function constantPool() { } namespaceSets.push(set); } + Timer.stop(); this.namespaces = namespaces; this.namespaceSets = namespaceSets; + Timer.start('Parse Multinames'); var multinames = [ undefined ]; @@ -13752,12 +12395,7 @@ var ConstantPool = function constantPool() { for (i = 1; i < n; ++i) { multinames.push(Multiname.parse(this, stream, multinames, patchFactoryTypes)); } - patchFactoryTypes.forEach(function (patch) { - var multiname = multinames[patch.index]; - true; - patch.multiname.name = multiname.name; - patch.multiname.namespaces = multiname.namespaces; - }); + Timer.stop(); this.multinames = multinames; } constantPool.prototype.getValue = function getValue(kind, index) { @@ -14053,41 +12691,55 @@ var ScriptInfo = function scriptInfo() { }(); var AbcFile = function () { function abcFile(bytes, name) { - console.time('Parse ABC: ' + name); + Timer.start('Parse ABC'); this.name = name; var n, i; var stream = new AbcStream(bytes); checkMagic(stream); + Timer.start('Parse constantPool'); this.constantPool = new ConstantPool(stream, name); + Timer.stop(); + Timer.start('Parse Method Infos'); this.methods = []; n = stream.readU30(); for (i = 0; i < n; ++i) { this.methods.push(new MethodInfo(this, stream)); } + Timer.stop(); + Timer.start('Parse MetaData Infos'); this.metadata = []; n = stream.readU30(); for (i = 0; i < n; ++i) { this.metadata.push(new MetaDataInfo(this, stream)); } + Timer.stop(); + Timer.start('Parse Instance Infos'); this.instances = []; n = stream.readU30(); for (i = 0; i < n; ++i) { this.instances.push(new InstanceInfo(this, stream)); } + Timer.stop(); + Timer.start('Parse Class Infos'); this.classes = []; for (i = 0; i < n; ++i) { this.classes.push(new ClassInfo(this, this.instances[i], stream)); } + Timer.stop(); + Timer.start('Parse Script Infos'); this.scripts = []; n = stream.readU30(); for (i = 0; i < n; ++i) { this.scripts.push(new ScriptInfo(this, i, stream)); } + Timer.stop(); + Timer.start('Parse Method Body Info'); n = stream.readU30(); for (i = 0; i < n; ++i) { MethodInfo.parseBody(this, stream); } - console.timeEnd('Parse ABC: ' + name); + Timer.stop(); + Timer.stop(); } function checkMagic(stream) { var magic = stream.readWord(); @@ -17386,6 +16038,9 @@ var TraitsType = function () { if (mn instanceof MultinameType) { return null; } + if (mn.isAttribute()) { + return null; + } if (followSuperType && (this.isInstanceInfo() || this.isClassInfo())) { var that = this; do { @@ -17614,7 +16269,7 @@ var Verifier = function () { function verification(methodInfo, scope) { this.scope = scope; this.methodInfo = methodInfo; - this.domain = methodInfo.abc.domain; + this.domain = methodInfo.abc.applicationDomain; this.writer = new IndentingWriter(); this.returnType = Type.Undefined; } @@ -17702,7 +16357,7 @@ var Verifier = function () { var scope = state.scope; var writer = verifierTraceLevel.value ? this.writer : null; var bytecodes = this.methodInfo.analysis.bytecodes; - var domain = this.methodInfo.abc.domain; + var domain = this.methodInfo.abc.applicationDomain; var multinames = this.methodInfo.abc.constantPool.multinames; var mi = this.methodInfo; var bc, obj, fn, mn, l, r, val, type, returnType; @@ -17754,7 +16409,9 @@ var Verifier = function () { } var trait = classType.getTrait(mn, false, true); if (trait) { - ti().object = LazyInitializer.create(classType.object); + if (!mi.isInstanceInitializer) { + ti().object = LazyInitializer.create(classType.object); + } return classType; } } @@ -17876,6 +16533,7 @@ var Verifier = function () { mn = popMultiname(); obj = pop(); true; + ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); push(getProperty(obj.super(), mn)); break; case 5: @@ -17883,6 +16541,7 @@ var Verifier = function () { mn = popMultiname(); obj = pop(); true; + ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); setProperty(obj.super(), mn, val); break; case 6: @@ -18032,20 +16691,19 @@ var Verifier = function () { notImplemented(bc); break; case 69: - stack.popMany(bc.argCount); - mn = popMultiname(); - obj = pop(); - getProperty(obj, mn); - push(Type.Any); - break; + case 78: case 79: case 70: case 76: stack.popMany(bc.argCount); mn = popMultiname(); obj = pop(); + if (op === OP_callsuper || op === OP_callsupervoid) { + obj = this.thisType.super(); + ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); + } type = getProperty(obj, mn); - if (op === OP_callpropvoid) { + if (op === OP_callpropvoid || op === OP_callsupervoid) { break; } if (type instanceof MethodType) { @@ -18091,11 +16749,6 @@ var Verifier = function () { case 77: notImplemented(bc); break; - case 78: - stack.popMany(bc.argCount); - popMultiname(); - pop(); - break; case 80: case 81: case 82: @@ -18156,11 +16809,7 @@ var Verifier = function () { local[bc.index] = pop(); break; case 100: - if (savedScope.object) { - push(Type.from(savedScope.global.object)); - } else { - push(Type.Any); - } + push(Type.from(savedScope.global.object)); break; case 101: push(scope[bc.index]); @@ -18514,6 +17163,11 @@ var Verifier = function () { assert: '', internal: true } + }, + ASCallSuper: { + scope: { + assert: '' + } } }, New: { @@ -18541,7 +17195,12 @@ var Verifier = function () { }, ASGetDescendants: {}, ASHasProperty: {}, - ASGetSlot: {} + ASGetSlot: {}, + ASGetSuper: { + scope: { + assert: '' + } + } }, SetProperty: { object: { @@ -18558,7 +17217,12 @@ var Verifier = function () { internal: true } }, - ASSetSlot: {} + ASSetSlot: {}, + ASSetSuper: { + scope: { + assert: '' + } + } }, DeleteProperty: { object: { @@ -18799,7 +17463,7 @@ var Verifier = function () { writer.writeLn('this.id = nextID[nextID.length - 1] += 1;'); writer.leave('}'); if (path.length > 1) { - writer.writeLn(prototypeName + ' = ' + 'extend(' + path[path.length - 2]._name + ', "' + node._name + '")'); + writer.writeLn(prototypeName + ' = ' + 'extend(' + path[path.length - 2]._name + ', "' + node._name + '");'); } writer.writeLn(prototypeName + '.nodeName = "' + node._name + '";'); writer.enter(prototypeName + '.visitInputs = function (visitor) {'); @@ -19096,6 +17760,39 @@ var Verifier = function () { }; return asCallPropertyNode; }(); + var ASCallSuper = function () { + function asCallSuperNode(control, store, object, name, args, flags, scope) { + true; + true; + true; + true; + true; + true; + true; + true; + this.control = control; + this.store = store; + this.loads = undefined; + this.object = object; + this.name = name; + this.args = args; + this.flags = flags; + this.scope = scope; + this.id = nextID[nextID.length - 1] += 1; + } + asCallSuperNode.prototype = extend(CallProperty, 'ASCallSuper'); + asCallSuperNode.prototype.nodeName = 'ASCallSuper'; + asCallSuperNode.prototype.visitInputs = function (visitor) { + this.control && visitor(this.control); + this.store && visitor(this.store); + this.loads && visitArrayInputs(this.loads, visitor); + visitor(this.object); + visitor(this.name); + visitArrayInputs(this.args, visitor); + visitor(this.scope); + }; + return asCallSuperNode; + }(); var New = function () { function newNode(control, store, callee, args) { true; @@ -19273,6 +17970,34 @@ var Verifier = function () { }; return asGetSlotNode; }(); + var ASGetSuper = function () { + function asGetSuperNode(control, store, object, name, scope) { + true; + true; + true; + true; + true; + true; + this.control = control; + this.store = store; + this.loads = undefined; + this.object = object; + this.name = name; + this.scope = scope; + this.id = nextID[nextID.length - 1] += 1; + } + asGetSuperNode.prototype = extend(GetProperty, 'ASGetSuper'); + asGetSuperNode.prototype.nodeName = 'ASGetSuper'; + asGetSuperNode.prototype.visitInputs = function (visitor) { + this.control && visitor(this.control); + this.store && visitor(this.store); + this.loads && visitArrayInputs(this.loads, visitor); + visitor(this.object); + visitor(this.name); + visitor(this.scope); + }; + return asGetSuperNode; + }(); var SetProperty = function () { function setPropertyNode(control, store, object, name, value) { true; @@ -19358,6 +18083,37 @@ var Verifier = function () { }; return asSetSlotNode; }(); + var ASSetSuper = function () { + function asSetSuperNode(control, store, object, name, value, scope) { + true; + true; + true; + true; + true; + true; + true; + this.control = control; + this.store = store; + this.loads = undefined; + this.object = object; + this.name = name; + this.value = value; + this.scope = scope; + this.id = nextID[nextID.length - 1] += 1; + } + asSetSuperNode.prototype = extend(SetProperty, 'ASSetSuper'); + asSetSuperNode.prototype.nodeName = 'ASSetSuper'; + asSetSuperNode.prototype.visitInputs = function (visitor) { + this.control && visitor(this.control); + this.store && visitor(this.store); + this.loads && visitArrayInputs(this.loads, visitor); + visitor(this.object); + visitor(this.name); + visitor(this.value); + visitor(this.scope); + }; + return asSetSuperNode; + }(); var DeleteProperty = function () { function deletePropertyNode(control, store, object, name) { true; @@ -21051,11 +19807,14 @@ var Verifier = function () { exports.SetProperty = SetProperty; exports.CallProperty = CallProperty; exports.ASCallProperty = ASCallProperty; + exports.ASCallSuper = ASCallSuper; exports.ASGetProperty = ASGetProperty; + exports.ASGetSuper = ASGetSuper; exports.ASHasProperty = ASHasProperty; exports.ASDeleteProperty = ASDeleteProperty; exports.ASGetDescendants = ASGetDescendants; exports.ASSetProperty = ASSetProperty; + exports.ASSetSuper = ASSetSuper; exports.ASGetSlot = ASGetSlot; exports.ASSetSlot = ASSetSlot; exports.Call = Call; @@ -21260,8 +20019,8 @@ var createName = function createName(namespaces, name) { node.mustFloat = true; return node; } - function warn(message) { - console.warn(message); + function info(message) { + console.info(message); } function unary(operator, argument) { var node = new Unary(operator, argument); @@ -21403,7 +20162,7 @@ var createName = function createName(namespaces, name) { local = coercer(local); } else if (c4CoerceNonPrimitiveParameters) { local = new Call(start, state.store, globalProperty('asCoerceByMultiname'), null, [ - constant(this.abc.domain), + constant(this.abc.applicationDomain), constant(parameter.type), local ], true); @@ -21425,7 +20184,7 @@ var createName = function createName(namespaces, name) { var methods = this.abc.methods; var classes = this.abc.classes; var multinames = this.abc.constantPool.multinames; - var domain = new Constant(this.abc.domain); + var domain = new Constant(this.abc.applicationDomain); var traceBuilder = c4TraceLevel.value > 2; var stopPoints = []; for (var i = 0; i < blocks.length; i++) { @@ -21566,7 +20325,7 @@ var createName = function createName(namespaces, name) { if (ti) { if (ti.object) { if (ti.object instanceof Global && !ti.object.isExecuting()) { - warn('Can\'t optimize findProperty ' + multiname + ', global object is not yet executed or executing.'); + info('Can\'t optimize findProperty ' + multiname + ', global object is not yet executed or executing.'); return slowPath; } return constant(ti.object); @@ -21574,7 +20333,7 @@ var createName = function createName(namespaces, name) { return getScopeObject(topScope(ti.scopeDepth)); } } - warn('Can\'t optimize findProperty ' + multiname); + info('Can\'t optimize findProperty ' + multiname); return slowPath; } function getJSProperty(object, path) { @@ -21630,6 +20389,32 @@ var createName = function createName(namespaces, name) { } return GlobalMultinameResolver.resolveMultiname(new Multiname(namespaces.value, name.value, multiname.flags)); } + function callSuper(scope, object, multiname, args, ti) { + if (ti && ti.trait && ti.trait.isMethod() && ti.baseClass) { + var qn = VM_OPEN_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); + var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); + return call(callee, object, args); + } + return store(new IR.ASCallSuper(region, state.store, object, multiname, args, IR.Flags.PRISTINE, scope)); + } + function getSuper(scope, object, multiname, ti) { + if (ti && ti.trait && ti.trait.isGetter() && ti.baseClass) { + var qn = VM_OPEN_GET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); + var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); + return call(callee, object, []); + } + return store(new IR.ASGetSuper(region, state.store, object, multiname, scope)); + } + function setSuper(scope, object, multiname, value, ti) { + if (ti && ti.trait && ti.trait.isSetter() && ti.baseClass) { + var qn = VM_OPEN_SET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); + var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); + return call(callee, object, [ + value + ]); + } + return store(new IR.ASSetSuper(region, state.store, object, multiname, value, scope)); + } function callProperty(object, multiname, args, isLex, ti) { if (ti && ti.trait) { if (ti.trait.isMethod()) { @@ -21677,7 +20462,7 @@ var createName = function createName(namespaces, name) { return store(new IR.ASGetProperty(region, state.store, object, multiname, IR.Flags.INDEXED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0))); } } - warn('Can\'t optimize getProperty ' + multiname); + info('Can\'t optimize getProperty ' + multiname); var qn = resolveMultinameGlobally(multiname); if (qn) { return store(new IR.ASGetProperty(region, state.store, object, constant(Multiname.getQualifiedName(qn)), IR.Flags.RESOLVED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0))); @@ -21689,6 +20474,10 @@ var createName = function createName(namespaces, name) { true; if (ti) { if (ti.trait) { + var coercer = ti.trait.typeName ? getCoercerForType(ti.trait.typeName) : null; + if (coercer) { + value = coercer(value); + } store(new IR.SetProperty(region, state.store, object, qualifiedNameConstant(ti.trait.name), value)); return; } @@ -21700,7 +20489,7 @@ var createName = function createName(namespaces, name) { return store(new IR.ASSetProperty(region, state.store, object, multiname, value, IR.Flags.INDEXED)); } } - warn('Can\'t optimize setProperty ' + multiname); + info('Can\'t optimize setProperty ' + multiname); var qn = resolveMultinameGlobally(multiname); if (qn) { } @@ -21721,6 +20510,7 @@ var createName = function createName(namespaces, name) { return store(new IR.GetProperty(region, state.store, object, constant(slotQn))); } } + info('Can\'t optimize getSlot ' + index); return store(new IR.ASGetSlot(null, state.store, object, index)); } function setSlot(object, index, value, ti) { @@ -21732,6 +20522,7 @@ var createName = function createName(namespaces, name) { return; } } + info('Can\'t optimize setSlot ' + index); store(new IR.ASSetSlot(region, state.store, object, index, value)); } function call(callee, object, args) { @@ -21895,7 +20686,7 @@ var createName = function createName(namespaces, name) { scope.pop(); break; case 100: - push(new IR.ASGlobal(null, topScope())); + push(new IR.ASGlobal(null, savedScope())); break; case 101: push(getScopeObject(state.scope[bc.index])); @@ -21944,22 +20735,13 @@ var createName = function createName(namespaces, name) { case 4: multiname = buildMultiname(bc.index); object = pop(); - push(call(globalProperty('getSuper'), null, [ - savedScope(), - object, - multiname - ])); + push(getSuper(savedScope(), object, multiname, bc.ti)); break; case 5: value = pop(); multiname = buildMultiname(bc.index); object = pop(); - store(call(globalProperty('setSuper'), null, [ - savedScope(), - object, - multiname, - value - ])); + push(setSuper(savedScope(), object, multiname, value, bc.ti)); break; case 241: case 240: @@ -21993,12 +20775,7 @@ var createName = function createName(namespaces, name) { multiname = buildMultiname(bc.index); args = popMany(bc.argCount); object = pop(); - callee = call(globalProperty('getSuper'), null, [ - savedScope(), - object, - multiname - ]); - value = call(callee, object, args); + value = callSuper(savedScope(), object, multiname, args, bc.ti); if (op !== OP_callsupervoid) { push(value); } @@ -23795,27 +22572,19 @@ var Compiler = new (function () { var VariableDeclarator = T.VariableDeclarator; var MemberExpression = T.MemberExpression; var BinaryExpression = T.BinaryExpression; - var SequenceExpression = T.SequenceExpression; var CallExpression = T.CallExpression; var AssignmentExpression = T.AssignmentExpression; var ExpressionStatement = T.ExpressionStatement; var ReturnStatement = T.ReturnStatement; - var Program = T.Program; - var Statement = T.Statement; var FunctionDeclaration = T.FunctionDeclaration; - var FunctionExpression = T.FunctionExpression; var ConditionalExpression = T.ConditionalExpression; var ObjectExpression = T.ObjectExpression; var ArrayExpression = T.ArrayExpression; var UnaryExpression = T.UnaryExpression; var NewExpression = T.NewExpression; var Property = T.Property; - var UpdateExpression = T.UpdateExpression; - var ForStatement = T.ForStatement; var BlockStatement = T.BlockStatement; var ThisExpression = T.ThisExpression; - var TypeAliasDirective = T.TypeAliasDirective; - var CastExpression = T.CastExpression; var ThrowStatement = T.ThrowStatement; var IfStatement = T.IfStatement; var WhileStatement = T.WhileStatement; @@ -23823,12 +22592,8 @@ var Compiler = new (function () { var ContinueStatement = T.ContinueStatement; var SwitchStatement = T.SwitchStatement; var SwitchCase = T.SwitchCase; - var TryStatement = T.TryStatement; - var CatchClause = T.CatchClause; var Block = IR.Block; var Operator = IR.Operator; - var If = IR.If; - var Jump = IR.Jump; var Projection = IR.Projection; var Start = IR.Start; var Control = Looper.Control; @@ -24183,6 +22948,14 @@ var Compiler = new (function () { var isMethod = new Literal(this.flags & IR.Flags.IS_METHOD); return call(property(object, 'asGetProperty'), name.concat(isMethod)); }; + IR.ASGetSuper.prototype.compile = function (cx) { + var scope = compileValue(this.scope, cx); + var object = compileValue(this.object, cx); + var name = compileMultiname(this.name, cx); + return call(property(object, 'asGetSuper'), [ + scope + ].concat(name)); + }; IR.Latch.prototype.compile = function (cx) { return new ConditionalExpression(compileValue(this.condition, cx), compileValue(this.left, cx), compileValue(this.right, cx)); }; @@ -24234,6 +23007,17 @@ var Compiler = new (function () { new ArrayExpression(args) ])); }; + IR.ASCallSuper.prototype.compile = function (cx) { + var scope = compileValue(this.scope, cx); + var object = compileValue(this.object, cx); + var args = this.args.map(function (arg) { + return compileValue(arg, cx); + }); + var name = compileMultiname(this.name, cx); + return call(property(object, 'asCallSuper'), [ + scope + ].concat(name).concat(new ArrayExpression(args))); + }; IR.Call.prototype.compile = function (cx) { var args = this.args.map(function (arg) { return compileValue(arg, cx); @@ -24285,6 +23069,17 @@ var Compiler = new (function () { var name = compileMultiname(this.name, cx); return call(property(object, 'asSetProperty'), name.concat(value)); }; + IR.ASSetSuper.prototype.compile = function (cx) { + var scope = compileValue(this.scope, cx); + var object = compileValue(this.object, cx); + var name = compileMultiname(this.name, cx); + var value = compileValue(this.value, cx); + return call(property(object, 'asSetSuper'), [ + scope + ].concat(name).concat([ + value + ])); + }; IR.ASDeleteProperty.prototype.compile = function (cx) { var object = compileValue(this.object, cx); var name = compileMultiname(this.name, cx); @@ -24429,7 +23224,7 @@ var Compiler = new (function () { } Backend.generate = generate; }(typeof exports === 'undefined' ? Backend = {} : exports)); -var domainOptions = systemOptions.register(new OptionSet('Domain Options')); +var domainOptions = systemOptions.register(new OptionSet('ApplicationDomain Options')); var traceClasses = domainOptions.register(new Option('tc', 'traceClasses', 'boolean', false, 'trace class creation')); var traceDomain = domainOptions.register(new Option('td', 'traceDomain', 'boolean', false, 'trace domain property access')); var EXECUTION_MODE = { @@ -24438,15 +23233,9 @@ var EXECUTION_MODE = { }; function executeScript(script) { var abc = script.abc; - if (disassemble.value) { - abc.trace(new IndentingWriter()); - } - if (traceExecution.value) { - print('Executing: ' + abc.name + ' ' + script); - } true; var global = new Global(script); - if (abc.domain.allowNatives) { + if (abc.applicationDomain.allowNatives) { global[Multiname.getPublicQualifiedName('unsafeJSNative')] = getNative; } script.executing = true; @@ -24466,8 +23255,10 @@ var Glue = createEmptyObject(); Glue.PUBLIC_PROPERTIES = 1; Glue.PUBLIC_METHODS = 2; Glue.ALL = Glue.PUBLIC_PROPERTIES | Glue.PUBLIC_METHODS; -var Domain = function () { - function Domain(vm, base, mode, allowNatives) { +var ApplicationDomain = function () { + function applicationDomain(vm, base, mode, allowNatives) { + true; + true; this.vm = vm; this.abcs = []; this.loadedAbcs = {}; @@ -24485,7 +23276,7 @@ var Domain = function () { this.system = this; } } - Domain.passthroughCallable = function passthroughCallable(f) { + applicationDomain.passthroughCallable = function passthroughCallable(f) { return { call: function ($this) { Array.prototype.shift.call(arguments); @@ -24496,7 +23287,7 @@ var Domain = function () { } }; }; - Domain.coerceCallable = function coerceCallable(type) { + applicationDomain.coerceCallable = function coerceCallable(type) { return { call: function ($this, value) { return asCoerce(type, value); @@ -24506,7 +23297,7 @@ var Domain = function () { } }; }; - Domain.constructingCallable = function constructingCallable(instanceConstructor) { + applicationDomain.constructingCallable = function constructingCallable(instanceConstructor) { return { call: function ($this) { return new Function.bind.apply(instanceConstructor, arguments); @@ -24518,7 +23309,7 @@ var Domain = function () { } }; }; - Domain.prototype = { + applicationDomain.prototype = { getType: function getType(multiname) { return this.getProperty(multiname, true, true); }, @@ -24552,7 +23343,7 @@ var Domain = function () { }, findDomainProperty: function findDomainProperty(multiname, strict, execute) { if (traceDomain.value) { - print('Domain.findDomainProperty: ' + multiname); + print('ApplicationDomain.findDomainProperty: ' + multiname); } var resolved = this.findDefiningScript(multiname, execute); if (resolved) { @@ -24638,7 +23429,7 @@ var Domain = function () { return resolved; } } - Counter.count('Domain: findDefiningScript'); + Counter.count('ApplicationDomain: findDefiningScript'); var abcs = this.abcs; for (var i = 0; i < abcs.length; i++) { var abc = abcs[i]; @@ -24675,7 +23466,6 @@ var Domain = function () { return undefined; }, compileAbc: function compileAbc(abc) { - console.time('Compile ABC: ' + abc.name); this.loadAbc(abc); var writer = new IndentingWriter(); writer.enter('var classes = {'); @@ -24683,19 +23473,16 @@ var Domain = function () { compileScript(abc.scripts[i], writer); } writer.leave('}'); - console.timeEnd('Compile ABC: ' + abc.name); }, executeAbc: function executeAbc(abc) { - console.time('Execute ABC: ' + abc.name); this.loadAbc(abc); executeScript(abc.lastScript); - console.timeEnd('Execute ABC: ' + abc.name); }, loadAbc: function loadAbc(abc) { if (traceExecution.value) { print('Loading: ' + abc.name); } - abc.domain = this; + abc.applicationDomain = this; GlobalMultinameResolver.loadAbc(abc); this.abcs.push(abc); if (!this.base) { @@ -24729,7 +23516,25 @@ var Domain = function () { lastOnly || writer.leave(''); } }; - return Domain; + return applicationDomain; + }(); +var SecurityDomain = function () { + function securityDomain() { + this.compartment = createNewCompartment(); + this.compartment.environment = environment; + this.compartment.homePath = homePath; + this.compartment.eval(snarf('compartment.js')); + this.compartment.release = true; + } + securityDomain.prototype.initializeShell = function (sysMode, appMode) { + var compartment = this.compartment; + compartment.avm2 = new compartment.AVM2(sysMode, appMode); + compartment.avm2.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/builtin/builtin.abc')); + compartment.avm2.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/shell/shell.abc')); + this.systemDomain = compartment.avm2.systemDomain; + this.applicationDomain = compartment.avm2.applicationDomain; + }; + return securityDomain; }(); var traitsWriter = null; var Binding = function () { @@ -24787,6 +23592,10 @@ var Bindings = function () { this.type = type; this.trait = trait; } + function SlotInfoMap() { + this.byID = []; + this.byQN = createEmptyObject(); + } function patch(patchTargets, value) { true; for (var i = 0; i < patchTargets.length; i++) { @@ -24897,17 +23706,27 @@ var Bindings = function () { return fn; }, 0, String(trait.name)); if (trait.isGetter()) { + defineNonEnumerableProperty(object, VM_OPEN_GET_METHOD_PREFIX + qn, trampoline); trampoline.patchTargets = [ { object: object, get: qn + }, + { + object: object, + name: VM_OPEN_GET_METHOD_PREFIX + qn } ]; } else { + defineNonEnumerableProperty(object, VM_OPEN_SET_METHOD_PREFIX + qn, trampoline); trampoline.patchTargets = [ { object: object, set: qn + }, + { + object: object, + name: VM_OPEN_SET_METHOD_PREFIX + qn } ]; } @@ -24918,7 +23737,7 @@ var Bindings = function () { true; true; true; - defineNonEnumerableProperty(object, VM_SLOTS, []); + defineNonEnumerableProperty(object, VM_SLOTS, new SlotInfoMap()); defineNonEnumerableProperty(object, VM_BINDINGS, []); defineNonEnumerableProperty(object, VM_OPEN_METHODS, createEmptyObject()); defineNonEnumerableProperty(object, 'bindings', this); @@ -24945,7 +23764,9 @@ var Bindings = function () { traitsWriter && traitsWriter.greenLn('Applying Trait ' + trait.kindName() + ': ' + trait); defineNonEnumerableProperty(object, qn, defaultValue); object[VM_BINDINGS].pushUnique(qn); - object[VM_SLOTS][trait.slotId] = new SlotInfo(qn, trait.isConst(), trait.typeName ? domain.getProperty(trait.typeName, false, false) : null, trait); + var slotInfo = new SlotInfo(qn, trait.isConst(), trait.typeName ? domain.getProperty(trait.typeName, false, false) : null, trait); + object[VM_SLOTS].byID[trait.slotId] = slotInfo; + object[VM_SLOTS].byQN[qn] = slotInfo; } } else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { if (trait.isGetter() || trait.isSetter()) { @@ -25121,10 +23942,11 @@ var InstanceBindings = function () { binding.natives = this.natives; } } - var domain = ii.abc.domain; + var domain = ii.abc.applicationDomain; var interfaces = ii.interfaces; for (var i = 0; i < interfaces.length; i++) { var interface = domain.getProperty(interfaces[i], true, true); + true; copyProperties(this.implementedInterfaces, interface.interfaceBindings.implementedInterfaces); this.implementedInterfaces[Multiname.getQualifiedName(interface.name)] = interface; } @@ -25214,9 +24036,9 @@ var Class = function () { this.instanceConstructor.class = this; } if (!callable) { - callable = Domain.coerceCallable(this); - } else if (callable === Domain.coerceCallable) { - callable = Domain.coerceCallable(this); + callable = ApplicationDomain.coerceCallable(this); + } else if (callable === ApplicationDomain.coerceCallable) { + callable = ApplicationDomain.coerceCallable(this); } defineNonEnumerableProperty(this, 'call', callable.call); defineNonEnumerableProperty(this, 'apply', callable.apply); @@ -25224,12 +24046,12 @@ var Class = function () { Class.createClass = function createClass(classInfo, baseClass, scope) { var ci = classInfo; var ii = ci.instanceInfo; - var domain = ci.abc.domain; + var domain = ci.abc.applicationDomain; var className = Multiname.getName(ii.name); var isNativeClass = ci.native; if (isNativeClass) { - var classBuilder = getNative(ci.native.cls); - if (!classBuilder) { + var buildClass = getNative(ci.native.cls); + if (!buildClass) { unexpected('No native for ' + ci.native.cls); } if (!baseClass) { @@ -25240,7 +24062,7 @@ var Class = function () { var instanceConstructor = createFunction(ii.init, classScope); var cls; if (isNativeClass) { - cls = classBuilder(domain, classScope, instanceConstructor, baseClass); + cls = buildClass(domain, classScope, instanceConstructor, baseClass); } else { cls = new Class(className, instanceConstructor); } @@ -25293,7 +24115,7 @@ var Class = function () { while (s = initializes.pop()) { s.call(obj); } - Counter.count('Initialize Instance'); + Counter.count('Initialize Instance ' + obj.class); }, createInstance: function createInstance(args) { var o = Object.create(this.instanceConstructor.prototype); @@ -25483,7 +24305,7 @@ var Class = function () { writer.enter('traitsPrototype: '); if (traitsPrototype) { writer.enter('VM_SLOTS: '); - writer.writeArray(traitsPrototype[VM_SLOTS].map(function (slot) { + writer.writeArray(traitsPrototype[VM_SLOTS].byID.map(function (slot) { return slot.trait; })); writer.outdent(); @@ -25525,7 +24347,7 @@ var Class = function () { return '[class ' + this.classInfo.instanceInfo.name.name + ']'; } }; - var callable = Domain.coerceCallable(Class); + var callable = ApplicationDomain.coerceCallable(Class); defineNonEnumerableProperty(Class, 'call', callable.call); defineNonEnumerableProperty(Class, 'apply', callable.apply); Class.instanceConstructor = Class; @@ -26178,16 +25000,9 @@ var VM_BINDINGS = 'vm bindings'; var VM_NATIVE_PROTOTYPE_FLAG = 'vm native prototype'; var VM_OPEN_METHODS = 'vm open methods'; var VM_IS_CLASS = 'vm is class'; -var VM_OPEN_METHOD_PREFIX = 'open_'; -var VM_NATIVE_BUILTINS = [ - Object, - Number, - Boolean, - String, - Array, - Date, - RegExp - ]; +var VM_OPEN_METHOD_PREFIX = 'method_'; +var VM_OPEN_SET_METHOD_PREFIX = 'set_'; +var VM_OPEN_GET_METHOD_PREFIX = 'get_'; var VM_NATIVE_BUILTIN_SURROGATES = [ { object: Object, @@ -26308,7 +25123,7 @@ var LazyInitializer = function () { } else if (this.target instanceof ClassInfo) { this.name = Multiname.getQualifiedName(target.instanceInfo.name); initialize = function () { - return target.abc.domain.getProperty(target.instanceInfo.name); + return target.abc.applicationDomain.getProperty(target.instanceInfo.name); }; } else { notImplemented(target); @@ -26420,6 +25235,16 @@ function asSetProperty(namespaces, name, flags, value) { if (this.asSetNumericProperty && Multiname.isNumeric(resolved)) { return this.asSetNumericProperty(resolved, value); } + var slotInfo = this[VM_SLOTS].byQN[resolved]; + if (slotInfo) { + if (slotInfo.const) { + return; + } + var type = slotInfo.type; + if (type && type.coerce) { + value = type.coerce(value); + } + } this[resolved] = value; } function asSetPropertyLikelyNumeric(namespaces, name, flags, value) { @@ -26470,6 +25295,40 @@ function asCallProperty(namespaces, name, flags, isLex, args) { traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); return result; } +function asCallSuper(scope, namespaces, name, flags, args) { + if (traceCallExecution.value) { + var receiver = this.class ? this.class.className + ' ' : ''; + callWriter.enter('call super ' + receiver + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name)); + } + var baseClass = scope.object.baseClass; + var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); + var openMethods = baseClass.traitsPrototype[VM_OPEN_METHODS]; + var method = openMethods[resolved]; + var result = method.apply(this, args); + traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); + return result; +} +function asSetSuper(scope, namespaces, name, flags, value) { + if (traceCallExecution.value) { + var receiver = this.class ? this.class.className + ' ' : ''; + callWriter.enter('set super ' + receiver + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name)); + } + var baseClass = scope.object.baseClass; + var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); + baseClass.traitsPrototype[VM_OPEN_SET_METHOD_PREFIX + resolved].call(this, value); + traceCallExecution.value > 0 && callWriter.leave(''); +} +function asGetSuper(scope, namespaces, name, flags) { + if (traceCallExecution.value) { + var receiver = this.class ? this.class.className + ' ' : ''; + callWriter.enter('get super ' + receiver + name + ' #' + callCounter.count(name)); + } + var baseClass = scope.object.baseClass; + var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); + var result = baseClass.traitsPrototype[VM_OPEN_GET_METHOD_PREFIX + resolved].call(this); + traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); + return result; +} function construct(constructor, args) { if (constructor.classInfo) { var qn = constructor.classInfo.instanceInfo.name.qualifiedName; @@ -26579,8 +25438,16 @@ function initializeGlobalObject(global) { } }); }); - VM_NATIVE_BUILTINS.forEach(function (o) { - defineReadOnlyProperty(o.prototype, VM_NATIVE_PROTOTYPE_FLAG, true); + [ + 'Object', + 'Number', + 'Boolean', + 'String', + 'Array', + 'Date', + 'RegExp' + ].forEach(function (name) { + defineReadOnlyProperty(global[name].prototype, VM_NATIVE_PROTOTYPE_FLAG, true); }); defineNonEnumerableProperty(global.Object.prototype, 'getNamespaceResolutionMap', getNamespaceResolutionMap); defineNonEnumerableProperty(global.Object.prototype, 'resolveMultinameProperty', resolveMultinameProperty); @@ -26592,6 +25459,9 @@ function initializeGlobalObject(global) { defineNonEnumerableProperty(global.Object.prototype, 'asDefineProperty', asDefineProperty); defineNonEnumerableProperty(global.Object.prototype, 'asDefinePublicProperty', asDefinePublicProperty); defineNonEnumerableProperty(global.Object.prototype, 'asCallProperty', asCallProperty); + defineNonEnumerableProperty(global.Object.prototype, 'asCallSuper', asCallSuper); + defineNonEnumerableProperty(global.Object.prototype, 'asGetSuper', asGetSuper); + defineNonEnumerableProperty(global.Object.prototype, 'asSetSuper', asSetSuper); defineNonEnumerableProperty(global.Object.prototype, 'asCallPublicProperty', asCallPublicProperty); defineNonEnumerableProperty(global.Object.prototype, 'asCallResolvedStringProperty', asCallResolvedStringProperty); defineNonEnumerableProperty(global.Object.prototype, 'asConstructProperty', asConstructProperty); @@ -26622,13 +25492,13 @@ function initializeGlobalObject(global) { defineNonEnumerableProperty(global[name].prototype, 'asGetProperty', asGetPropertyLikelyNumeric); defineNonEnumerableProperty(global[name].prototype, 'asSetProperty', asSetPropertyLikelyNumeric); }); - Array.prototype.asGetProperty = function (namespaces, name, flags) { + global.Array.prototype.asGetProperty = function (namespaces, name, flags) { if (typeof name === 'number') { return this[name]; } return asGetProperty.call(this, namespaces, name, flags); }; - Array.prototype.asSetProperty = function (namespaces, name, flags, value) { + global.Array.prototype.asSetProperty = function (namespaces, name, flags, value) { if (typeof name === 'number') { this[name] = value; return; @@ -26666,15 +25536,15 @@ function publicizeProperties(object) { } } function asGetSlot(object, index) { - return object[object[VM_SLOTS][index].name]; + return object[object[VM_SLOTS].byID[index].name]; } function asSetSlot(object, index, value) { - var binding = object[VM_SLOTS][index]; - if (binding.const) { + var slotInfo = object[VM_SLOTS].byID[index]; + if (slotInfo.const) { return; } - var name = binding.name; - var type = binding.type; + var name = slotInfo.name; + var type = slotInfo.type; if (type && type.coerce) { object[name] = type.coerce(value); } else { @@ -26771,9 +25641,9 @@ var ScopeStack = function () { }(); var Scope = function () { function scope(parent, object, isWith) { - true; this.parent = parent; - this.object = object; + this.object = boxValue(object); + true; this.global = parent ? parent.global : this; this.isWith = isWith; this.cache = createEmptyObject(); @@ -26926,88 +25796,9 @@ function resolveMultiname(object, mn, traitsOnly) { function sliceArguments(args, offset) { return Array.prototype.slice.call(args, offset); } -function hasProperty(object, name) { - object = boxValue(object); - if (object.hasProperty) { - return object.hasProperty(name); - } - return resolveName(object, name) in object; -} function nonProxyingHasProperty(object, name) { return name in object; } -function getSuper(scope, object, mn) { - true; - true; - true; - var superClass = scope.object.baseClass; - true; - var superTraitsPrototype = superClass.instanceConstructor.prototype; - var resolved = mn.isQName() ? mn : resolveMultiname(superTraitsPrototype, mn); - var value = undefined; - if (resolved) { - if (Multiname.isNumeric(resolved) && superTraitsPrototype.asGetNumericProperty) { - value = superTraitsPrototype.asGetNumericProperty(Multiname.getQualifiedName(resolved), value); - } else { - var qn = Multiname.getQualifiedName(resolved); - var openMethod = superTraitsPrototype[VM_OPEN_METHODS][qn]; - var superName = superClass.classInfo.instanceInfo.name; - if (openMethod) { - value = object[superName + ' ' + qn]; - if (!value) { - value = object[superName + ' ' + qn] = bindSafely(openMethod, object); - } - } else { - var descriptor = Object.getOwnPropertyDescriptor(superTraitsPrototype, qn); - true; - value = descriptor.get ? descriptor.get.call(object) : object[qn]; - } - } - } - return value; -} -function resolveName(object, name) { - if (name instanceof Multiname) { - if (name.namespaces.length > 1) { - var resolved = resolveMultiname(object, name); - if (resolved !== undefined) { - return Multiname.getQualifiedName(resolved); - } else { - return Multiname.getPublicQualifiedName(name.name); - } - } else { - return Multiname.getQualifiedName(name); - } - } else if (typeof name === 'object') { - return Multiname.getPublicQualifiedName(String(name)); - } else { - return name; - } -} -function setSuper(scope, object, mn, value) { - true; - true; - var superClass = scope.object.baseClass; - true; - var superTraitsPrototype = superClass.instanceConstructor.prototype; - var resolved = Multiname.isQName(mn) ? mn : resolveMultiname(superTraitsPrototype, mn); - if (resolved !== undefined) { - if (Multiname.isNumeric(resolved) && superTraitsPrototype.asSetNumericProperty) { - superTraitsPrototype.asSetNumericProperty(Multiname.getQualifiedName(resolved), value); - } else { - var qn = Multiname.getQualifiedName(resolved); - var descriptor = Object.getOwnPropertyDescriptor(superTraitsPrototype, qn); - true; - if (descriptor.set) { - descriptor.set.call(object, value); - } else { - object[qn] = value; - } - } - } else { - throw new ReferenceError('Cannot create property ' + mn.name + ' on ' + superClass.debugName); - } -} function forEachPublicProperty(object, fn, self) { if (!object[VM_BINDINGS]) { for (var key in object) { @@ -27062,29 +25853,29 @@ function CatchScopeObject(domain, trait) { } } var Global = function () { - function Global(script) { + function global(script) { this.scriptInfo = script; script.global = this; script.scriptBindings = new ScriptBindings(script, new Scope(null, this)); - script.scriptBindings.applyTo(script.abc.domain, this); + script.scriptBindings.applyTo(script.abc.applicationDomain, this); script.loaded = true; } - Global.prototype.toString = function () { + global.prototype.toString = function () { return '[object global]'; }; - Global.prototype.isExecuted = function () { + global.prototype.isExecuted = function () { return this.scriptInfo.executed; }; - Global.prototype.isExecuting = function () { + global.prototype.isExecuting = function () { return this.scriptInfo.executing; }; - Global.prototype.ensureExecuted = function () { + global.prototype.ensureExecuted = function () { ensureScriptIsExecuted(this.scriptInfo); }; - defineNonEnumerableProperty(Global.prototype, Multiname.getPublicQualifiedName('toString'), function () { + defineNonEnumerableProperty(global.prototype, Multiname.getPublicQualifiedName('toString'), function () { return this.toString(); }); - return Global; + return global; }(); function canCompile(mi) { if (!mi.hasBody) { @@ -27172,24 +25963,8 @@ function debugName(value) { } return value; } -function createCompiledFunctionTrampoline(methodInfo, scope, hasDynamicScope, breakpoint) { - var mi = methodInfo; - return function trampolineContext() { - var fn; - return function () { - if (!fn) { - fn = mi.freeMethod = createCompiledFunction(mi, scope, hasDynamicScope, breakpoint); - mi.freeMethod.methodInfo = mi; - } - return fn.apply(this, arguments); - }; - }(); -} function createCompiledFunction(methodInfo, scope, hasDynamicScope, breakpoint, deferCompilation) { var mi = methodInfo; - if (false && deferCompilation) { - return createCompiledFunctionTrampoline(methodInfo, scope, hasDynamicScope, breakpoint); - } $M.push(mi); var result = Compiler.compileMethod(mi, scope, hasDynamicScope); var parameters = result.parameters; @@ -27217,11 +25992,9 @@ function createCompiledFunction(methodInfo, scope, hasDynamicScope, breakpoint, if (traceLevel.value > 1) { mi.trace(new IndentingWriter(), mi.abc); } - mi.debugTrace = function (abc) { - return function () { - mi.trace(new IndentingWriter(), abc); - }; - }(this.abc); + mi.debugTrace = function () { + mi.trace(new IndentingWriter(), mi.abc); + }; if (traceLevel.value > 0) { print(fnSource); } @@ -27229,16 +26002,20 @@ function createCompiledFunction(methodInfo, scope, hasDynamicScope, breakpoint, fn.debugName = 'Compiled Function #' + vmNextCompiledFunctionId++; return fn; } +function getMethodOverrideKey(methodInfo) { + var key; + if (methodInfo.holder instanceof ClassInfo) { + key = 'static ' + methodInfo.holder.instanceInfo.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); + } else if (methodInfo.holder instanceof InstanceInfo) { + key = methodInfo.holder.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); + } else { + key = methodInfo.name.getOriginalName(); + } + return key; +} function checkMethodOverrides(methodInfo) { if (methodInfo.name) { - var key; - if (methodInfo.holder instanceof ClassInfo) { - key = 'static ' + methodInfo.holder.instanceInfo.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); - } else if (methodInfo.holder instanceof InstanceInfo) { - key = methodInfo.holder.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); - } else { - key = methodInfo.name.getOriginalName(); - } + var key = getMethodOverrideKey(methodInfo); if (key in VM_METHOD_OVERRIDES) { warning('Overriding Method: ' + key); return VM_METHOD_OVERRIDES[key]; @@ -27332,7 +26109,7 @@ function createFunction(mi, scope, hasDynamicScope, breakpoint) { ensureFunctionIsInitialized(mi); totalFunctionCount++; var useInterpreter = false; - if ((mi.abc.domain.mode === EXECUTION_MODE.INTERPRET || !shouldCompile(mi)) && !forceCompile(mi)) { + if ((mi.abc.applicationDomain.mode === EXECUTION_MODE.INTERPRET || !shouldCompile(mi)) && !forceCompile(mi)) { useInterpreter = true; } if (compileOnly.value >= 0) { @@ -27373,7 +26150,7 @@ function ensureFunctionIsInitialized(methodInfo) { mi.analysis = new Analysis(mi); if (mi.needsActivation()) { mi.activationPrototype = new Activation(mi); - new ActivationBindings(mi).applyTo(mi.abc.domain, mi.activationPrototype); + new ActivationBindings(mi).applyTo(mi.abc.applicationDomain, mi.activationPrototype); } var exceptions = mi.exceptions; for (var i = 0, j = exceptions.length; i < j; i++) { @@ -27384,7 +26161,7 @@ function ensureFunctionIsInitialized(methodInfo) { varTrait.name = handler.varName; varTrait.typeName = handler.typeName; varTrait.holder = mi; - handler.scopeObject = new CatchScopeObject(mi.abc.domain, varTrait); + handler.scopeObject = new CatchScopeObject(mi.abc.applicationDomain, varTrait); } else { handler.scopeObject = new CatchScopeObject(); } @@ -27445,7 +26222,7 @@ function createClass(classInfo, baseClass, scope) { true; var ci = classInfo; var ii = ci.instanceInfo; - var domain = ci.abc.domain; + var domain = ci.abc.applicationDomain; var className = Multiname.getName(ii.name); if (traceExecution.value) { print('Creating ' + (ii.isInterface() ? 'Interface' : 'Class') + ': ' + className + (ci.native ? ' replaced with native ' + ci.native.cls : '')); @@ -27519,8 +26296,22 @@ function applyType(domain, factory, types) { return notImplemented(factoryClassName); } } +function checkArgumentCount(name, expected, got) { + if (got !== expected) { + throwError('ArgumentError', Errors.WrongArgumentCountError, name, expected, got); + } +} +function throwError(name, error) { + if (true) { + var message = formatErrorMessage.apply(null, Array.prototype.slice.call(arguments, 1)); + throwErrorFromVM(AVM2.currentDomain(), name, message, error.code); + } else { + throwErrorFromVM(AVM2.currentDomain(), name, getErrorMessage(error.code), error.code); + } +} function throwErrorFromVM(domain, errorClass, message, id) { - throw new (domain.getClass(errorClass)).instanceConstructor(message, id); + var error = new (domain.getClass(errorClass)).instanceConstructor(message, id); + throw error; } function translateError(domain, error) { if (error instanceof Error) { @@ -27605,13 +26396,16 @@ function asDefaultCompareFunction(a, b) { return String(a).localeCompare(String(b)); } function asCompare(a, b, options, compareFunction) { - true; true; true; var result = 0; if (!compareFunction) { compareFunction = asDefaultCompareFunction; } + if (options & SORT_CASEINSENSITIVE) { + a = String(a).toLowerCase(); + b = String(b).toLowerCase(); + } if (options & SORT_NUMERIC) { a = toNumber(a); b = toNumber(b); @@ -27691,16 +26485,29 @@ VM_METHOD_OVERRIDES['com.midasplayer.debug.DebugLog::trace'] = function (msg) { VM_METHOD_OVERRIDES['com.midasplayer.engine.comm.DebugGameComm::getGameData'] = function () { return '