michael@0: /* michael@0: * Copyright 2013 Mozilla Foundation michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: // This file is automatically generated michael@0: michael@0: (function (global) { michael@0: if (global.DataView) michael@0: return; michael@0: if (!global.ArrayBuffer) michael@0: fail('ArrayBuffer not supported'); michael@0: if (!Object.defineProperties) michael@0: fail('This module requires ECMAScript 5'); michael@0: var nativele = new Int8Array(new Int32Array([ michael@0: 1 michael@0: ]).buffer)[0] === 1; michael@0: var temp = new Uint8Array(8); michael@0: global.DataView = function DataView(buffer, offset, length) { michael@0: if (!(buffer instanceof ArrayBuffer)) michael@0: fail('Bad ArrayBuffer'); michael@0: offset = offset || 0; michael@0: length = length || buffer.byteLength - offset; michael@0: if (offset < 0 || length < 0 || offset + length > buffer.byteLength) michael@0: fail('Illegal offset and/or length'); michael@0: Object.defineProperties(this, { michael@0: buffer: { michael@0: value: buffer, michael@0: enumerable: false, michael@0: writable: false, michael@0: configurable: false michael@0: }, michael@0: byteOffset: { michael@0: value: offset, michael@0: enumerable: false, michael@0: writable: false, michael@0: configurable: false michael@0: }, michael@0: byteLength: { michael@0: value: length, michael@0: enumerable: false, michael@0: writable: false, michael@0: configurable: false michael@0: }, michael@0: _bytes: { michael@0: value: new Uint8Array(buffer, offset, length), michael@0: enumerable: false, michael@0: writable: false, michael@0: configurable: false michael@0: } michael@0: }); michael@0: }; michael@0: global.DataView.prototype = { michael@0: constructor: DataView, michael@0: getInt8: function getInt8(offset) { michael@0: return get(this, Int8Array, 1, offset); michael@0: }, michael@0: getUint8: function getUint8(offset) { michael@0: return get(this, Uint8Array, 1, offset); michael@0: }, michael@0: getInt16: function getInt16(offset, le) { michael@0: return get(this, Int16Array, 2, offset, le); michael@0: }, michael@0: getUint16: function getUint16(offset, le) { michael@0: return get(this, Uint16Array, 2, offset, le); michael@0: }, michael@0: getInt32: function getInt32(offset, le) { michael@0: return get(this, Int32Array, 4, offset, le); michael@0: }, michael@0: getUint32: function getUint32(offset, le) { michael@0: return get(this, Uint32Array, 4, offset, le); michael@0: }, michael@0: getFloat32: function getFloat32(offset, le) { michael@0: return get(this, Float32Array, 4, offset, le); michael@0: }, michael@0: getFloat64: function getFloat32(offset, le) { michael@0: return get(this, Float64Array, 8, offset, le); michael@0: }, michael@0: setInt8: function setInt8(offset, value) { michael@0: set(this, Int8Array, 1, offset, value); michael@0: }, michael@0: setUint8: function setUint8(offset, value) { michael@0: set(this, Uint8Array, 1, offset, value); michael@0: }, michael@0: setInt16: function setInt16(offset, value, le) { michael@0: set(this, Int16Array, 2, offset, value, le); michael@0: }, michael@0: setUint16: function setUint16(offset, value, le) { michael@0: set(this, Uint16Array, 2, offset, value, le); michael@0: }, michael@0: setInt32: function setInt32(offset, value, le) { michael@0: set(this, Int32Array, 4, offset, value, le); michael@0: }, michael@0: setUint32: function setUint32(offset, value, le) { michael@0: set(this, Uint32Array, 4, offset, value, le); michael@0: }, michael@0: setFloat32: function setFloat32(offset, value, le) { michael@0: set(this, Float32Array, 4, offset, value, le); michael@0: }, michael@0: setFloat64: function setFloat64(offset, value, le) { michael@0: set(this, Float64Array, 8, offset, value, le); michael@0: } michael@0: }; michael@0: function get(view, type, size, offset, le) { michael@0: if (offset === undefined) michael@0: fail('Missing required offset argument'); michael@0: if (offset < 0 || offset + size > view.byteLength) michael@0: fail('Invalid index: ' + offset); michael@0: if (size === 1 || !(!le) === nativele) { michael@0: if ((view.byteOffset + offset) % size === 0) michael@0: return new type(view.buffer, view.byteOffset + offset, 1)[0]; michael@0: else { michael@0: for (var i = 0; i < size; i++) michael@0: temp[i] = view._bytes[offset + i]; michael@0: return new type(temp.buffer)[0]; michael@0: } michael@0: } else { michael@0: for (var i = 0; i < size; i++) michael@0: temp[size - i - 1] = view._bytes[offset + i]; michael@0: return new type(temp.buffer)[0]; michael@0: } michael@0: } michael@0: function set(view, type, size, offset, value, le) { michael@0: if (offset === undefined) michael@0: fail('Missing required offset argument'); michael@0: if (value === undefined) michael@0: fail('Missing required value argument'); michael@0: if (offset < 0 || offset + size > view.byteLength) michael@0: fail('Invalid index: ' + offset); michael@0: if (size === 1 || !(!le) === nativele) { michael@0: if ((view.byteOffset + offset) % size === 0) { michael@0: new type(view.buffer, view.byteOffset + offset, 1)[0] = value; michael@0: } else { michael@0: new type(temp.buffer)[0] = value; michael@0: for (var i = 0; i < size; i++) michael@0: view._bytes[i + offset] = temp[i]; michael@0: } michael@0: } else { michael@0: new type(temp.buffer)[0] = value; michael@0: for (var i = 0; i < size; i++) michael@0: view._bytes[offset + i] = temp[size - 1 - i]; michael@0: } michael@0: } michael@0: function fail(msg) { michael@0: throw new Error(msg); michael@0: } michael@0: }(this)); michael@0: ; michael@0: var ByteArray = ByteArray || function (undefined) { michael@0: ByteArrayClass.INITIAL_SIZE = 128; michael@0: ByteArrayClass.DEFAULT_OBJECT_ENCODING = 3; michael@0: function ByteArrayClass(bytes) { michael@0: if (bytes instanceof ByteArray) { michael@0: return bytes; michael@0: } michael@0: var initData = bytes || this.symbol && this.symbol.data; michael@0: if (initData) { michael@0: this.a = new ArrayBuffer(initData.length); michael@0: this.length = initData.length; michael@0: new Uint8Array(this.a).set(initData); michael@0: } else { michael@0: this.a = new ArrayBuffer(ByteArrayClass.INITIAL_SIZE); michael@0: this.length = 0; michael@0: } michael@0: this.position = 0; michael@0: this.cacheViews(); michael@0: this.nativele = new Int8Array(new Int32Array([]).buffer)[0] === 1; michael@0: this.le = this.nativele; michael@0: this.objectEncoding = ByteArrayClass.DEFAULT_OBJECT_ENCODING; michael@0: this.bitBuffer = 0; michael@0: this.bitLength = 0; michael@0: } michael@0: ; michael@0: function throwEOFError() { michael@0: runtime.throwErrorFromVM('flash.errors.EOFError', 'End of file was encountered.'); michael@0: } michael@0: function throwRangeError() { michael@0: var error = Errors.ParamRangeError; michael@0: runtime.throwErrorFromVM('RangeError', getErrorMessage(error.code), error.code); michael@0: } michael@0: function throwCompressedDataError() { michael@0: var error = Errors.CompressedDataError; michael@0: runtime.throwErrorFromVM('CompressedDataError', getErrorMessage(error.code), error.code); michael@0: } michael@0: function checkRange(x, min, max) { michael@0: if (x !== clamp(x, min, max)) { michael@0: throwRangeError(); michael@0: } michael@0: } michael@0: function get(b, m, size) { michael@0: if (b.position + size > b.length) { michael@0: throwEOFError(); michael@0: } michael@0: var v = b.view[m](b.position, b.le); michael@0: b.position += size; michael@0: return v; michael@0: } michael@0: function set(b, m, size, v) { michael@0: var len = b.position + size; michael@0: b.ensureCapacity(len); michael@0: b.view[m](b.position, v, b.le); michael@0: b.position = len; michael@0: if (len > b.length) { michael@0: b.length = len; michael@0: } michael@0: } michael@0: var BAp = ByteArrayClass.prototype; michael@0: BAp.cacheViews = function cacheViews() { michael@0: var a = this.a; michael@0: this.int8v = new Int8Array(a); michael@0: this.uint8v = new Uint8Array(a); michael@0: this.view = new DataView(a); michael@0: }; michael@0: BAp.getBytes = function getBytes() { michael@0: return new Uint8Array(this.a, 0, this.length); michael@0: }; michael@0: BAp.ensureCapacity = function ensureCapacity(size) { michael@0: var origa = this.a; michael@0: if (origa.byteLength < size) { michael@0: var newSize = origa.byteLength; michael@0: while (newSize < size) { michael@0: newSize *= 2; michael@0: } michael@0: var copya = new ArrayBuffer(newSize); michael@0: var origv = this.int8v; michael@0: this.a = copya; michael@0: this.cacheViews(); michael@0: this.int8v.set(origv); michael@0: } michael@0: }; michael@0: BAp.clear = function clear() { michael@0: this.length = 0; michael@0: this.position = 0; michael@0: }; michael@0: BAp.readBoolean = function readBoolean() { michael@0: if (this.position + 1 > this.length) { michael@0: throwEOFError(); michael@0: } michael@0: return this.int8v[this.position++] !== 0; michael@0: }; michael@0: BAp.readByte = function readByte() { michael@0: if (this.position + 1 > this.length) { michael@0: throwEOFError(); michael@0: } michael@0: return this.int8v[this.position++]; michael@0: }; michael@0: BAp.readUnsignedByte = function readUnsignedByte() { michael@0: if (this.position + 1 > this.length) { michael@0: throwEOFError(); michael@0: } michael@0: return this.uint8v[this.position++]; michael@0: }; michael@0: BAp.readBytes = function readBytes(bytes, offset, length) { michael@0: var pos = this.position; michael@0: if (!offset) { michael@0: offset = 0; michael@0: } michael@0: if (!length) { michael@0: length = this.length - pos; michael@0: } michael@0: if (pos + length > this.length) { michael@0: throwEOFError(); michael@0: } michael@0: if (bytes.length < offset + length) { michael@0: bytes.ensureCapacity(offset + length); michael@0: bytes.length = offset + length; michael@0: } michael@0: bytes.int8v.set(new Int8Array(this.a, pos, length), offset); michael@0: this.position += length; michael@0: }; michael@0: BAp.writeBoolean = function writeBoolean(v) { michael@0: var len = this.position + 1; michael@0: this.ensureCapacity(len); michael@0: this.int8v[this.position++] = v ? 1 : 0; michael@0: if (len > this.length) { michael@0: this.length = len; michael@0: } michael@0: }; michael@0: BAp.writeByte = function writeByte(v) { michael@0: var len = this.position + 1; michael@0: this.ensureCapacity(len); michael@0: this.int8v[this.position++] = v; michael@0: if (len > this.length) { michael@0: this.length = len; michael@0: } michael@0: }; michael@0: BAp.writeUnsignedByte = function writeUnsignedByte(v) { michael@0: var len = this.position + 1; michael@0: this.ensureCapacity(len); michael@0: this.uint8v[this.position++] = v; michael@0: if (len > this.length) { michael@0: this.length = len; michael@0: } michael@0: }; michael@0: BAp.writeRawBytes = function writeRawBytes(bytes) { michael@0: var len = this.position + bytes.length; michael@0: this.ensureCapacity(len); michael@0: this.int8v.set(bytes, this.position); michael@0: this.position = len; michael@0: if (len > this.length) { michael@0: this.length = len; michael@0: } michael@0: }; michael@0: BAp.readRawBytes = function readRawBytes() { michael@0: return new Int8Array(this.a, 0, this.length); michael@0: }; michael@0: BAp.writeBytes = function writeBytes(bytes, offset, length) { michael@0: if (arguments.length < 2) { michael@0: offset = 0; michael@0: } michael@0: if (arguments.length < 3) { michael@0: length = 0; michael@0: } michael@0: checkRange(offset, 0, bytes.length); michael@0: checkRange(offset + length, 0, bytes.length); michael@0: if (length === 0) { michael@0: length = bytes.length - offset; michael@0: } michael@0: this.writeRawBytes(new Int8Array(bytes.a, offset, length)); michael@0: }; michael@0: BAp.readDouble = function readDouble() { michael@0: return get(this, 'getFloat64', 8); michael@0: }; michael@0: BAp.readFloat = function readFloat() { michael@0: return get(this, 'getFloat32', 4); michael@0: }; michael@0: BAp.readInt = function readInt() { michael@0: return get(this, 'getInt32', 4); michael@0: }; michael@0: BAp.readShort = function readShort() { michael@0: return get(this, 'getInt16', 2); michael@0: }; michael@0: BAp.readUnsignedInt = function readUnsignedInt() { michael@0: return get(this, 'getUint32', 4); michael@0: }; michael@0: BAp.readUnsignedShort = function readUnsignedShort() { michael@0: return get(this, 'getUint16', 2); michael@0: }; michael@0: BAp.writeDouble = function writeDouble(v) { michael@0: set(this, 'setFloat64', 8, v); michael@0: }; michael@0: BAp.writeFloat = function writeFloat(v) { michael@0: set(this, 'setFloat32', 4, v); michael@0: }; michael@0: BAp.writeInt = function writeInt(v) { michael@0: set(this, 'setInt32', 4, v); michael@0: }; michael@0: BAp.writeShort = function writeShort(v) { michael@0: set(this, 'setInt16', 2, v); michael@0: }; michael@0: BAp.writeUnsignedInt = function writeUnsignedInt(v) { michael@0: set(this, 'setUint32', 4, v); michael@0: }; michael@0: BAp.writeUnsignedShort = function writeUnsignedShort(v) { michael@0: set(this, 'setUint16', 2, v); michael@0: }; michael@0: var codeLengthOrder = [ michael@0: 16, michael@0: 17, michael@0: 18, michael@0: 0, michael@0: 8, michael@0: 7, michael@0: 9, michael@0: 6, michael@0: 10, michael@0: 5, michael@0: 11, michael@0: 4, michael@0: 12, michael@0: 3, michael@0: 13, michael@0: 2, michael@0: 14, michael@0: 1, michael@0: 15 michael@0: ]; michael@0: var distanceCodes = []; michael@0: var distanceExtraBits = []; michael@0: for (var i = 0, j = 0, code = 1; i < 30; ++i) { michael@0: distanceCodes[i] = code; michael@0: code += 1 << (distanceExtraBits[i] = ~(~((j += i > 2 ? 1 : 0) / 2))); michael@0: } michael@0: var bitLengths = []; michael@0: for (var i = 0; i < 32; ++i) { michael@0: bitLengths[i] = 5; michael@0: } michael@0: var fixedDistanceTable = makeHuffmanTable(bitLengths); michael@0: var lengthCodes = []; michael@0: var lengthExtraBits = []; michael@0: for (var i = 0, j = 0, code = 3; i < 29; ++i) { michael@0: lengthCodes[i] = code - (i == 28 ? 1 : 0); michael@0: code += 1 << (lengthExtraBits[i] = ~(~((j += i > 4 ? 1 : 0) / 4 % 6))); michael@0: } michael@0: for (var i = 0; i < 288; ++i) { michael@0: bitLengths[i] = i < 144 || i > 279 ? 8 : i < 256 ? 9 : 7; michael@0: } michael@0: var fixedLiteralTable = makeHuffmanTable(bitLengths); michael@0: function makeHuffmanTable(bitLengths) { michael@0: var maxBits = Math.max.apply(null, bitLengths); michael@0: var numLengths = bitLengths.length; michael@0: var size = 1 << maxBits; michael@0: var codes = new Uint32Array(size); michael@0: for (var code = 0, len = 1, skip = 2; len <= maxBits; code <<= 1, ++len, skip <<= 1) { michael@0: for (var val = 0; val < numLengths; ++val) { michael@0: if (bitLengths[val] === len) { michael@0: var lsb = 0; michael@0: for (var i = 0; i < len; ++i) { michael@0: lsb = lsb * 2 + (code >> i & 1); michael@0: } michael@0: for (var i = lsb; i < size; i += skip) { michael@0: codes[i] = len << 16 | val; michael@0: } michael@0: ++code; michael@0: } michael@0: } michael@0: } michael@0: return { michael@0: codes: codes, michael@0: maxBits: maxBits michael@0: }; michael@0: } michael@0: function inflateBlock(input, output) { michael@0: var header = readBits(input, 3); michael@0: switch (header >> 1) { michael@0: case 0: michael@0: input.bitBuffer = input.bitLength = 0; michael@0: var len = input.readUnsignedShort(); michael@0: var nlen = input.readUnsignedShort(); michael@0: if ((~nlen & 65535) !== len) { michael@0: throwCompressedDataError(); michael@0: } michael@0: output.writeBytes(input, input.position, len); michael@0: input.position += len; michael@0: break; michael@0: case 1: michael@0: inflate(input, output, fixedLiteralTable, fixedDistanceTable); michael@0: break; michael@0: case 2: michael@0: var bitLengths = []; michael@0: var numLiteralCodes = readBits(input, 5) + 257; michael@0: var numDistanceCodes = readBits(input, 5) + 1; michael@0: var numCodes = numLiteralCodes + numDistanceCodes; michael@0: var numLengthCodes = readBits(input, 4) + 4; michael@0: for (var i = 0; i < 19; ++i) { michael@0: bitLengths[codeLengthOrder[i]] = i < numLengthCodes ? readBits(input, 3) : 0; michael@0: } michael@0: var codeLengthTable = makeHuffmanTable(bitLengths); michael@0: bitLengths = []; michael@0: var i = 0; michael@0: var prev = 0; michael@0: while (i < numCodes) { michael@0: var j = 1; michael@0: var sym = readCode(input, codeLengthTable); michael@0: switch (sym) { michael@0: case 16: michael@0: j = readBits(input, 2) + 3; michael@0: sym = prev; michael@0: break; michael@0: case 17: michael@0: j = readBits(input, 3) + 3; michael@0: sym = 0; michael@0: break; michael@0: case 18: michael@0: j = readBits(input, 7) + 11; michael@0: sym = 0; michael@0: break; michael@0: default: michael@0: prev = sym; michael@0: } michael@0: while (j--) { michael@0: bitLengths[i++] = sym; michael@0: } michael@0: } michael@0: var distanceTable = makeHuffmanTable(bitLengths.splice(numLiteralCodes, numDistanceCodes)); michael@0: var literalTable = makeHuffmanTable(bitLengths); michael@0: inflate(input, output, literalTable, distanceTable); michael@0: break; michael@0: default: michael@0: fail('unknown block type', 'inflate'); michael@0: } michael@0: } michael@0: function readBits(input, size) { michael@0: var buffer = input.bitBuffer; michael@0: var bufflen = input.bitLength; michael@0: while (size > bufflen) { michael@0: buffer |= input.readUnsignedByte() << bufflen; michael@0: bufflen += 8; michael@0: } michael@0: input.bitBuffer = buffer >>> size; michael@0: input.bitLength = bufflen - size; michael@0: return buffer & (1 << size) - 1; michael@0: } michael@0: function inflate(input, output, literalTable, distanceTable) { michael@0: var sym; michael@0: while ((sym = readCode(input, literalTable)) !== 256) { michael@0: if (sym < 256) { michael@0: output.writeUnsignedByte(sym); michael@0: } else { michael@0: sym -= 257; michael@0: var len = lengthCodes[sym] + readBits(input, lengthExtraBits[sym]); michael@0: sym = readCode(input, distanceTable); michael@0: var distance = distanceCodes[sym] + readBits(input, distanceExtraBits[sym]); michael@0: output.writeBytes(output, output.position - distance, len); michael@0: } michael@0: } michael@0: } michael@0: function readCode(input, codeTable) { michael@0: var buffer = input.bitBuffer; michael@0: var bitlen = input.bitLength; michael@0: var maxBits = codeTable.maxBits; michael@0: while (maxBits > bitlen) { michael@0: buffer |= input.readUnsignedByte() << bitlen; michael@0: bitlen += 8; michael@0: } michael@0: var code = codeTable.codes[buffer & (1 << maxBits) - 1]; michael@0: var len = code >> 16; michael@0: if (!len) { michael@0: throwCompressedDataError(); michael@0: } michael@0: input.bitBuffer = buffer >>> len; michael@0: input.bitLength = bitlen - len; michael@0: return code & 65535; michael@0: } michael@0: function adler32(data, start, end) { michael@0: var a = 1; michael@0: var b = 0; michael@0: for (var i = start; i < end; ++i) { michael@0: a = (a + (data[i] & 255)) % 65521; michael@0: b = (b + a) % 65521; michael@0: } michael@0: return b << 16 | a; michael@0: } michael@0: BAp.compress = function (algorithm) { michael@0: this.position = 0; michael@0: var output = new ByteArray(); michael@0: switch (algorithm) { michael@0: case 'zlib': michael@0: output.writeUnsignedByte(120); michael@0: output.writeUnsignedByte(156); michael@0: case 'deflate': michael@0: output.le = true; michael@0: var len = this.length; michael@0: output.ensureCapacity(len + Math.ceil(len / 65535) * 5 + 4); michael@0: while (len > 65535) { michael@0: output.writeUnsignedByte(0); michael@0: output.writeUnsignedShort(65535); michael@0: output.writeUnsignedShort(0); michael@0: output.writeBytes(this, this.position, 65535); michael@0: this.position += 65535; michael@0: len -= 65535; michael@0: } michael@0: output.writeUnsignedByte(0); michael@0: output.writeUnsignedShort(len); michael@0: output.writeUnsignedShort(~len & 65535); michael@0: output.writeBytes(this, this.position, len); michael@0: if (algorithm === 'zlib') { michael@0: output.writeUnsignedInt(adler32(this.uint8v, 0, this.length)); michael@0: } michael@0: break; michael@0: default: michael@0: return; michael@0: } michael@0: this.ensureCapacity(output.uint8v.length); michael@0: this.uint8v.set(output.uint8v); michael@0: this.length = output.length; michael@0: this.position = 0; michael@0: }; michael@0: BAp.uncompress = function (algorithm) { michael@0: var output = new ByteArray(); michael@0: switch (algorithm) { michael@0: case 'zlib': michael@0: var header = this.readUnsignedShort(); michael@0: if ((header & 3840) !== 2048 || header % 31 !== 0 || header & 32) { michael@0: throwCompressedDataError(); michael@0: } michael@0: case 'deflate': michael@0: var le = this.le; michael@0: this.le = true; michael@0: while (this.position < this.length - 6) { michael@0: inflateBlock(this, output); michael@0: } michael@0: this.le = le; michael@0: break; michael@0: default: michael@0: return; michael@0: } michael@0: this.ensureCapacity(output.uint8v.length); michael@0: this.uint8v.set(output.uint8v); michael@0: this.length = output.length; michael@0: this.position = 0; michael@0: }; michael@0: return ByteArrayClass; michael@0: }(); michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (Options) { michael@0: var Argument = function () { michael@0: function Argument(shortName, longName, type, options) { michael@0: this.shortName = shortName; michael@0: this.longName = longName; michael@0: this.type = type; michael@0: options = options || {}; michael@0: this.positional = options.positional; michael@0: this.parseFn = options.parse; michael@0: this.value = options.defaultValue; michael@0: } michael@0: Argument.prototype.parse = function (value) { michael@0: if (this.type === 'boolean') { michael@0: true; michael@0: this.value = value; michael@0: } else if (this.type === 'number') { michael@0: true; michael@0: this.value = parseInt(value, 10); michael@0: } else { michael@0: this.value = value; michael@0: } michael@0: if (this.parseFn) { michael@0: this.parseFn(this.value); michael@0: } michael@0: }; michael@0: return Argument; michael@0: }(); michael@0: Options.Argument = Argument; michael@0: var ArgumentParser = function () { michael@0: function ArgumentParser() { michael@0: this.args = []; michael@0: } michael@0: ArgumentParser.prototype.addArgument = function (shortName, longName, type, options) { michael@0: var argument = new Argument(shortName, longName, type, options); michael@0: this.args.push(argument); michael@0: return argument; michael@0: }; michael@0: ArgumentParser.prototype.addBoundOption = function (option) { michael@0: var options = { michael@0: parse: function (x) { michael@0: option.value = x; michael@0: } michael@0: }; michael@0: this.args.push(new Argument(option.shortName, option.longName, option.type, options)); michael@0: }; michael@0: ArgumentParser.prototype.addBoundOptionSet = function (optionSet) { michael@0: var self = this; michael@0: optionSet.options.forEach(function (x) { michael@0: if (x instanceof OptionSet) { michael@0: self.addBoundOptionSet(x); michael@0: } else { michael@0: true; michael@0: self.addBoundOption(x); michael@0: } michael@0: }); michael@0: }; michael@0: ArgumentParser.prototype.getUsage = function () { michael@0: var str = ''; michael@0: this.args.forEach(function (x) { michael@0: if (!x.positional) { michael@0: str += '[-' + x.shortName + '|--' + x.longName + (x.type === 'boolean' ? '' : ' ' + x.type[0].toUpperCase()) + ']'; michael@0: } else { michael@0: str += x.longName; michael@0: } michael@0: str += ' '; michael@0: }); michael@0: return str; michael@0: }; michael@0: ArgumentParser.prototype.parse = function (args) { michael@0: var nonPositionalArgumentMap = {}; michael@0: var positionalArgumentList = []; michael@0: this.args.forEach(function (x) { michael@0: if (x.positional) { michael@0: positionalArgumentList.push(x); michael@0: } else { michael@0: nonPositionalArgumentMap['-' + x.shortName] = x; michael@0: nonPositionalArgumentMap['--' + x.longName] = x; michael@0: } michael@0: }); michael@0: var leftoverArguments = []; michael@0: while (args.length) { michael@0: var argString = args.shift(); michael@0: var argument = null, value = argString; michael@0: if (argString == '--') { michael@0: leftoverArguments = leftoverArguments.concat(args); michael@0: break; michael@0: } else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') { michael@0: argument = nonPositionalArgumentMap[argString]; michael@0: true; michael@0: if (!argument) { michael@0: continue; michael@0: } michael@0: if (argument.type !== 'boolean') { michael@0: value = args.shift(); michael@0: true; michael@0: } else { michael@0: value = true; michael@0: } michael@0: } else if (positionalArgumentList.length) { michael@0: argument = positionalArgumentList.shift(); michael@0: } else { michael@0: leftoverArguments.push(value); michael@0: } michael@0: if (argument) { michael@0: argument.parse(value); michael@0: } michael@0: } michael@0: true; michael@0: return leftoverArguments; michael@0: }; michael@0: return ArgumentParser; michael@0: }(); michael@0: Options.ArgumentParser = ArgumentParser; michael@0: var OptionSet = function () { michael@0: function OptionSet(name) { michael@0: this.name = name; michael@0: this.options = []; michael@0: } michael@0: OptionSet.prototype.register = function (option) { michael@0: this.options.push(option); michael@0: return option; michael@0: }; michael@0: OptionSet.prototype.trace = function (writer) { michael@0: writer.enter(this.name + ' {'); michael@0: this.options.forEach(function (option) { michael@0: option.trace(writer); michael@0: }); michael@0: writer.leave('}'); michael@0: }; michael@0: return OptionSet; michael@0: }(); michael@0: Options.OptionSet = OptionSet; michael@0: var Option = function () { michael@0: function Option(shortName, longName, type, defaultValue, description) { michael@0: this.longName = longName; michael@0: this.shortName = shortName; michael@0: this.type = type; michael@0: this.defaultValue = defaultValue; michael@0: this.value = defaultValue; michael@0: this.description = description; michael@0: } michael@0: Option.prototype.parse = function (value) { michael@0: this.value = value; michael@0: }; michael@0: Option.prototype.trace = function (writer) { michael@0: writer.writeLn(('-' + this.shortName + '|--' + this.longName).padRight(' ', 30) + ' = ' + this.type + ' ' + this.value + ' [' + this.defaultValue + ']' + ' (' + this.description + ')'); michael@0: }; michael@0: return Option; michael@0: }(); michael@0: Options.Option = Option; michael@0: }(Shumway.Options || (Shumway.Options = {}))); michael@0: var Options = Shumway.Options; michael@0: }(Shumway || (Shumway = {}))); michael@0: if (typeof exports !== 'undefined') { michael@0: exports['Shumway'] = Shumway; michael@0: } michael@0: var ArgumentParser = Shumway.Options.ArgumentParser; michael@0: var Option = Shumway.Options.Option; michael@0: var OptionSet = Shumway.Options.OptionSet; michael@0: var Option = Shumway.Options.Option; michael@0: var OptionSet = Shumway.Options.OptionSet; michael@0: var coreOptions = new OptionSet('Core Options'); michael@0: var Timeline = function () { michael@0: var barColor = 'rgba(255,255,255, 0.075)'; michael@0: var backgroundColor = 'rgb(61, 61, 61)'; michael@0: var backgroundColorInfo = 'rgba(0,0,0, 0.85)'; michael@0: var fpsLineColor = 'rgb(255,64,0)'; michael@0: var textColor = '#ccc'; michael@0: function timeline(canvas) { michael@0: this.depth = 0; michael@0: this.start = 0; michael@0: this.index = 0; michael@0: this.marks = new Shumway.CircularBuffer(Int32Array); michael@0: this.times = new Shumway.CircularBuffer(Float64Array); michael@0: this.frameRate = 12; michael@0: this.maxFrameTime = 1000 * 2 / this.frameRate; michael@0: this.refreshFrequency = 10; michael@0: this.refreshCounter = 0; michael@0: this.count = 0; michael@0: this.kinds = createEmptyObject(); michael@0: this.kindCount = 0; michael@0: this.canvas = canvas; michael@0: this.context = canvas.getContext('2d', { michael@0: original: true michael@0: }); michael@0: this.fillStyles = [ michael@0: 'rgb(85, 152, 213)', michael@0: '#bfd8a7', michael@0: '#d906d7' michael@0: ]; michael@0: window.addEventListener('resize', this.resizeHandler.bind(this), false); michael@0: this.resizeHandler(); michael@0: } michael@0: timeline.prototype.setFrameRate = function setFrameRate(frameRate) { michael@0: this.frameRate = frameRate; michael@0: this.maxFrameTime = 1000 * 2 / frameRate; michael@0: }; michael@0: timeline.prototype.refreshEvery = function refreshEvery(freq) { michael@0: this.refreshFrequency = freq; michael@0: this.refreshCounter = 0; michael@0: }; michael@0: var ENTER = 3203334144 | 0; michael@0: var LEAVE = 3735879680 | 0; michael@0: timeline.prototype.registerKind = function getKind(name, fillStyle) { michael@0: if (this.kinds[name] === undefined) { michael@0: this.fillStyles[this.kindCount] = fillStyle; michael@0: this.kinds[name] = this.kindCount++; michael@0: } else { michael@0: this.fillStyles[this.kinds[name]] = fillStyle; michael@0: } michael@0: }; michael@0: timeline.prototype.getKind = function getKind(name) { michael@0: if (this.kinds[name] === undefined) { michael@0: this.kinds[name] = this.kindCount++; michael@0: if (this.kindCount > this.fillStyles.length) { michael@0: this.fillStyles.push(randomStyle()); michael@0: } michael@0: } michael@0: return this.kinds[name]; michael@0: }; michael@0: timeline.prototype.enter = function enter(name) { michael@0: this.depth++; michael@0: this.marks.write(ENTER | this.getKind(name)); michael@0: this.times.write(performance.now()); michael@0: }; michael@0: timeline.prototype.leave = function leave(name) { michael@0: this.marks.write(LEAVE | this.getKind(name)); michael@0: this.times.write(performance.now()); michael@0: this.depth--; michael@0: if (this.depth === 0) { michael@0: this.count++; michael@0: if (++this.refreshCounter == this.refreshFrequency) { michael@0: this.refreshCounter = 0; michael@0: this.paint(); michael@0: } michael@0: } michael@0: }; michael@0: timeline.prototype.gatherFrames = function gatherFrames(maxFrames) { michael@0: var stack = []; michael@0: var frames = []; michael@0: var times = this.times; michael@0: maxFrames++; michael@0: this.marks.forEachInReverse(function (mark, i) { michael@0: var time = times.get(i); michael@0: if ((mark & 4294901760) === ENTER) { michael@0: var node = stack.pop(); michael@0: node.startTime = time; michael@0: if (!stack.length) { michael@0: if (frames.length && !frames[0].total) { michael@0: frames[0].total = frames[0].startTime - time; michael@0: } michael@0: frames.unshift(node); michael@0: } else { michael@0: var top = stack.top(); michael@0: if (!top.children) { michael@0: top.children = [ michael@0: node michael@0: ]; michael@0: } else { michael@0: top.children.push(node); michael@0: } michael@0: } michael@0: } else if ((mark & 4294901760) === LEAVE) { michael@0: if (frames.length > maxFrames) { michael@0: return true; michael@0: } michael@0: stack.push({ michael@0: kind: mark & 65535, michael@0: endTime: time michael@0: }); michael@0: } michael@0: }); michael@0: return frames; michael@0: }; michael@0: timeline.prototype.resizeHandler = function resizeHandler(event) { michael@0: var parent = this.canvas.parentElement; michael@0: this.cw = parent.offsetWidth; michael@0: this.ch = parent.offsetHeight - 1; michael@0: var devicePixelRatio = window.devicePixelRatio || 1; michael@0: var backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1; michael@0: if (devicePixelRatio !== backingStoreRatio) { michael@0: var ratio = devicePixelRatio / backingStoreRatio; michael@0: this.canvas.width = this.cw * ratio; michael@0: this.canvas.height = this.ch * ratio; michael@0: this.canvas.style.width = this.cw + 'px'; michael@0: this.canvas.style.height = this.ch + 'px'; michael@0: this.context.scale(ratio, ratio); michael@0: } else { michael@0: this.canvas.width = this.cw; michael@0: this.canvas.height = this.ch; michael@0: } michael@0: this.context.font = '10px Consolas, "Liberation Mono", Courier, monospace'; michael@0: }; michael@0: timeline.prototype.paint = function paint() { michael@0: var w = 10; michael@0: var gap = 1; michael@0: var maxFrames = this.cw / (w + gap) | 0; michael@0: var frames = this.gatherFrames(maxFrames); michael@0: var context = this.context; michael@0: var maxFrameTime = this.maxFrameTime; michael@0: var fillStyles = this.fillStyles; michael@0: context.clearRect(0, 0, this.cw, this.ch); michael@0: var maxFrameRate = 0; michael@0: var maxFrameRateCount = 0; michael@0: var avgFrameRate = 0; michael@0: var avgFrameRateCount = 0; michael@0: var offsetW; michael@0: context.save(); michael@0: context.translate(0, this.ch); michael@0: context.scale(1, -this.ch / maxFrameTime); michael@0: for (var i = 0; i < frames.length - 1; i++) { michael@0: var frame = frames[i]; michael@0: maxFrameRate += frame.endTime - frame.startTime; michael@0: maxFrameRateCount++; michael@0: if (frame.total) { michael@0: avgFrameRate += frame.total; michael@0: avgFrameRateCount++; michael@0: } michael@0: offsetW = i * (w + gap); michael@0: context.fillStyle = barColor; michael@0: context.fillRect(offsetW, 0, w, frames[i + 1].startTime - frame.startTime); michael@0: drawNode(frame, frame.startTime); michael@0: } michael@0: function drawNode(node, frameStartTime) { michael@0: var nodeTime = node.endTime - node.startTime; michael@0: var offsetH = node.startTime - frameStartTime; michael@0: context.fillStyle = fillStyles[node.kind]; michael@0: context.fillRect(offsetW, offsetH, w, nodeTime); michael@0: if (node.children) { michael@0: var children = node.children; michael@0: for (var i = 0, n = children.length; i < n; i++) { michael@0: drawNode(children[i], frameStartTime); michael@0: } michael@0: } michael@0: } michael@0: var lineH = 1000 / this.frameRate; michael@0: context.beginPath(); michael@0: context.lineWidth = 0.5; michael@0: context.moveTo(0, lineH); michael@0: context.lineTo(this.cw, lineH); michael@0: context.strokeStyle = fpsLineColor; michael@0: context.stroke(); michael@0: context.restore(); michael@0: context.fillStyle = backgroundColorInfo; michael@0: context.fillRect(0, 0, this.cw, 20); michael@0: var textOffset; michael@0: var sFrameCount = this.count; michael@0: var sMaxFrameRate = Math.round(1000 * maxFrameRateCount / maxFrameRate); michael@0: var sAvgFrameRate = Math.round(1000 * avgFrameRateCount / avgFrameRate); michael@0: var space = 5; michael@0: textOffset = 5; michael@0: context.fillStyle = textColor; michael@0: context.fillText(sFrameCount, textOffset, 13); michael@0: textOffset += context.measureText(sFrameCount).width + space; michael@0: context.fillText(sMaxFrameRate, textOffset, 13); michael@0: textOffset += context.measureText(sMaxFrameRate).width + space; michael@0: context.fillText(sAvgFrameRate, textOffset, 13); michael@0: var basicOffset = textOffset + context.measureText(sAvgFrameRate).width + space; michael@0: textOffset = this.cw; michael@0: for (var k in this.kinds) { michael@0: context.fillStyle = this.fillStyles[this.getKind(k)]; michael@0: textOffset -= context.measureText(k).width + space; michael@0: if (textOffset > basicOffset) { michael@0: this.context.fillText(k, textOffset, 13); michael@0: } michael@0: } michael@0: }; michael@0: return timeline; michael@0: }(); michael@0: var create = Object.create; michael@0: var defineProperty = Object.defineProperty; michael@0: var keys = Object.keys; michael@0: var isArray = Array.isArray; michael@0: var fromCharCode = String.fromCharCode; michael@0: var logE = Math.log; michael@0: var max = Math.max; michael@0: var min = Math.min; michael@0: var pow = Math.pow; michael@0: var push = Array.prototype.push; michael@0: var slice = Array.prototype.slice; michael@0: var splice = Array.prototype.splice; michael@0: function fail(msg, context) { michael@0: throw new Error((context ? context + ': ' : '') + msg); michael@0: } michael@0: function assert(cond, msg, context) { michael@0: if (!cond) michael@0: fail(msg, context); michael@0: } michael@0: function scriptProperties(namespace, props) { michael@0: return props.reduce(function (o, p) { michael@0: o[p] = namespace + ' ' + p; michael@0: return o; michael@0: }, {}); michael@0: } michael@0: function cloneObject(obj) { michael@0: var clone = Object.create(null); michael@0: for (var prop in obj) michael@0: clone[prop] = obj[prop]; michael@0: return clone; michael@0: } michael@0: function sortNumeric(a, b) { michael@0: return a - b; michael@0: } michael@0: function sortByZindex(a, b) { michael@0: return a._zindex - b._zindex; michael@0: } michael@0: function rgbaObjToStr(color) { michael@0: return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')'; michael@0: } michael@0: function rgbIntAlphaToStr(color, alpha) { michael@0: color |= 0; michael@0: if (alpha >= 1) { michael@0: var colorStr = color.toString(16); michael@0: while (colorStr.length < 6) { michael@0: colorStr = '0' + colorStr; michael@0: } michael@0: return '#' + colorStr; michael@0: } michael@0: var red = color >> 16 & 255; michael@0: var green = color >> 8 & 255; michael@0: var blue = color & 255; michael@0: return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')'; michael@0: } michael@0: function argbUintToStr(argb) { michael@0: return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')'; michael@0: } michael@0: (function functionNameSupport() { michael@0: if (eval('function t() {} t.name === \'t\'')) { michael@0: return; michael@0: } michael@0: Object.defineProperty(Function.prototype, 'name', { michael@0: get: function () { michael@0: if (this.__name) { michael@0: return this.__name; michael@0: } michael@0: var m = /function\s([^\(]+)/.exec(this.toString()); michael@0: var name = m && m[1] !== 'anonymous' ? m[1] : null; michael@0: this.__name = name; michael@0: return name; michael@0: }, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: }()); michael@0: var randomStyleCache; michael@0: var nextStyle = 0; michael@0: function randomStyle() { michael@0: if (!randomStyleCache) { michael@0: randomStyleCache = [ michael@0: '#ff5e3a', michael@0: '#ff9500', michael@0: '#ffdb4c', michael@0: '#87fc70', michael@0: '#52edc7', michael@0: '#1ad6fd', michael@0: '#c644fc', michael@0: '#ef4db6', michael@0: '#4a4a4a', michael@0: '#dbddde', michael@0: '#ff3b30', michael@0: '#ff9500', michael@0: '#ffcc00', michael@0: '#4cd964', michael@0: '#34aadc', michael@0: '#007aff', michael@0: '#5856d6', michael@0: '#ff2d55', michael@0: '#8e8e93', michael@0: '#c7c7cc', michael@0: '#5ad427', michael@0: '#c86edf', michael@0: '#d1eefc', michael@0: '#e0f8d8', michael@0: '#fb2b69', michael@0: '#f7f7f7', michael@0: '#1d77ef', michael@0: '#d6cec3', michael@0: '#55efcb', michael@0: '#ff4981', michael@0: '#ffd3e0', michael@0: '#f7f7f7', michael@0: '#ff1300', michael@0: '#1f1f21', michael@0: '#bdbec2', michael@0: '#ff3a2d' michael@0: ]; michael@0: } michael@0: return randomStyleCache[nextStyle++ % randomStyleCache.length]; michael@0: } michael@0: (function PromiseClosure() { michael@0: var global = Function('return this')(); michael@0: if (global.Promise) { michael@0: if (typeof global.Promise.all !== 'function') { michael@0: global.Promise.all = function (iterable) { michael@0: var count = 0, results = [], resolve, reject; michael@0: var promise = new global.Promise(function (resolve_, reject_) { michael@0: resolve = resolve_; michael@0: reject = reject_; michael@0: }); michael@0: iterable.forEach(function (p, i) { michael@0: count++; michael@0: p.then(function (result) { michael@0: results[i] = result; michael@0: count--; michael@0: if (count === 0) { michael@0: resolve(results); michael@0: } michael@0: }, reject); michael@0: }); michael@0: if (count === 0) { michael@0: resolve(results); michael@0: } michael@0: return promise; michael@0: }; michael@0: } michael@0: if (typeof global.Promise.resolve !== 'function') { michael@0: global.Promise.resolve = function (x) { michael@0: return new global.Promise(function (resolve) { michael@0: resolve(x); michael@0: }); michael@0: }; michael@0: } michael@0: return; michael@0: } michael@0: function getDeferred(C) { michael@0: if (typeof C !== 'function') { michael@0: throw new TypeError('Invalid deferred constructor'); michael@0: } michael@0: var resolver = createDeferredConstructionFunctions(); michael@0: var promise = new C(resolver); michael@0: var resolve = resolver.resolve; michael@0: if (typeof resolve !== 'function') { michael@0: throw new TypeError('Invalid resolve construction function'); michael@0: } michael@0: var reject = resolver.reject; michael@0: if (typeof reject !== 'function') { michael@0: throw new TypeError('Invalid reject construction function'); michael@0: } michael@0: return { michael@0: promise: promise, michael@0: resolve: resolve, michael@0: reject: reject michael@0: }; michael@0: } michael@0: function updateDeferredFromPotentialThenable(x, deferred) { michael@0: if (typeof x !== 'object' || x === null) { michael@0: return false; michael@0: } michael@0: try { michael@0: var then = x.then; michael@0: if (typeof then !== 'function') { michael@0: return false; michael@0: } michael@0: var thenCallResult = then.call(x, deferred.resolve, deferred.reject); michael@0: } catch (e) { michael@0: var reject = deferred.reject; michael@0: reject(e); michael@0: } michael@0: return true; michael@0: } michael@0: function isPromise(x) { michael@0: return typeof x === 'object' && x !== null && typeof x.promiseStatus !== 'undefined'; michael@0: } michael@0: function rejectPromise(promise, reason) { michael@0: if (promise.promiseStatus !== 'unresolved') { michael@0: return; michael@0: } michael@0: var reactions = promise.rejectReactions; michael@0: promise.result = reason; michael@0: promise.resolveReactions = undefined; michael@0: promise.rejectReactions = undefined; michael@0: promise.promiseStatus = 'has-rejection'; michael@0: triggerPromiseReactions(reactions, reason); michael@0: } michael@0: function resolvePromise(promise, resolution) { michael@0: if (promise.promiseStatus !== 'unresolved') { michael@0: return; michael@0: } michael@0: var reactions = promise.resolveReactions; michael@0: promise.result = resolution; michael@0: promise.resolveReactions = undefined; michael@0: promise.rejectReactions = undefined; michael@0: promise.promiseStatus = 'has-resolution'; michael@0: triggerPromiseReactions(reactions, resolution); michael@0: } michael@0: function triggerPromiseReactions(reactions, argument) { michael@0: for (var i = 0; i < reactions.length; i++) { michael@0: queueMicrotask({ michael@0: reaction: reactions[i], michael@0: argument: argument michael@0: }); michael@0: } michael@0: } michael@0: function queueMicrotask(task) { michael@0: if (microtasksQueue.length === 0) { michael@0: setTimeout(handleMicrotasksQueue, 0); michael@0: } michael@0: microtasksQueue.push(task); michael@0: } michael@0: function executePromiseReaction(reaction, argument) { michael@0: var deferred = reaction.deferred; michael@0: var handler = reaction.handler; michael@0: var handlerResult, updateResult; michael@0: try { michael@0: handlerResult = handler(argument); michael@0: } catch (e) { michael@0: var reject = deferred.reject; michael@0: return reject(e); michael@0: } michael@0: if (handlerResult === deferred.promise) { michael@0: var reject = deferred.reject; michael@0: return reject(new TypeError('Self resolution')); michael@0: } michael@0: try { michael@0: updateResult = updateDeferredFromPotentialThenable(handlerResult, deferred); michael@0: if (!updateResult) { michael@0: var resolve = deferred.resolve; michael@0: return resolve(handlerResult); michael@0: } michael@0: } catch (e) { michael@0: var reject = deferred.reject; michael@0: return reject(e); michael@0: } michael@0: } michael@0: var microtasksQueue = []; michael@0: function handleMicrotasksQueue() { michael@0: while (microtasksQueue.length > 0) { michael@0: var task = microtasksQueue[0]; michael@0: try { michael@0: executePromiseReaction(task.reaction, task.argument); michael@0: } catch (e) { michael@0: if (typeof Promise.onerror === 'function') { michael@0: Promise.onerror(e); michael@0: } michael@0: } michael@0: microtasksQueue.shift(); michael@0: } michael@0: } michael@0: function throwerFunction(e) { michael@0: throw e; michael@0: } michael@0: function identityFunction(x) { michael@0: return x; michael@0: } michael@0: function createRejectPromiseFunction(promise) { michael@0: return function (reason) { michael@0: rejectPromise(promise, reason); michael@0: }; michael@0: } michael@0: function createResolvePromiseFunction(promise) { michael@0: return function (resolution) { michael@0: resolvePromise(promise, resolution); michael@0: }; michael@0: } michael@0: function createDeferredConstructionFunctions() { michael@0: var fn = function (resolve, reject) { michael@0: fn.resolve = resolve; michael@0: fn.reject = reject; michael@0: }; michael@0: return fn; michael@0: } michael@0: function createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler) { michael@0: return function (x) { michael@0: if (x === promise) { michael@0: return rejectionHandler(new TypeError('Self resolution')); michael@0: } michael@0: var cstr = promise.promiseConstructor; michael@0: if (isPromise(x)) { michael@0: var xConstructor = x.promiseConstructor; michael@0: if (xConstructor === cstr) { michael@0: return x.then(fulfillmentHandler, rejectionHandler); michael@0: } michael@0: } michael@0: var deferred = getDeferred(cstr); michael@0: var updateResult = updateDeferredFromPotentialThenable(x, deferred); michael@0: if (updateResult) { michael@0: var deferredPromise = deferred.promise; michael@0: return deferredPromise.then(fulfillmentHandler, rejectionHandler); michael@0: } michael@0: return fulfillmentHandler(x); michael@0: }; michael@0: } michael@0: function createPromiseAllCountdownFunction(index, values, deferred, countdownHolder) { michael@0: return function (x) { michael@0: values[index] = x; michael@0: countdownHolder.countdown--; michael@0: if (countdownHolder.countdown === 0) { michael@0: deferred.resolve(values); michael@0: } michael@0: }; michael@0: } michael@0: function Promise(resolver) { michael@0: if (typeof resolver !== 'function') { michael@0: throw new TypeError('resolver is not a function'); michael@0: } michael@0: var promise = this; michael@0: if (typeof promise !== 'object') { michael@0: throw new TypeError('Promise to initialize is not an object'); michael@0: } michael@0: promise.promiseStatus = 'unresolved'; michael@0: promise.resolveReactions = []; michael@0: promise.rejectReactions = []; michael@0: promise.result = undefined; michael@0: var resolve = createResolvePromiseFunction(promise); michael@0: var reject = createRejectPromiseFunction(promise); michael@0: try { michael@0: var result = resolver(resolve, reject); michael@0: } catch (e) { michael@0: rejectPromise(promise, e); michael@0: } michael@0: promise.promiseConstructor = Promise; michael@0: return promise; michael@0: } michael@0: Promise.all = function (iterable) { michael@0: var deferred = getDeferred(this); michael@0: var values = []; michael@0: var countdownHolder = { michael@0: countdown: 0 michael@0: }; michael@0: var index = 0; michael@0: iterable.forEach(function (nextValue) { michael@0: var nextPromise = this.cast(nextValue); michael@0: var fn = createPromiseAllCountdownFunction(index, values, deferred, countdownHolder); michael@0: nextPromise.then(fn, deferred.reject); michael@0: index++; michael@0: countdownHolder.countdown++; michael@0: }, this); michael@0: if (index === 0) { michael@0: deferred.resolve(values); michael@0: } michael@0: return deferred.promise; michael@0: }; michael@0: Promise.cast = function (x) { michael@0: if (isPromise(x)) { michael@0: return x; michael@0: } michael@0: var deferred = getDeferred(this); michael@0: deferred.resolve(x); michael@0: return deferred.promise; michael@0: }; michael@0: Promise.reject = function (r) { michael@0: var deferred = getDeferred(this); michael@0: var rejectResult = deferred.reject(r); michael@0: return deferred.promise; michael@0: }; michael@0: Promise.resolve = function (x) { michael@0: var deferred = getDeferred(this); michael@0: var rejectResult = deferred.resolve(x); michael@0: return deferred.promise; michael@0: }; michael@0: Promise.prototype = { michael@0: 'catch': function (onRejected) { michael@0: this.then(undefined, onRejected); michael@0: }, michael@0: then: function (onFulfilled, onRejected) { michael@0: var promise = this; michael@0: if (!isPromise(promise)) { michael@0: throw new TypeError('this is not a Promises'); michael@0: } michael@0: var cstr = promise.promiseConstructor; michael@0: var deferred = getDeferred(cstr); michael@0: var rejectionHandler = typeof onRejected === 'function' ? onRejected : throwerFunction; michael@0: var fulfillmentHandler = typeof onFulfilled === 'function' ? onFulfilled : identityFunction; michael@0: var resolutionHandler = createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler); michael@0: var resolveReaction = { michael@0: deferred: deferred, michael@0: handler: resolutionHandler michael@0: }; michael@0: var rejectReaction = { michael@0: deferred: deferred, michael@0: handler: rejectionHandler michael@0: }; michael@0: switch (promise.promiseStatus) { michael@0: case 'unresolved': michael@0: promise.resolveReactions.push(resolveReaction); michael@0: promise.rejectReactions.push(rejectReaction); michael@0: break; michael@0: case 'has-resolution': michael@0: var resolution = promise.result; michael@0: queueMicrotask({ michael@0: reaction: resolveReaction, michael@0: argument: resolution michael@0: }); michael@0: break; michael@0: case 'has-rejection': michael@0: var rejection = promise.result; michael@0: queueMicrotask({ michael@0: reaction: rejectReaction, michael@0: argument: rejection michael@0: }); michael@0: break; michael@0: } michael@0: return deferred.promise; michael@0: } michael@0: }; michael@0: global.Promise = Promise; michael@0: }()); michael@0: var QuadTree = function (x, y, width, height, parent) { michael@0: this.x = x | 0; michael@0: this.y = y | 0; michael@0: this.width = width | 0; michael@0: this.height = height | 0; michael@0: if (parent) { michael@0: this.root = parent.root; michael@0: this.parent = parent; michael@0: this.level = parent.level + 1; michael@0: } else { michael@0: this.root = this; michael@0: this.parent = null; michael@0: this.level = 0; michael@0: } michael@0: this.reset(); michael@0: }; michael@0: QuadTree.prototype.reset = function () { michael@0: this.stuckObjects = null; michael@0: this.objects = null; michael@0: this.nodes = []; michael@0: }; michael@0: QuadTree.prototype._findIndex = function (xMin, xMax, yMin, yMax) { michael@0: var midX = this.x + (this.width / 2 | 0); michael@0: var midY = this.y + (this.height / 2 | 0); michael@0: var top = yMin < midY && yMax < midY; michael@0: var bottom = yMin > midY; michael@0: if (xMin < midX && xMax < midX) { michael@0: if (top) { michael@0: return 1; michael@0: } else if (bottom) { michael@0: return 2; michael@0: } michael@0: } else if (xMin > midX) { michael@0: if (top) { michael@0: return 0; michael@0: } else if (bottom) { michael@0: return 3; michael@0: } michael@0: } michael@0: return -1; michael@0: }; michael@0: QuadTree.prototype.insert = function (obj) { michael@0: var nodes = this.nodes; michael@0: if (nodes.length) { michael@0: var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax); michael@0: if (index > -1) { michael@0: nodes[index].insert(obj); michael@0: } else { michael@0: obj.prev = null; michael@0: if (this.stuckObjects) { michael@0: obj.next = this.stuckObjects; michael@0: this.stuckObjects.prev = obj; michael@0: } else { michael@0: obj.next = null; michael@0: } michael@0: this.stuckObjects = obj; michael@0: obj.parent = this; michael@0: } michael@0: return; michael@0: } michael@0: var numChildren = 1; michael@0: var item = this.objects; michael@0: if (!item) { michael@0: obj.prev = null; michael@0: obj.next = null; michael@0: this.objects = obj; michael@0: } else { michael@0: while (item.next) { michael@0: numChildren++; michael@0: item = item.next; michael@0: } michael@0: obj.prev = item; michael@0: obj.next = null; michael@0: item.next = obj; michael@0: } michael@0: if (numChildren > 4 && this.level < 10) { michael@0: this._subdivide(); michael@0: item = this.objects; michael@0: while (item) { michael@0: var next = item.next; michael@0: this.insert(item); michael@0: item = next; michael@0: } michael@0: this.objects = null; michael@0: return; michael@0: } michael@0: obj.parent = this; michael@0: }; michael@0: QuadTree.prototype.update = function (obj) { michael@0: var node = obj.parent; michael@0: if (node) { michael@0: if (obj.xMin >= node.x && obj.xMax <= node.x + node.width && obj.yMin >= node.y && obj.yMax <= node.y + node.height) { michael@0: if (node.nodes.length) { michael@0: var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax); michael@0: if (index > -1) { michael@0: node.remove(obj); michael@0: node = this.nodes[index]; michael@0: node.insert(obj); michael@0: } michael@0: } else { michael@0: node.remove(obj); michael@0: node.insert(obj); michael@0: } michael@0: return; michael@0: } michael@0: node.remove(obj); michael@0: } michael@0: this.root.insert(obj); michael@0: }; michael@0: QuadTree.prototype.remove = function (obj) { michael@0: var prev = obj.prev; michael@0: var next = obj.next; michael@0: if (prev) { michael@0: prev.next = next; michael@0: obj.prev = null; michael@0: } else { michael@0: var node = obj.parent; michael@0: if (node.objects === obj) { michael@0: node.objects = next; michael@0: } else if (node.stuckObjects === obj) { michael@0: node.stuckObjects = next; michael@0: } michael@0: } michael@0: if (next) { michael@0: next.prev = prev; michael@0: obj.next = null; michael@0: } michael@0: obj.parent = null; michael@0: }; michael@0: QuadTree.prototype.retrieve = function (xMin, xMax, yMin, yMax) { michael@0: var stack = []; michael@0: var out = []; michael@0: var node = this; michael@0: do { michael@0: if (node.nodes.length) { michael@0: var index = node._findIndex(xMin, xMax, yMin, yMax); michael@0: if (index > -1) { michael@0: stack.push(node.nodes[index]); michael@0: } else { michael@0: stack.push.apply(stack, node.nodes); michael@0: } michael@0: } michael@0: var item = node.objects; michael@0: for (var i = 0; i < 2; i++) { michael@0: while (item) { michael@0: if (!(item.xMin > xMax || item.xMax < xMin || item.yMin > yMax || item.yMax < yMin)) { michael@0: out.push(item); michael@0: } michael@0: item = item.next; michael@0: } michael@0: item = node.stuckObjects; michael@0: } michael@0: node = stack.pop(); michael@0: } while (node); michael@0: return out; michael@0: }; michael@0: QuadTree.prototype._subdivide = function () { michael@0: var halfWidth = this.width / 2 | 0; michael@0: var halfHeight = this.height / 2 | 0; michael@0: var midX = this.x + halfWidth; michael@0: var midY = this.y + halfHeight; michael@0: this.nodes[0] = new QuadTree(midX, this.y, halfWidth, halfHeight, this); michael@0: this.nodes[1] = new QuadTree(this.x, this.y, halfWidth, halfHeight, this); michael@0: this.nodes[2] = new QuadTree(this.x, midY, halfWidth, halfHeight, this); michael@0: this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, this); michael@0: }; michael@0: var RegionCluster = function () { michael@0: this.regions = []; michael@0: }; michael@0: RegionCluster.prototype.reset = function () { michael@0: this.regions.length = 0; michael@0: }; michael@0: RegionCluster.prototype.insert = function (region) { michael@0: var regions = this.regions; michael@0: if (regions.length < 3) { michael@0: regions.push({ michael@0: xMin: region.xMin, michael@0: xMax: region.xMax, michael@0: yMin: region.yMin, michael@0: yMax: region.yMax michael@0: }); michael@0: return; michael@0: } michael@0: var a = region; michael@0: var b = regions[0]; michael@0: var c = regions[1]; michael@0: var d = regions[2]; michael@0: var ab = (max(a.xMax, b.xMax) - min(a.xMin, b.xMin)) * (max(a.yMax, b.yMax) - min(a.yMin, b.yMin)); michael@0: var rb = regions[0]; michael@0: var ac = (max(a.xMax, c.xMax) - min(a.xMin, c.xMin)) * (max(a.yMax, c.yMax) - min(a.yMin, c.yMin)); michael@0: var ad = (max(a.xMax, d.xMax) - min(a.xMin, d.xMin)) * (max(a.yMax, d.yMax) - min(a.yMin, d.yMin)); michael@0: if (ac < ab) { michael@0: ab = ac; michael@0: rb = c; michael@0: } michael@0: if (ad < ab) { michael@0: ab = ad; michael@0: rb = d; michael@0: } michael@0: var bc = (max(b.xMax, c.xMax) - min(b.xMin, c.xMin)) * (max(b.yMax, c.yMax) - min(b.yMin, c.yMin)); michael@0: var bd = (max(b.xMax, d.xMax) - min(b.xMin, d.xMin)) * (max(b.yMax, d.yMax) - min(b.yMin, d.yMin)); michael@0: var cd = (max(c.xMax, d.xMax) - min(c.xMin, d.xMin)) * (max(c.yMax, d.yMax) - min(c.yMin, d.yMin)); michael@0: if (ab < bc && ab < bd && ab < cd) { michael@0: if (a.xMin < rb.xMin) { michael@0: rb.xMin = a.xMin; michael@0: } michael@0: if (a.xMax > rb.xMax) { michael@0: rb.xMax = a.xMax; michael@0: } michael@0: if (a.yMin < rb.yMin) { michael@0: rb.yMin = a.yMin; michael@0: } michael@0: if (a.yMax > rb.yMax) { michael@0: rb.yMax = a.yMax; michael@0: } michael@0: return; michael@0: } michael@0: rb = regions[0]; michael@0: var rc = regions[1]; michael@0: if (bd < bc) { michael@0: bc = bd; michael@0: rc = regions[2]; michael@0: } michael@0: if (cd < bc) { michael@0: rb = regions[1]; michael@0: rc = regions[2]; michael@0: } michael@0: if (rc.xMin < rb.xMin) { michael@0: rb.xMin = rc.xMin; michael@0: } michael@0: if (rc.xMax > rb.xMax) { michael@0: rb.xMax = rc.xMax; michael@0: } michael@0: if (rc.yMin < rb.yMin) { michael@0: rb.yMin = rc.yMin; michael@0: } michael@0: if (rc.yMax > rb.yMax) { michael@0: rb.yMax = rc.yMax; michael@0: } michael@0: rc.xMin = a.xMin; michael@0: rc.xMax = a.xMax; michael@0: rc.yMin = a.yMin; michael@0: rc.yMax = a.yMax; michael@0: }; michael@0: RegionCluster.prototype.retrieve = function () { michael@0: return this.regions; michael@0: }; michael@0: var EXTERNAL_INTERFACE_FEATURE = 1; michael@0: var CLIPBOARD_FEATURE = 2; michael@0: var SHAREDOBJECT_FEATURE = 3; michael@0: var VIDEO_FEATURE = 4; michael@0: var SOUND_FEATURE = 5; michael@0: var NETCONNECTION_FEATURE = 6; michael@0: if (!this.performance) { michael@0: this.performance = {}; michael@0: } michael@0: if (!this.performance.now) { michael@0: this.performance.now = Date.now; michael@0: } michael@0: var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74; michael@0: var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87; michael@0: var SWF_TAG_CODE_DEFINE_BITS = 6; michael@0: var SWF_TAG_CODE_DEFINE_BITS_JPEG2 = 21; michael@0: var SWF_TAG_CODE_DEFINE_BITS_JPEG3 = 35; michael@0: var SWF_TAG_CODE_DEFINE_BITS_JPEG4 = 90; michael@0: var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS = 20; michael@0: var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2 = 36; michael@0: var SWF_TAG_CODE_DEFINE_BUTTON = 7; michael@0: var SWF_TAG_CODE_DEFINE_BUTTON2 = 34; michael@0: var SWF_TAG_CODE_DEFINE_BUTTON_CXFORM = 23; michael@0: var SWF_TAG_CODE_DEFINE_BUTTON_SOUND = 17; michael@0: var SWF_TAG_CODE_DEFINE_EDIT_TEXT = 37; michael@0: var SWF_TAG_CODE_DEFINE_FONT = 10; michael@0: var SWF_TAG_CODE_DEFINE_FONT2 = 48; michael@0: var SWF_TAG_CODE_DEFINE_FONT3 = 75; michael@0: var SWF_TAG_CODE_DEFINE_FONT4 = 91; michael@0: var SWF_TAG_CODE_DEFINE_FONT_ALIGN_ZONES = 73; michael@0: var SWF_TAG_CODE_DEFINE_FONT_INFO = 13; michael@0: var SWF_TAG_CODE_DEFINE_FONT_INFO2 = 62; michael@0: var SWF_TAG_CODE_DEFINE_FONT_NAME = 88; michael@0: var SWF_TAG_CODE_DEFINE_MORPH_SHAPE = 46; michael@0: var SWF_TAG_CODE_DEFINE_MORPH_SHAPE2 = 84; michael@0: var SWF_TAG_CODE_DEFINE_SCALING_GRID = 78; michael@0: var SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA = 86; michael@0: var SWF_TAG_CODE_DEFINE_SHAPE = 2; michael@0: var SWF_TAG_CODE_DEFINE_SHAPE2 = 22; michael@0: var SWF_TAG_CODE_DEFINE_SHAPE3 = 32; michael@0: var SWF_TAG_CODE_DEFINE_SHAPE4 = 83; michael@0: var SWF_TAG_CODE_DEFINE_SOUND = 14; michael@0: var SWF_TAG_CODE_DEFINE_SPRITE = 39; michael@0: var SWF_TAG_CODE_DEFINE_TEXT = 11; michael@0: var SWF_TAG_CODE_DEFINE_TEXT2 = 33; michael@0: var SWF_TAG_CODE_DEFINE_VIDEO_STREAM = 60; michael@0: var SWF_TAG_CODE_DO_ABC = 82; michael@0: var SWF_TAG_CODE_DO_ABC_ = 72; michael@0: var SWF_TAG_CODE_DO_ACTION = 12; michael@0: var SWF_TAG_CODE_DO_INIT_ACTION = 59; michael@0: var SWF_TAG_CODE_ENABLE_DEBUGGER = 58; michael@0: var SWF_TAG_CODE_ENABLE_DEBUGGER2 = 64; michael@0: var SWF_TAG_CODE_END = 0; michael@0: var SWF_TAG_CODE_EXPORT_ASSETS = 56; michael@0: var SWF_TAG_CODE_FILE_ATTRIBUTES = 69; michael@0: var SWF_TAG_CODE_FRAME_LABEL = 43; michael@0: var SWF_TAG_CODE_IMPORT_ASSETS = 57; michael@0: var SWF_TAG_CODE_IMPORT_ASSETS2 = 71; michael@0: var SWF_TAG_CODE_JPEG_TABLES = 8; michael@0: var SWF_TAG_CODE_METADATA = 77; michael@0: var SWF_TAG_CODE_PLACE_OBJECT = 4; michael@0: var SWF_TAG_CODE_PLACE_OBJECT2 = 26; michael@0: var SWF_TAG_CODE_PLACE_OBJECT3 = 70; michael@0: var SWF_TAG_CODE_PROTECT = 24; michael@0: var SWF_TAG_CODE_REMOVE_OBJECT = 5; michael@0: var SWF_TAG_CODE_REMOVE_OBJECT2 = 28; michael@0: var SWF_TAG_CODE_SCRIPT_LIMITS = 65; michael@0: var SWF_TAG_CODE_SET_BACKGROUND_COLOR = 9; michael@0: var SWF_TAG_CODE_SET_TAB_INDEX = 66; michael@0: var SWF_TAG_CODE_SHOW_FRAME = 1; michael@0: var SWF_TAG_CODE_SOUND_STREAM_BLOCK = 19; michael@0: var SWF_TAG_CODE_SOUND_STREAM_HEAD = 18; michael@0: var SWF_TAG_CODE_SOUND_STREAM_HEAD2 = 45; michael@0: var SWF_TAG_CODE_START_SOUND = 15; michael@0: var SWF_TAG_CODE_START_SOUND2 = 89; michael@0: var SWF_TAG_CODE_SYMBOL_CLASS = 76; michael@0: var SWF_TAG_CODE_VIDEO_FRAME = 61; michael@0: self.SWF = {}; michael@0: var codeLengthOrder = [ michael@0: 16, michael@0: 17, michael@0: 18, michael@0: 0, michael@0: 8, michael@0: 7, michael@0: 9, michael@0: 6, michael@0: 10, michael@0: 5, michael@0: 11, michael@0: 4, michael@0: 12, michael@0: 3, michael@0: 13, michael@0: 2, michael@0: 14, michael@0: 1, michael@0: 15 michael@0: ]; michael@0: var distanceCodes = []; michael@0: var distanceExtraBits = []; michael@0: for (var i = 0, j = 0, code = 1; i < 30; ++i) { michael@0: distanceCodes[i] = code; michael@0: code += 1 << (distanceExtraBits[i] = ~(~((j += i > 2 ? 1 : 0) / 2))); michael@0: } michael@0: var bitLengths = []; michael@0: for (var i = 0; i < 32; ++i) michael@0: bitLengths[i] = 5; michael@0: var fixedDistanceTable = makeHuffmanTable(bitLengths); michael@0: var lengthCodes = []; michael@0: var lengthExtraBits = []; michael@0: for (var i = 0, j = 0, code = 3; i < 29; ++i) { michael@0: lengthCodes[i] = code - (i == 28 ? 1 : 0); michael@0: code += 1 << (lengthExtraBits[i] = ~(~((j += i > 4 ? 1 : 0) / 4 % 6))); michael@0: } michael@0: for (var i = 0; i < 288; ++i) michael@0: bitLengths[i] = i < 144 || i > 279 ? 8 : i < 256 ? 9 : 7; michael@0: var fixedLiteralTable = makeHuffmanTable(bitLengths); michael@0: function makeHuffmanTable(bitLengths) { michael@0: var maxBits = Math.max.apply(null, bitLengths); michael@0: var numLengths = bitLengths.length; michael@0: var size = 1 << maxBits; michael@0: var codes = new Uint32Array(size); michael@0: for (var code = 0, len = 1, skip = 2; len <= maxBits; code <<= 1, ++len, skip <<= 1) { michael@0: for (var val = 0; val < numLengths; ++val) { michael@0: if (bitLengths[val] === len) { michael@0: var lsb = 0; michael@0: for (var i = 0; i < len; ++i) michael@0: lsb = lsb * 2 + (code >> i & 1); michael@0: for (var i = lsb; i < size; i += skip) michael@0: codes[i] = len << 16 | val; michael@0: ++code; michael@0: } michael@0: } michael@0: } michael@0: return { michael@0: codes: codes, michael@0: maxBits: maxBits michael@0: }; michael@0: } michael@0: function verifyDeflateHeader(bytes) { michael@0: var header = bytes[0] << 8 | bytes[1]; michael@0: } michael@0: function createInflatedStream(bytes, outputLength) { michael@0: verifyDeflateHeader(bytes); michael@0: var stream = new Stream(bytes, 2); michael@0: var output = { michael@0: data: new Uint8Array(outputLength), michael@0: available: 0, michael@0: completed: false michael@0: }; michael@0: var state = { michael@0: header: null, michael@0: distanceTable: null, michael@0: literalTable: null, michael@0: sym: null, michael@0: len: null, michael@0: sym2: null michael@0: }; michael@0: do { michael@0: inflateBlock(stream, output, state); michael@0: } while (!output.completed && stream.pos < stream.end); michael@0: return new Stream(output.data, 0, output.available); michael@0: } michael@0: var InflateNoDataError = {}; michael@0: function inflateBlock(stream, output, state) { michael@0: var header = state.header !== null ? state.header : state.header = readBits(stream.bytes, stream, 3); michael@0: switch (header >> 1) { michael@0: case 0: michael@0: stream.align(); michael@0: var pos = stream.pos; michael@0: if (stream.end - pos < 4) { michael@0: throw InflateNoDataError; michael@0: } michael@0: var len = stream.getUint16(pos, true); michael@0: var nlen = stream.getUint16(pos + 2, true); michael@0: if (stream.end - pos < 4 + len) { michael@0: throw InflateNoDataError; michael@0: } michael@0: var begin = pos + 4; michael@0: var end = stream.pos = begin + len; michael@0: var sbytes = stream.bytes, dbytes = output.data; michael@0: dbytes.set(sbytes.subarray(begin, end), output.available); michael@0: output.available += len; michael@0: break; michael@0: case 1: michael@0: inflate(stream, output, fixedLiteralTable, fixedDistanceTable, state); michael@0: break; michael@0: case 2: michael@0: var distanceTable, literalTable; michael@0: if (state.distanceTable !== null) { michael@0: distanceTable = state.distanceTable; michael@0: literalTable = state.literalTable; michael@0: } else { michael@0: var sbytes = stream.bytes; michael@0: var savedBufferPos = stream.pos; michael@0: var savedBitBuffer = stream.bitBuffer; michael@0: var savedBitLength = stream.bitLength; michael@0: var bitLengths = []; michael@0: var numLiteralCodes, numDistanceCodes; michael@0: try { michael@0: numLiteralCodes = readBits(sbytes, stream, 5) + 257; michael@0: numDistanceCodes = readBits(sbytes, stream, 5) + 1; michael@0: var numCodes = numLiteralCodes + numDistanceCodes; michael@0: var numLengthCodes = readBits(sbytes, stream, 4) + 4; michael@0: for (var i = 0; i < 19; ++i) michael@0: bitLengths[codeLengthOrder[i]] = i < numLengthCodes ? readBits(sbytes, stream, 3) : 0; michael@0: var codeLengthTable = makeHuffmanTable(bitLengths); michael@0: bitLengths = []; michael@0: var i = 0; michael@0: var prev = 0; michael@0: while (i < numCodes) { michael@0: var j = 1; michael@0: var sym = readCode(sbytes, stream, codeLengthTable); michael@0: switch (sym) { michael@0: case 16: michael@0: j = readBits(sbytes, stream, 2) + 3; michael@0: sym = prev; michael@0: break; michael@0: case 17: michael@0: j = readBits(sbytes, stream, 3) + 3; michael@0: sym = 0; michael@0: break; michael@0: case 18: michael@0: j = readBits(sbytes, stream, 7) + 11; michael@0: sym = 0; michael@0: break; michael@0: default: michael@0: prev = sym; michael@0: } michael@0: while (j--) michael@0: bitLengths[i++] = sym; michael@0: } michael@0: } catch (e) { michael@0: stream.pos = savedBufferPos; michael@0: stream.bitBuffer = savedBitBuffer; michael@0: stream.bitLength = savedBitLength; michael@0: throw e; michael@0: } michael@0: distanceTable = state.distanceTable = makeHuffmanTable(bitLengths.splice(numLiteralCodes, numDistanceCodes)); michael@0: literalTable = state.literalTable = makeHuffmanTable(bitLengths); michael@0: } michael@0: inflate(stream, output, literalTable, distanceTable, state); michael@0: state.distanceTable = null; michael@0: state.literalTable = null; michael@0: break; michael@0: default: michael@0: fail('unknown block type', 'inflate'); michael@0: } michael@0: state.header = null; michael@0: output.completed = !(!(header & 1)); michael@0: } michael@0: function readBits(bytes, stream, size) { michael@0: var bitBuffer = stream.bitBuffer; michael@0: var bitLength = stream.bitLength; michael@0: if (size > bitLength) { michael@0: var pos = stream.pos; michael@0: var end = stream.end; michael@0: do { michael@0: if (pos >= end) { michael@0: stream.pos = pos; michael@0: stream.bitBuffer = bitBuffer; michael@0: stream.bitLength = bitLength; michael@0: throw InflateNoDataError; michael@0: } michael@0: bitBuffer |= bytes[pos++] << bitLength; michael@0: bitLength += 8; michael@0: } while (size > bitLength); michael@0: stream.pos = pos; michael@0: } michael@0: stream.bitBuffer = bitBuffer >>> size; michael@0: stream.bitLength = bitLength - size; michael@0: return bitBuffer & (1 << size) - 1; michael@0: } michael@0: function inflate(stream, output, literalTable, distanceTable, state) { michael@0: var pos = output.available; michael@0: var dbytes = output.data; michael@0: var sbytes = stream.bytes; michael@0: var sym = state.sym !== null ? state.sym : readCode(sbytes, stream, literalTable); michael@0: while (sym !== 256) { michael@0: if (sym < 256) { michael@0: dbytes[pos++] = sym; michael@0: } else { michael@0: state.sym = sym; michael@0: sym -= 257; michael@0: var len = state.len !== null ? state.len : state.len = lengthCodes[sym] + readBits(sbytes, stream, lengthExtraBits[sym]); michael@0: var sym2 = state.sym2 !== null ? state.sym2 : state.sym2 = readCode(sbytes, stream, distanceTable); michael@0: var distance = distanceCodes[sym2] + readBits(sbytes, stream, distanceExtraBits[sym2]); michael@0: var i = pos - distance; michael@0: while (len--) michael@0: dbytes[pos++] = dbytes[i++]; michael@0: state.sym2 = null; michael@0: state.len = null; michael@0: state.sym = null; michael@0: } michael@0: output.available = pos; michael@0: sym = readCode(sbytes, stream, literalTable); michael@0: } michael@0: } michael@0: function readCode(bytes, stream, codeTable) { michael@0: var bitBuffer = stream.bitBuffer; michael@0: var bitLength = stream.bitLength; michael@0: var maxBits = codeTable.maxBits; michael@0: if (maxBits > bitLength) { michael@0: var pos = stream.pos; michael@0: var end = stream.end; michael@0: do { michael@0: if (pos >= end) { michael@0: stream.pos = pos; michael@0: stream.bitBuffer = bitBuffer; michael@0: stream.bitLength = bitLength; michael@0: throw InflateNoDataError; michael@0: } michael@0: bitBuffer |= bytes[pos++] << bitLength; michael@0: bitLength += 8; michael@0: } while (maxBits > bitLength); michael@0: stream.pos = pos; michael@0: } michael@0: var code = codeTable.codes[bitBuffer & (1 << maxBits) - 1]; michael@0: var len = code >> 16; michael@0: stream.bitBuffer = bitBuffer >>> len; michael@0: stream.bitLength = bitLength - len; michael@0: return code & 65535; michael@0: } michael@0: var StreamNoDataError = {}; michael@0: var Stream = function StreamClosure() { michael@0: function Stream_align() { michael@0: this.bitBuffer = this.bitLength = 0; michael@0: } michael@0: function Stream_ensure(size) { michael@0: if (this.pos + size > this.end) { michael@0: throw StreamNoDataError; michael@0: } michael@0: } michael@0: function Stream_remaining() { michael@0: return this.end - this.pos; michael@0: } michael@0: function Stream_substream(begin, end) { michael@0: var stream = new Stream(this.bytes); michael@0: stream.pos = begin; michael@0: stream.end = end; michael@0: return stream; michael@0: } michael@0: function Stream_push(data) { michael@0: var bytes = this.bytes; michael@0: var newBytesLength = this.end + data.length; michael@0: if (newBytesLength > bytes.length) { michael@0: throw 'stream buffer overfow'; michael@0: } michael@0: bytes.set(data, this.end); michael@0: this.end = newBytesLength; michael@0: } michael@0: function Stream(buffer, offset, length, maxLength) { michael@0: if (offset === undefined) michael@0: offset = 0; michael@0: if (buffer.buffer instanceof ArrayBuffer) { michael@0: offset += buffer.byteOffset; michael@0: buffer = buffer.buffer; michael@0: } michael@0: if (length === undefined) michael@0: length = buffer.byteLength - offset; michael@0: if (maxLength === undefined) michael@0: maxLength = length; michael@0: var bytes = new Uint8Array(buffer, offset, maxLength); michael@0: var stream = new DataView(buffer, offset, maxLength); michael@0: stream.bytes = bytes; michael@0: stream.pos = 0; michael@0: stream.end = length; michael@0: stream.bitBuffer = 0; michael@0: stream.bitLength = 0; michael@0: stream.align = Stream_align; michael@0: stream.ensure = Stream_ensure; michael@0: stream.remaining = Stream_remaining; michael@0: stream.substream = Stream_substream; michael@0: stream.push = Stream_push; michael@0: return stream; michael@0: } michael@0: return Stream; michael@0: }(); michael@0: var FORMAT_COLORMAPPED = 3; michael@0: var FORMAT_15BPP = 4; michael@0: var FORMAT_24BPP = 5; michael@0: var FACTOR_5BBP = 255 / 31; michael@0: var crcTable = []; michael@0: for (var i = 0; i < 256; i++) { michael@0: var c = i; michael@0: for (var h = 0; h < 8; h++) { michael@0: if (c & 1) michael@0: c = 3988292384 ^ c >> 1 & 2147483647; michael@0: else michael@0: c = c >> 1 & 2147483647; michael@0: } michael@0: crcTable[i] = c; michael@0: } michael@0: function crc32(data, start, end) { michael@0: var crc = -1; michael@0: for (var i = start; i < end; i++) { michael@0: var a = (crc ^ data[i]) & 255; michael@0: var b = crcTable[a]; michael@0: crc = crc >>> 8 ^ b; michael@0: } michael@0: return crc ^ -1; michael@0: } michael@0: function createPngChunk(type, data) { michael@0: var chunk = new Uint8Array(12 + data.length); michael@0: var p = 0; michael@0: var len = data.length; michael@0: chunk[p] = len >> 24 & 255; michael@0: chunk[p + 1] = len >> 16 & 255; michael@0: chunk[p + 2] = len >> 8 & 255; michael@0: chunk[p + 3] = len & 255; michael@0: chunk[p + 4] = type.charCodeAt(0) & 255; michael@0: chunk[p + 5] = type.charCodeAt(1) & 255; michael@0: chunk[p + 6] = type.charCodeAt(2) & 255; michael@0: chunk[p + 7] = type.charCodeAt(3) & 255; michael@0: if (data instanceof Uint8Array) michael@0: chunk.set(data, 8); michael@0: p = 8 + len; michael@0: var crc = crc32(chunk, 4, p); michael@0: chunk[p] = crc >> 24 & 255; michael@0: chunk[p + 1] = crc >> 16 & 255; michael@0: chunk[p + 2] = crc >> 8 & 255; michael@0: chunk[p + 3] = crc & 255; michael@0: return chunk; michael@0: } michael@0: function adler32(data, start, end) { michael@0: var a = 1; michael@0: var b = 0; michael@0: for (var i = start; i < end; ++i) { michael@0: a = (a + (data[i] & 255)) % 65521; michael@0: b = (b + a) % 65521; michael@0: } michael@0: return b << 16 | a; michael@0: } michael@0: function defineBitmap(tag) { michael@0: var width = tag.width; michael@0: var height = tag.height; michael@0: var hasAlpha = tag.hasAlpha; michael@0: var plte = ''; michael@0: var trns = ''; michael@0: var literals; michael@0: var bmpData = tag.bmpData; michael@0: switch (tag.format) { michael@0: case FORMAT_COLORMAPPED: michael@0: var colorType = 3; michael@0: var bytesPerLine = width + 3 & ~3; michael@0: var colorTableSize = tag.colorTableSize + 1; michael@0: var paletteSize = colorTableSize * (tag.hasAlpha ? 4 : 3); michael@0: var datalen = paletteSize + bytesPerLine * height; michael@0: var stream = createInflatedStream(bmpData, datalen); michael@0: var bytes = stream.bytes; michael@0: var pos = 0; michael@0: stream.ensure(paletteSize); michael@0: if (hasAlpha) { michael@0: var palette = new Uint8Array(paletteSize / 4 * 3); michael@0: var pp = 0; michael@0: var alphaValues = new Uint8Array(paletteSize / 4); michael@0: var pa = 0; michael@0: while (pos < paletteSize) { michael@0: palette[pp++] = bytes[pos]; michael@0: palette[pp++] = bytes[pos + 1]; michael@0: palette[pp++] = bytes[pos + 2]; michael@0: alphaValues[pa++] = bytes[pos + 3]; michael@0: pos += 4; michael@0: } michael@0: plte = createPngChunk('PLTE', palette); michael@0: trns = createPngChunk('tRNS', alphaValues); michael@0: } else { michael@0: plte = createPngChunk('PLTE', bytes.subarray(pos, pos + paletteSize)); michael@0: pos += paletteSize; michael@0: } michael@0: literals = new Uint8Array(width * height + height); michael@0: var pl = 0; michael@0: while (pos < datalen) { michael@0: stream.ensure(bytesPerLine); michael@0: var begin = pos; michael@0: var end = begin + width; michael@0: pl++; michael@0: literals.set(bytes.subarray(begin, end), pl); michael@0: pl += end - begin; michael@0: stream.pos = pos += bytesPerLine; michael@0: } michael@0: break; michael@0: case FORMAT_15BPP: michael@0: var colorType = 2; michael@0: var bytesPerLine = width * 2 + 3 & ~3; michael@0: var stream = createInflatedStream(bmpData, bytesPerLine * height); michael@0: var pos = 0; michael@0: literals = new Uint8Array(width * height * 3 + height); michael@0: var pl = 0; michael@0: for (var y = 0; y < height; ++y) { michael@0: pl++; michael@0: stream.ensure(bytesPerLine); michael@0: for (var x = 0; x < width; ++x) { michael@0: var word = stream.getUint16(pos); michael@0: pos += 2; michael@0: literals[pl++] = 0 | FACTOR_5BBP * (word >> 10 & 31); michael@0: literals[pl++] = 0 | FACTOR_5BBP * (word >> 5 & 31); michael@0: literals[pl++] = 0 | FACTOR_5BBP * (word & 31); michael@0: } michael@0: stream.pos = pos += bytesPerLine; michael@0: } michael@0: break; michael@0: case FORMAT_24BPP: michael@0: var padding; michael@0: if (hasAlpha) { michael@0: var colorType = 6; michael@0: padding = 0; michael@0: literals = new Uint8Array(width * height * 4 + height); michael@0: } else { michael@0: var colorType = 2; michael@0: padding = 1; michael@0: literals = new Uint8Array(width * height * 3 + height); michael@0: } michael@0: var bytesPerLine = width * 4; michael@0: var stream = createInflatedStream(bmpData, bytesPerLine * height); michael@0: var bytes = stream.bytes; michael@0: var pos = 0; michael@0: var pl = 0; michael@0: for (var y = 0; y < height; ++y) { michael@0: stream.ensure(bytesPerLine); michael@0: pl++; michael@0: for (var x = 0; x < width; ++x) { michael@0: pos += padding; michael@0: if (hasAlpha) { michael@0: var alpha = bytes[pos]; michael@0: if (alpha) { michael@0: var opacity = alpha / 255; michael@0: literals[pl++] = 0 | bytes[pos + 1] / opacity; michael@0: literals[pl++] = 0 | bytes[pos + 2] / opacity; michael@0: literals[pl++] = 0 | bytes[pos + 3] / opacity; michael@0: literals[pl++] = alpha; michael@0: } else { michael@0: pl += 4; michael@0: } michael@0: } else { michael@0: literals[pl++] = bytes[pos]; michael@0: literals[pl++] = bytes[pos + 1]; michael@0: literals[pl++] = bytes[pos + 2]; michael@0: } michael@0: pos += 4 - padding; michael@0: } michael@0: stream.pos = pos; michael@0: } michael@0: break; michael@0: default: michael@0: fail('invalid format', 'bitmap'); michael@0: } michael@0: var ihdr = new Uint8Array([ michael@0: width >> 24 & 255, michael@0: width >> 16 & 255, michael@0: width >> 8 & 255, michael@0: width & 255, michael@0: height >> 24 & 255, michael@0: height >> 16 & 255, michael@0: height >> 8 & 255, michael@0: height & 255, michael@0: 8, michael@0: colorType, michael@0: 0, michael@0: 0, michael@0: 0 michael@0: ]); michael@0: var len = literals.length; michael@0: var maxBlockLength = 65535; michael@0: var idat = new Uint8Array(2 + len + Math.ceil(len / maxBlockLength) * 5 + 4); michael@0: var pi = 0; michael@0: idat[pi++] = 120; michael@0: idat[pi++] = 156; michael@0: var pos = 0; michael@0: while (len > maxBlockLength) { michael@0: idat[pi++] = 0; michael@0: idat[pi++] = 255; michael@0: idat[pi++] = 255; michael@0: idat[pi++] = 0; michael@0: idat[pi++] = 0; michael@0: idat.set(literals.subarray(pos, pos + maxBlockLength), pi); michael@0: pi += maxBlockLength; michael@0: pos += maxBlockLength; michael@0: len -= maxBlockLength; michael@0: } michael@0: idat[pi++] = 1; michael@0: idat[pi++] = len & 255; michael@0: idat[pi++] = len >> 8 & 255; michael@0: idat[pi++] = ~len & 65535 & 255; michael@0: idat[pi++] = (~len & 65535) >> 8 & 255; michael@0: idat.set(literals.subarray(pos), pi); michael@0: pi += literals.length - pos; michael@0: var adler = adler32(literals, 0, literals.length); michael@0: idat[pi++] = adler >> 24 & 255; michael@0: idat[pi++] = adler >> 16 & 255; michael@0: idat[pi++] = adler >> 8 & 255; michael@0: idat[pi++] = adler & 255; michael@0: var chunks = [ michael@0: new Uint8Array([ michael@0: 137, michael@0: 80, michael@0: 78, michael@0: 71, michael@0: 13, michael@0: 10, michael@0: 26, michael@0: 10 michael@0: ]), michael@0: createPngChunk('IHDR', ihdr), michael@0: plte, michael@0: trns, michael@0: createPngChunk('IDAT', idat), michael@0: createPngChunk('IEND', '') michael@0: ]; michael@0: return { michael@0: type: 'image', michael@0: id: tag.id, michael@0: width: width, michael@0: height: height, michael@0: mimeType: 'image/png', michael@0: data: new Blob(chunks, { michael@0: type: 'image/png' michael@0: }) michael@0: }; michael@0: } michael@0: function defineButton(tag, dictionary) { michael@0: var characters = tag.characters; michael@0: var states = { michael@0: up: {}, michael@0: over: {}, michael@0: down: {}, michael@0: hitTest: {} michael@0: }; michael@0: var i = 0, character; michael@0: while (character = characters[i++]) { michael@0: if (character.eob) michael@0: break; michael@0: var characterItem = dictionary[character.symbolId]; michael@0: var entry = { michael@0: symbolId: characterItem.id, michael@0: hasMatrix: !(!character.matrix), michael@0: matrix: character.matrix michael@0: }; michael@0: if (character.stateUp) michael@0: states.up[character.depth] = entry; michael@0: if (character.stateOver) michael@0: states.over[character.depth] = entry; michael@0: if (character.stateDown) michael@0: states.down[character.depth] = entry; michael@0: if (character.stateHitTest) michael@0: states.hitTest[character.depth] = entry; michael@0: } michael@0: var button = { michael@0: type: 'button', michael@0: id: tag.id, michael@0: buttonActions: tag.buttonActions, michael@0: states: states michael@0: }; michael@0: return button; michael@0: } michael@0: var nextFontId = 1; michael@0: function maxPower2(num) { michael@0: var maxPower = 0; michael@0: var val = num; michael@0: while (val >= 2) { michael@0: val /= 2; michael@0: ++maxPower; michael@0: } michael@0: return pow(2, maxPower); michael@0: } michael@0: function toString16(val) { michael@0: return fromCharCode(val >> 8 & 255, val & 255); michael@0: } michael@0: function toString32(val) { michael@0: return toString16(val >> 16) + toString16(val); michael@0: } michael@0: function defineFont(tag, dictionary) { michael@0: var tables = {}; michael@0: var codes = []; michael@0: var glyphIndex = {}; michael@0: var ranges = []; michael@0: var glyphs = tag.glyphs; michael@0: var glyphCount = glyphs.length; michael@0: if (tag.codes) { michael@0: codes = codes.concat(tag.codes); michael@0: for (var i = 0, code; code = codes[i]; ++i) michael@0: glyphIndex[code] = i; michael@0: codes.sort(function (a, b) { michael@0: return a - b; michael@0: }); michael@0: var i = 0; michael@0: var code; michael@0: while (code = codes[i++]) { michael@0: var start = code; michael@0: var end = start; michael@0: var indices = [ michael@0: i - 1 michael@0: ]; michael@0: while ((code = codes[i]) && end + 1 === code) { michael@0: ++end; michael@0: indices.push(i); michael@0: ++i; michael@0: } michael@0: ranges.push([ michael@0: start, michael@0: end, michael@0: indices michael@0: ]); michael@0: } michael@0: } else { michael@0: var indices = []; michael@0: var UAC_OFFSET = 57344; michael@0: for (var i = 0; i < glyphCount; i++) { michael@0: var code = UAC_OFFSET + i; michael@0: codes.push(code); michael@0: glyphIndex[code] = i; michael@0: indices.push(i); michael@0: } michael@0: ranges.push([ michael@0: UAC_OFFSET, michael@0: UAC_OFFSET + glyphCount - 1, michael@0: indices michael@0: ]); michael@0: } michael@0: var resolution = tag.resolution || 1; michael@0: var ascent = Math.ceil(tag.ascent / resolution) || 1024; michael@0: var descent = -Math.ceil(tag.descent / resolution) | 0; michael@0: var leading = tag.leading / resolution | 0; michael@0: tables['OS/2'] = '\0\x01\0\0' + toString16(tag.bold ? 700 : 400) + '\0\x05' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0\0\0\0\0\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + 'ALF ' + toString16((tag.italic ? 1 : 0) | (tag.bold ? 32 : 0)) + toString16(codes[0]) + toString16(codes[codes.length - 1]) + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(ascent) + toString16(-descent) + '\0\0\0\0' + '\0\0\0\0'; michael@0: ; michael@0: var startCount = ''; michael@0: var endCount = ''; michael@0: var idDelta = ''; michael@0: var idRangeOffset = ''; michael@0: var i = 0; michael@0: var range; michael@0: while (range = ranges[i++]) { michael@0: var start = range[0]; michael@0: var end = range[1]; michael@0: var code = range[2][0]; michael@0: startCount += toString16(start); michael@0: endCount += toString16(end); michael@0: idDelta += toString16(code - start + 1 & 65535); michael@0: idRangeOffset += toString16(0); michael@0: } michael@0: endCount += '\xff\xff'; michael@0: startCount += '\xff\xff'; michael@0: idDelta += '\0\x01'; michael@0: idRangeOffset += '\0\0'; michael@0: var segCount = ranges.length + 1; michael@0: var searchRange = maxPower2(segCount) * 2; michael@0: var rangeShift = 2 * segCount - searchRange; michael@0: var format314 = '\0\0' + toString16(segCount * 2) + toString16(searchRange) + toString16(logE(segCount) / logE(2)) + toString16(rangeShift) + endCount + '\0\0' + startCount + idDelta + idRangeOffset; michael@0: ; michael@0: tables['cmap'] = '\0\0\0\x01\0\x03\0\x01\0\0\0\f\0\x04' + toString16(format314.length + 4) + format314; michael@0: ; michael@0: var glyf = '\0\x01\0\0\0\0\0\0\0\0\0\0\0\x001\0'; michael@0: var loca = '\0\0'; michael@0: var offset = 16; michael@0: var maxPoints = 0; michael@0: var xMins = []; michael@0: var xMaxs = []; michael@0: var yMins = []; michael@0: var yMaxs = []; michael@0: var maxContours = 0; michael@0: var i = 0; michael@0: var code; michael@0: while (code = codes[i++]) { michael@0: var glyph = glyphs[glyphIndex[code]]; michael@0: var records = glyph.records; michael@0: var numberOfContours = 1; michael@0: var endPoint = 0; michael@0: var endPtsOfContours = ''; michael@0: var flags = ''; michael@0: var xCoordinates = ''; michael@0: var yCoordinates = ''; michael@0: var x = 0; michael@0: var y = 0; michael@0: var xMin = 1024; michael@0: var xMax = -1024; michael@0: var yMin = 1024; michael@0: var yMax = -1024; michael@0: for (var j = 0, record; record = records[j]; ++j) { michael@0: if (record.type) { michael@0: if (record.isStraight) { michael@0: if (record.isGeneral) { michael@0: flags += '\x01'; michael@0: var dx = record.deltaX / resolution; michael@0: var dy = -record.deltaY / resolution; michael@0: xCoordinates += toString16(dx); michael@0: yCoordinates += toString16(dy); michael@0: x += dx; michael@0: y += dy; michael@0: } else if (record.isVertical) { michael@0: flags += '\x11'; michael@0: var dy = -record.deltaY / resolution; michael@0: yCoordinates += toString16(dy); michael@0: y += dy; michael@0: } else { michael@0: flags += '!'; michael@0: var dx = record.deltaX / resolution; michael@0: xCoordinates += toString16(dx); michael@0: x += dx; michael@0: } michael@0: } else { michael@0: flags += '\0'; michael@0: var cx = record.controlDeltaX / resolution; michael@0: var cy = -record.controlDeltaY / resolution; michael@0: xCoordinates += toString16(cx); michael@0: yCoordinates += toString16(cy); michael@0: flags += '\x01'; michael@0: var dx = record.anchorDeltaX / resolution; michael@0: var dy = -record.anchorDeltaY / resolution; michael@0: xCoordinates += toString16(dx); michael@0: yCoordinates += toString16(dy); michael@0: ++endPoint; michael@0: x += cx + dx; michael@0: y += cy + dy; michael@0: } michael@0: if (x < xMin) michael@0: xMin = x; michael@0: if (x > xMax) michael@0: xMax = x; michael@0: if (y < yMin) michael@0: yMin = y; michael@0: if (y > yMax) michael@0: yMax = y; michael@0: ++endPoint; michael@0: } else { michael@0: if (record.eos) michael@0: break; michael@0: if (record.move) { michael@0: if (endPoint) { michael@0: ++numberOfContours; michael@0: endPtsOfContours += toString16(endPoint - 1); michael@0: } michael@0: flags += '\x01'; michael@0: var moveX = record.moveX / resolution; michael@0: var moveY = -record.moveY / resolution; michael@0: var dx = moveX - x; michael@0: var dy = moveY - y; michael@0: xCoordinates += toString16(dx); michael@0: yCoordinates += toString16(dy); michael@0: x = moveX; michael@0: y = moveY; michael@0: if (endPoint > maxPoints) michael@0: maxPoints = endPoint; michael@0: if (x < xMin) michael@0: xMin = x; michael@0: if (x > xMax) michael@0: xMax = x; michael@0: if (y < yMin) michael@0: yMin = y; michael@0: if (y > yMax) michael@0: yMax = y; michael@0: ++endPoint; michael@0: } michael@0: } michael@0: } michael@0: endPtsOfContours += toString16((endPoint || 1) - 1); michael@0: if (!j) { michael@0: xMin = xMax = yMin = yMax = 0; michael@0: flags += '1'; michael@0: } michael@0: var entry = toString16(numberOfContours) + toString16(xMin) + toString16(yMin) + toString16(xMax) + toString16(yMax) + endPtsOfContours + '\0\0' + flags + xCoordinates + yCoordinates; michael@0: ; michael@0: if (entry.length & 1) michael@0: entry += '\0'; michael@0: glyf += entry; michael@0: loca += toString16(offset / 2); michael@0: offset += entry.length; michael@0: xMins.push(xMin); michael@0: xMaxs.push(xMax); michael@0: yMins.push(yMin); michael@0: yMaxs.push(yMax); michael@0: if (numberOfContours > maxContours) michael@0: maxContours = numberOfContours; michael@0: if (endPoint > maxPoints) michael@0: maxPoints = endPoint; michael@0: } michael@0: loca += toString16(offset / 2); michael@0: tables['glyf'] = glyf; michael@0: tables['head'] = '\0\x01\0\0\0\x01\0\0\0\0\0\0_\x0f<\xf5\0\v\x04\0\0\0\0\0' + toString32(Date.now()) + '\0\0\0\0' + toString32(Date.now()) + toString16(min.apply(null, xMins)) + toString16(min.apply(null, yMins)) + toString16(max.apply(null, xMaxs)) + toString16(max.apply(null, yMaxs)) + toString16((tag.italic ? 2 : 0) | (tag.bold ? 1 : 0)) + '\0\b' + '\0\x02' + '\0\0' + '\0\0'; michael@0: ; michael@0: var advance = tag.advance; michael@0: tables['hhea'] = '\0\x01\0\0' + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(advance ? max.apply(null, advance) : 1024) + '\0\0' + '\0\0' + '\x03\xb8' + '\0\x01' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + toString16(glyphCount + 1); michael@0: ; michael@0: var hmtx = '\0\0\0\0'; michael@0: for (var i = 0; i < glyphCount; ++i) michael@0: hmtx += toString16(advance ? advance[i] / resolution : 1024) + '\0\0'; michael@0: tables['hmtx'] = hmtx; michael@0: if (tag.kerning) { michael@0: var kerning = tag.kerning; michael@0: var nPairs = kerning.length; michael@0: var searchRange = maxPower2(nPairs) * 2; michael@0: var kern = '\0\0\0\x01\0\0' + toString16(14 + nPairs * 6) + '\0\x01' + toString16(nPairs) + toString16(searchRange) + toString16(logE(nPairs) / logE(2)) + toString16(2 * nPairs - searchRange); michael@0: ; michael@0: var i = 0; michael@0: var record; michael@0: while (record = kerning[i++]) { michael@0: kern += toString16(glyphIndex[record.code1]) + toString16(glyphIndex[record.code2]) + toString16(record.adjustment); michael@0: ; michael@0: } michael@0: tables['kern'] = kern; michael@0: } michael@0: tables['loca'] = loca; michael@0: tables['maxp'] = '\0\x01\0\0' + toString16(glyphCount + 1) + toString16(maxPoints) + toString16(maxContours) + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0'; michael@0: ; michael@0: var uniqueId = 'swf-font-' + nextFontId++; michael@0: var fontName = tag.name || uniqueId; michael@0: var psName = fontName.replace(/ /g, ''); michael@0: var strings = [ michael@0: tag.copyright || 'Original licence', michael@0: fontName, michael@0: 'Unknown', michael@0: uniqueId, michael@0: fontName, michael@0: '1.0', michael@0: psName, michael@0: 'Unknown', michael@0: 'Unknown', michael@0: 'Unknown' michael@0: ]; michael@0: var count = strings.length; michael@0: var name = '\0\0' + toString16(count) + toString16(count * 12 + 6); michael@0: var offset = 0; michael@0: var i = 0; michael@0: var str; michael@0: while (str = strings[i++]) { michael@0: name += '\0\x01\0\0\0\0' + toString16(i - 1) + toString16(str.length) + toString16(offset); michael@0: offset += str.length; michael@0: } michael@0: tables['name'] = name + strings.join(''); michael@0: tables['post'] = '\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'; michael@0: ; michael@0: var names = keys(tables); michael@0: var numTables = names.length; michael@0: var header = '\0\x01\0\0' + toString16(numTables) + '\0\x80' + '\0\x03' + '\0 '; michael@0: ; michael@0: var data = ''; michael@0: var offset = numTables * 16 + header.length; michael@0: var i = 0; michael@0: var name; michael@0: while (name = names[i++]) { michael@0: var table = tables[name]; michael@0: var length = table.length; michael@0: header += name + '\0\0\0\0' + toString32(offset) + toString32(length); michael@0: ; michael@0: while (length & 3) { michael@0: table += '\0'; michael@0: ++length; michael@0: } michael@0: data += table; michael@0: while (offset & 3) michael@0: ++offset; michael@0: offset += length; michael@0: } michael@0: var otf = header + data; michael@0: var unitPerEm = 1024; michael@0: var metrics = { michael@0: ascent: ascent / unitPerEm, michael@0: descent: -descent / unitPerEm, michael@0: leading: leading / unitPerEm michael@0: }; michael@0: return { michael@0: type: 'font', michael@0: id: tag.id, michael@0: name: fontName, michael@0: uniqueName: psName + uniqueId, michael@0: codes: codes, michael@0: metrics: metrics, michael@0: bold: tag.bold === 1, michael@0: italic: tag.italic === 1, michael@0: data: otf michael@0: }; michael@0: } michael@0: function getUint16(buff, pos) { michael@0: return buff[pos] << 8 | buff[pos + 1]; michael@0: } michael@0: function parseJpegChunks(imgDef, bytes) { michael@0: var i = 0; michael@0: var n = bytes.length; michael@0: var chunks = []; michael@0: var code; michael@0: do { michael@0: var begin = i; michael@0: while (i < n && bytes[i] !== 255) michael@0: ++i; michael@0: while (i < n && bytes[i] === 255) michael@0: ++i; michael@0: code = bytes[i++]; michael@0: if (code === 218) { michael@0: i = n; michael@0: } else if (code === 217) { michael@0: i += 2; michael@0: continue; michael@0: } else if (code < 208 || code > 216) { michael@0: var length = getUint16(bytes, i); michael@0: if (code >= 192 && code <= 195) { michael@0: imgDef.height = getUint16(bytes, i + 3); michael@0: imgDef.width = getUint16(bytes, i + 5); michael@0: } michael@0: i += length; michael@0: } michael@0: chunks.push(bytes.subarray(begin, i)); michael@0: } while (i < n); michael@0: return chunks; michael@0: } michael@0: function defineImage(tag, dictionary) { michael@0: var img = { michael@0: type: 'image', michael@0: id: tag.id, michael@0: mimeType: tag.mimeType michael@0: }; michael@0: var imgData = tag.imgData; michael@0: var chunks; michael@0: if (tag.mimeType === 'image/jpeg') { michael@0: chunks = parseJpegChunks(img, imgData); michael@0: var alphaData = tag.alphaData; michael@0: if (alphaData) { michael@0: img.mask = createInflatedStream(alphaData, img.width * img.height).bytes; michael@0: } michael@0: if (tag.incomplete) { michael@0: var tables = dictionary[0]; michael@0: var header = tables.data; michael@0: if (header && header.size) { michael@0: chunks[0] = chunks[0].subarray(2); michael@0: chunks.unshift(header.slice(0, header.size - 2)); michael@0: } michael@0: } michael@0: } else { michael@0: chunks = [ michael@0: imgData michael@0: ]; michael@0: } michael@0: img.data = new Blob(chunks, { michael@0: type: tag.mimeType michael@0: }); michael@0: return img; michael@0: } michael@0: function defineLabel(tag, dictionary) { michael@0: var records = tag.records; michael@0: var m = tag.matrix; michael@0: var cmds = [ michael@0: 'c.save()', michael@0: 'c.transform(' + [ michael@0: m.a, michael@0: m.b, michael@0: m.c, michael@0: m.d, michael@0: m.tx / 20, michael@0: m.ty / 20 michael@0: ].join(',') + ')', michael@0: 'c.scale(0.05, 0.05)' michael@0: ]; michael@0: var dependencies = []; michael@0: var x = 0; michael@0: var y = 0; michael@0: var i = 0; michael@0: var record; michael@0: var codes; michael@0: while (record = records[i++]) { michael@0: if (record.eot) michael@0: break; michael@0: if (record.hasFont) { michael@0: var font = dictionary[record.fontId]; michael@0: codes = font.codes; michael@0: cmds.push('c.font="' + record.fontHeight + 'px \'' + font.uniqueName + '\'"'); michael@0: dependencies.push(font.id); michael@0: } michael@0: if (record.hasColor) { michael@0: cmds.push('ct.setFillStyle(c,"' + rgbaObjToStr(record.color) + '")'); michael@0: cmds.push('ct.setAlpha(c)'); michael@0: } else { michael@0: cmds.push('ct.setAlpha(c,true)'); michael@0: } michael@0: if (record.hasMoveX) michael@0: x = record.moveX; michael@0: if (record.hasMoveY) michael@0: y = record.moveY; michael@0: var entries = record.entries; michael@0: var j = 0; michael@0: var entry; michael@0: while (entry = entries[j++]) { michael@0: var code = codes[entry.glyphIndex]; michael@0: var text = code >= 32 && code != 34 && code != 92 ? fromCharCode(code) : '\\u' + (code + 65536).toString(16).substring(1); michael@0: cmds.push('c.fillText("' + text + '",' + x + ',' + y + ')'); michael@0: x += entry.advance; michael@0: } michael@0: } michael@0: cmds.push('c.restore()'); michael@0: var label = { michael@0: type: 'label', michael@0: id: tag.id, michael@0: bbox: tag.bbox, michael@0: data: cmds.join('\n') michael@0: }; michael@0: if (dependencies.length) michael@0: label.require = dependencies; michael@0: return label; michael@0: } michael@0: var GRAPHICS_FILL_CLIPPED_BITMAP = 65; michael@0: var GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT = 19; michael@0: var GRAPHICS_FILL_LINEAR_GRADIENT = 16; michael@0: var GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP = 67; michael@0: var GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP = 66; michael@0: var GRAPHICS_FILL_RADIAL_GRADIENT = 18; michael@0: var GRAPHICS_FILL_REPEATING_BITMAP = 64; michael@0: var GRAPHICS_FILL_SOLID = 0; michael@0: function applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph) { michael@0: if (!segment) { michael@0: return; michael@0: } michael@0: var commands = segment.commands; michael@0: var data = segment.data; michael@0: var morphData = segment.morphData; michael@0: if (morphData) { michael@0: } michael@0: var path; michael@0: var targetSegment; michael@0: var command; michael@0: var i; michael@0: if (styles.fill0) { michael@0: path = fillPaths[styles.fill0 - 1]; michael@0: if (!(styles.fill1 || styles.line)) { michael@0: targetSegment = path.head(); michael@0: targetSegment.commands = []; michael@0: targetSegment.data = []; michael@0: targetSegment.morphData = isMorph ? [] : null; michael@0: } else { michael@0: targetSegment = path.addSegment([], [], isMorph ? [] : null); michael@0: } michael@0: var targetCommands = targetSegment.commands; michael@0: var targetData = targetSegment.data; michael@0: var targetMorphData = targetSegment.morphData; michael@0: targetCommands.push(SHAPE_MOVE_TO); michael@0: var j = data.length - 2; michael@0: targetData.push(data[j], data[j + 1]); michael@0: if (isMorph) { michael@0: targetMorphData.push(morphData[j], morphData[j + 1]); michael@0: } michael@0: for (i = commands.length; i-- > 1; j -= 2) { michael@0: command = commands[i]; michael@0: targetCommands.push(command); michael@0: targetData.push(data[j - 2], data[j - 1]); michael@0: if (isMorph) { michael@0: targetMorphData.push(morphData[j - 2], morphData[j - 1]); michael@0: } michael@0: if (command === SHAPE_CURVE_TO) { michael@0: targetData.push(data[j - 4], data[j - 3]); michael@0: if (isMorph) { michael@0: targetMorphData.push(morphData[j - 4], morphData[j - 3]); michael@0: } michael@0: j -= 2; michael@0: } michael@0: } michael@0: if (isMorph) { michael@0: } michael@0: } michael@0: if (styles.line && styles.fill1) { michael@0: path = linePaths[styles.line - 1]; michael@0: path.addSegment(commands, data, morphData); michael@0: } michael@0: } michael@0: function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) { michael@0: var isMorph = recordsMorph !== null; michael@0: var styles = { michael@0: fill0: 0, michael@0: fill1: 0, michael@0: line: 0 michael@0: }; michael@0: var segment = null; michael@0: var allPaths; michael@0: var defaultPath; michael@0: var numRecords = records.length - 1; michael@0: var x = 0; michael@0: var y = 0; michael@0: var morphX = 0; michael@0: var morphY = 0; michael@0: var path; michael@0: for (var i = 0, j = 0; i < numRecords; i++) { michael@0: var record = records[i]; michael@0: var morphRecord; michael@0: if (isMorph) { michael@0: morphRecord = recordsMorph[j++]; michael@0: } michael@0: if (record.type === 0) { michael@0: if (segment) { michael@0: applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); michael@0: } michael@0: if (record.hasNewStyles) { michael@0: if (!allPaths) { michael@0: allPaths = []; michael@0: } michael@0: push.apply(allPaths, fillPaths); michael@0: fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies); michael@0: push.apply(allPaths, linePaths); michael@0: linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies); michael@0: if (defaultPath) { michael@0: allPaths.push(defaultPath); michael@0: defaultPath = null; michael@0: } michael@0: styles = { michael@0: fill0: 0, michael@0: fill1: 0, michael@0: line: 0 michael@0: }; michael@0: } michael@0: if (record.hasFillStyle0) { michael@0: styles.fill0 = record.fillStyle0; michael@0: } michael@0: if (record.hasFillStyle1) { michael@0: styles.fill1 = record.fillStyle1; michael@0: } michael@0: if (record.hasLineStyle) { michael@0: styles.line = record.lineStyle; michael@0: } michael@0: if (styles.fill1) { michael@0: path = fillPaths[styles.fill1 - 1]; michael@0: } else if (styles.line) { michael@0: path = linePaths[styles.line - 1]; michael@0: } else if (styles.fill0) { michael@0: path = fillPaths[styles.fill0 - 1]; michael@0: } michael@0: if (record.move) { michael@0: x = record.moveX | 0; michael@0: y = record.moveY | 0; michael@0: } michael@0: if (path) { michael@0: segment = path.addSegment([], [], isMorph ? [] : null); michael@0: segment.commands.push(SHAPE_MOVE_TO); michael@0: segment.data.push(x, y); michael@0: if (isMorph) { michael@0: if (morphRecord.type === 0) { michael@0: morphX = morphRecord.moveX | 0; michael@0: morphY = morphRecord.moveY | 0; michael@0: } else { michael@0: morphX = x; michael@0: morphY = y; michael@0: j--; michael@0: } michael@0: segment.morphData.push(morphX, morphY); michael@0: } michael@0: } michael@0: } else { michael@0: if (!segment) { michael@0: if (!defaultPath) { michael@0: var style = { michael@0: color: { michael@0: red: 0, michael@0: green: 0, michael@0: blue: 0, michael@0: alpha: 255 michael@0: }, michael@0: width: 20 michael@0: }; michael@0: defaultPath = new SegmentedPath(null, processStyle(style, true)); michael@0: } michael@0: segment = defaultPath.addSegment([], [], isMorph ? [] : null); michael@0: segment.commands.push(SHAPE_MOVE_TO); michael@0: segment.data.push(x, y); michael@0: if (isMorph) { michael@0: segment.morphData.push(morphX, morphY); michael@0: } michael@0: } michael@0: if (isMorph) { michael@0: while (morphRecord && morphRecord.type === 0) { michael@0: morphRecord = recordsMorph[j++]; michael@0: } michael@0: if (!morphRecord) { michael@0: morphRecord = record; michael@0: } michael@0: } michael@0: if (record.isStraight && (!isMorph || morphRecord.isStraight)) { michael@0: x += record.deltaX | 0; michael@0: y += record.deltaY | 0; michael@0: segment.commands.push(SHAPE_LINE_TO); michael@0: segment.data.push(x, y); michael@0: if (isMorph) { michael@0: morphX += morphRecord.deltaX | 0; michael@0: morphY += morphRecord.deltaY | 0; michael@0: segment.morphData.push(morphX, morphY); michael@0: } michael@0: } else { michael@0: var cx, cy; michael@0: var deltaX, deltaY; michael@0: if (!record.isStraight) { michael@0: cx = x + record.controlDeltaX | 0; michael@0: cy = y + record.controlDeltaY | 0; michael@0: x = cx + record.anchorDeltaX | 0; michael@0: y = cy + record.anchorDeltaY | 0; michael@0: } else { michael@0: deltaX = record.deltaX | 0; michael@0: deltaY = record.deltaY | 0; michael@0: cx = x + (deltaX >> 1); michael@0: cy = y + (deltaY >> 1); michael@0: x += deltaX; michael@0: y += deltaY; michael@0: } michael@0: segment.commands.push(SHAPE_CURVE_TO); michael@0: segment.data.push(cx, cy, x, y); michael@0: if (isMorph) { michael@0: if (!morphRecord.isStraight) { michael@0: cx = morphX + morphRecord.controlDeltaX | 0; michael@0: cy = morphY + morphRecord.controlDeltaY | 0; michael@0: morphX = cx + morphRecord.anchorDeltaX | 0; michael@0: morphY = cy + morphRecord.anchorDeltaY | 0; michael@0: } else { michael@0: deltaX = morphRecord.deltaX | 0; michael@0: deltaY = morphRecord.deltaY | 0; michael@0: cx = morphX + (deltaX >> 1); michael@0: cy = morphY + (deltaY >> 1); michael@0: morphX += deltaX; michael@0: morphY += deltaY; michael@0: } michael@0: segment.morphData.push(cx, cy, morphX, morphY); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph); michael@0: if (allPaths) { michael@0: push.apply(allPaths, fillPaths); michael@0: } else { michael@0: allPaths = fillPaths; michael@0: } michael@0: push.apply(allPaths, linePaths); michael@0: if (defaultPath) { michael@0: allPaths.push(defaultPath); michael@0: } michael@0: var removeCount = 0; michael@0: for (i = 0; i < allPaths.length; i++) { michael@0: path = allPaths[i]; michael@0: if (!path.head()) { michael@0: removeCount++; michael@0: continue; michael@0: } michael@0: allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables); michael@0: } michael@0: allPaths.length -= removeCount; michael@0: return allPaths; michael@0: } michael@0: function segmentedPathToShapePath(path, isMorph, transferables) { michael@0: var start = path.head(); michael@0: var end = start; michael@0: var finalRoot = null; michael@0: var finalHead = null; michael@0: var skippedMoves = 0; michael@0: var current = start.prev; michael@0: while (start) { michael@0: while (current) { michael@0: if (path.segmentsConnect(current, start)) { michael@0: if (current.next !== start) { michael@0: path.removeSegment(current); michael@0: path.insertSegment(current, start); michael@0: } michael@0: start = current; michael@0: current = start.prev; michael@0: skippedMoves++; michael@0: continue; michael@0: } michael@0: if (path.segmentsConnect(end, current)) { michael@0: path.removeSegment(current); michael@0: end.next = current; michael@0: current = current.prev; michael@0: end.next.prev = end; michael@0: end.next.next = null; michael@0: end = end.next; michael@0: skippedMoves++; michael@0: continue; michael@0: } michael@0: current = current.prev; michael@0: } michael@0: current = start.prev; michael@0: if (!finalRoot) { michael@0: finalRoot = start; michael@0: finalHead = end; michael@0: } else { michael@0: finalHead.next = start; michael@0: start.prev = finalHead; michael@0: finalHead = end; michael@0: finalHead.next = null; michael@0: } michael@0: if (!current) { michael@0: break; michael@0: } michael@0: start = end = current; michael@0: current = start.prev; michael@0: } michael@0: var totalCommandsLength = -skippedMoves; michael@0: var totalDataLength = -skippedMoves << 1; michael@0: current = finalRoot; michael@0: while (current) { michael@0: totalCommandsLength += current.commands.length; michael@0: totalDataLength += current.data.length; michael@0: current = current.next; michael@0: } michael@0: var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables); michael@0: var allCommands = shape.commands; michael@0: var allData = shape.data; michael@0: var allMorphData = shape.morphData; michael@0: var commandsIndex = 0; michael@0: var dataIndex = 0; michael@0: current = finalRoot; michael@0: while (current) { michael@0: var commands = current.commands; michael@0: var data = current.data; michael@0: var morphData = current.morphData; michael@0: var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]); michael@0: for (var i = offset; i < commands.length; i++, commandsIndex++) { michael@0: allCommands[commandsIndex] = commands[i]; michael@0: } michael@0: for (i = offset << 1; i < data.length; i++, dataIndex++) { michael@0: allData[dataIndex] = data[i]; michael@0: if (isMorph) { michael@0: allMorphData[dataIndex] = morphData[i]; michael@0: } michael@0: } michael@0: current = current.next; michael@0: } michael@0: return shape; michael@0: } michael@0: var CAPS_STYLE_TYPES = [ michael@0: 'round', michael@0: 'none', michael@0: 'square' michael@0: ]; michael@0: var JOIN_STYLE_TYPES = [ michael@0: 'round', michael@0: 'bevel', michael@0: 'miter' michael@0: ]; michael@0: function processStyle(style, isLineStyle, dictionary, dependencies) { michael@0: if (isLineStyle) { michael@0: style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0]; michael@0: style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0]; michael@0: style.miterLimit = (style.miterLimitFactor || 1.5) * 2; michael@0: if (!style.color && style.hasFill) { michael@0: var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies); michael@0: style.style = fillStyle.style; michael@0: style.type = fillStyle.type; michael@0: style.transform = fillStyle.transform; michael@0: style.records = fillStyle.records; michael@0: style.focalPoint = fillStyle.focalPoint; michael@0: style.bitmapId = fillStyle.bitmapId; michael@0: style.repeat = fillStyle.repeat; michael@0: style.fillStyle = null; michael@0: return style; michael@0: } michael@0: } michael@0: var color; michael@0: if (style.type === undefined || style.type === GRAPHICS_FILL_SOLID) { michael@0: color = style.color; michael@0: style.style = 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')'; michael@0: style.color = null; michael@0: return style; michael@0: } michael@0: var scale; michael@0: switch (style.type) { michael@0: case GRAPHICS_FILL_LINEAR_GRADIENT: michael@0: case GRAPHICS_FILL_RADIAL_GRADIENT: michael@0: case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT: michael@0: scale = 819.2; michael@0: break; michael@0: case GRAPHICS_FILL_REPEATING_BITMAP: michael@0: case GRAPHICS_FILL_CLIPPED_BITMAP: michael@0: case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP: michael@0: case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP: michael@0: if (dictionary[style.bitmapId]) { michael@0: dependencies.push(dictionary[style.bitmapId].id); michael@0: scale = 0.05; michael@0: } michael@0: break; michael@0: default: michael@0: fail('invalid fill style', 'shape'); michael@0: } michael@0: if (!style.matrix) { michael@0: return style; michael@0: } michael@0: var matrix = style.matrix; michael@0: style.transform = { michael@0: a: matrix.a * scale, michael@0: b: matrix.b * scale, michael@0: c: matrix.c * scale, michael@0: d: matrix.d * scale, michael@0: e: matrix.tx, michael@0: f: matrix.ty michael@0: }; michael@0: style.matrix = null; michael@0: return style; michael@0: } michael@0: function createPathsList(styles, isLineStyle, dictionary, dependencies) { michael@0: var paths = []; michael@0: for (var i = 0; i < styles.length; i++) { michael@0: var style = processStyle(styles[i], isLineStyle, dictionary, dependencies); michael@0: if (!isLineStyle) { michael@0: paths[i] = new SegmentedPath(style, null); michael@0: } else { michael@0: paths[i] = new SegmentedPath(null, style); michael@0: } michael@0: } michael@0: return paths; michael@0: } michael@0: function defineShape(tag, dictionary) { michael@0: var dependencies = []; michael@0: var transferables = []; michael@0: var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies); michael@0: var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies); michael@0: var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables); michael@0: if (tag.bboxMorph) { michael@0: var mbox = tag.bboxMorph; michael@0: extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin); michael@0: extendBoundsByPoint(tag.bbox, mbox.xMax, mbox.yMax); michael@0: mbox = tag.strokeBboxMorph; michael@0: if (mbox) { michael@0: extendBoundsByPoint(tag.strokeBbox, mbox.xMin, mbox.yMin); michael@0: extendBoundsByPoint(tag.strokeBbox, mbox.xMax, mbox.yMax); michael@0: } michael@0: } michael@0: return { michael@0: type: 'shape', michael@0: id: tag.id, michael@0: strokeBbox: tag.strokeBbox, michael@0: strokeBboxMorph: tag.strokeBboxMorph, michael@0: bbox: tag.bbox, michael@0: bboxMorph: tag.bboxMorph, michael@0: isMorph: tag.isMorph, michael@0: paths: paths, michael@0: require: dependencies.length ? dependencies : null, michael@0: transferables: transferables michael@0: }; michael@0: } michael@0: function logShape(paths, bbox) { michael@0: var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) { michael@0: return path.serialize(); michael@0: }).join() + ']}'; michael@0: console.log(output); michael@0: } michael@0: function SegmentedPath(fillStyle, lineStyle) { michael@0: this.fillStyle = fillStyle; michael@0: this.lineStyle = lineStyle; michael@0: this._head = null; michael@0: } michael@0: SegmentedPath.prototype = { michael@0: addSegment: function (commands, data, morphData) { michael@0: var segment = { michael@0: commands: commands, michael@0: data: data, michael@0: morphData: morphData, michael@0: prev: this._head, michael@0: next: null michael@0: }; michael@0: if (this._head) { michael@0: this._head.next = segment; michael@0: } michael@0: this._head = segment; michael@0: return segment; michael@0: }, michael@0: removeSegment: function (segment) { michael@0: if (segment.prev) { michael@0: segment.prev.next = segment.next; michael@0: } michael@0: if (segment.next) { michael@0: segment.next.prev = segment.prev; michael@0: } michael@0: }, michael@0: insertSegment: function (segment, next) { michael@0: var prev = next.prev; michael@0: segment.prev = prev; michael@0: segment.next = next; michael@0: if (prev) { michael@0: prev.next = segment; michael@0: } michael@0: next.prev = segment; michael@0: }, michael@0: head: function () { michael@0: return this._head; michael@0: }, michael@0: segmentsConnect: function (first, second) { michael@0: var firstLength = first.data.length; michael@0: return first.data[firstLength - 2] === second.data[0] && first.data[firstLength - 1] === second.data[1]; michael@0: } michael@0: }; michael@0: var SHAPE_MOVE_TO = 1; michael@0: var SHAPE_LINE_TO = 2; michael@0: var SHAPE_CURVE_TO = 3; michael@0: var SHAPE_WIDE_MOVE_TO = 4; michael@0: var SHAPE_WIDE_LINE_TO = 5; michael@0: var SHAPE_CUBIC_CURVE_TO = 6; michael@0: var SHAPE_CIRCLE = 7; michael@0: var SHAPE_ELLIPSE = 8; michael@0: function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) { michael@0: this.fillStyle = fillStyle; michael@0: this.lineStyle = lineStyle; michael@0: if (commandsCount) { michael@0: this.commands = new Uint8Array(commandsCount); michael@0: this.data = new Int32Array(dataLength); michael@0: this.morphData = isMorph ? new Int32Array(dataLength) : null; michael@0: } else { michael@0: this.commands = []; michael@0: this.data = []; michael@0: } michael@0: this.bounds = null; michael@0: this.strokeBounds = null; michael@0: this.isMorph = !(!isMorph); michael@0: this.fullyInitialized = false; michael@0: if (inWorker) { michael@0: this.buffers = [ michael@0: this.commands.buffer, michael@0: this.data.buffer michael@0: ]; michael@0: transferables.push(this.commands.buffer, this.data.buffer); michael@0: if (isMorph) { michael@0: this.buffers.push(this.morphData.buffer); michael@0: transferables.push(this.morphData.buffer); michael@0: } michael@0: } else { michael@0: this.buffers = null; michael@0: } michael@0: } michael@0: ShapePath.prototype = { michael@0: get isEmpty() { michael@0: return this.commands.length === 0; michael@0: }, michael@0: moveTo: function (x, y) { michael@0: if (this.commands[this.commands.length - 1] === SHAPE_MOVE_TO) { michael@0: this.data[this.data.length - 2] = x; michael@0: this.data[this.data.length - 1] = y; michael@0: return; michael@0: } michael@0: this.commands.push(SHAPE_MOVE_TO); michael@0: this.data.push(x, y); michael@0: }, michael@0: lineTo: function (x, y) { michael@0: this.commands.push(SHAPE_LINE_TO); michael@0: this.data.push(x, y); michael@0: }, michael@0: curveTo: function (controlX, controlY, anchorX, anchorY) { michael@0: this.commands.push(SHAPE_CURVE_TO); michael@0: this.data.push(controlX, controlY, anchorX, anchorY); michael@0: }, michael@0: cubicCurveTo: function (control1X, control1Y, control2X, control2Y, anchorX, anchorY) { michael@0: this.commands.push(SHAPE_CUBIC_CURVE_TO); michael@0: this.data.push(control1X, control1Y, control2X, control2Y, anchorX, anchorY); michael@0: }, michael@0: rect: function (x, y, w, h) { michael@0: var x2 = x + w; michael@0: var y2 = y + h; michael@0: this.commands.push(SHAPE_MOVE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO); michael@0: this.data.push(x, y, x2, y, x2, y2, x, y2, x, y); michael@0: }, michael@0: circle: function (x, y, radius) { michael@0: this.commands.push(SHAPE_CIRCLE); michael@0: this.data.push(x, y, radius); michael@0: }, michael@0: ellipse: function (x, y, radiusX, radiusY) { michael@0: this.commands.push(SHAPE_ELLIPSE); michael@0: this.data.push(x, y, radiusX, radiusY); michael@0: }, michael@0: draw: function (ctx, clip, ratio, colorTransform) { michael@0: if (clip && !this.fillStyle) { michael@0: return; michael@0: } michael@0: ctx.beginPath(); michael@0: var commands = this.commands; michael@0: var data = this.data; michael@0: var morphData = this.morphData; michael@0: var formOpen = false; michael@0: var formOpenX = 0; michael@0: var formOpenY = 0; michael@0: if (!this.isMorph) { michael@0: for (var j = 0, k = 0; j < commands.length; j++) { michael@0: switch (commands[j]) { michael@0: case SHAPE_MOVE_TO: michael@0: formOpen = true; michael@0: formOpenX = data[k++] / 20; michael@0: formOpenY = data[k++] / 20; michael@0: ctx.moveTo(formOpenX, formOpenY); michael@0: break; michael@0: case SHAPE_WIDE_MOVE_TO: michael@0: ctx.moveTo(data[k++] / 20, data[k++] / 20); michael@0: k += 2; michael@0: break; michael@0: case SHAPE_LINE_TO: michael@0: ctx.lineTo(data[k++] / 20, data[k++] / 20); michael@0: break; michael@0: case SHAPE_WIDE_LINE_TO: michael@0: ctx.lineTo(data[k++] / 20, data[k++] / 20); michael@0: k += 2; michael@0: break; michael@0: case SHAPE_CURVE_TO: michael@0: ctx.quadraticCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20); michael@0: break; michael@0: case SHAPE_CUBIC_CURVE_TO: michael@0: ctx.bezierCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20); michael@0: break; michael@0: case SHAPE_CIRCLE: michael@0: if (formOpen) { michael@0: ctx.lineTo(formOpenX, formOpenY); michael@0: formOpen = false; michael@0: } michael@0: ctx.moveTo((data[k] + data[k + 2]) / 20, data[k + 1] / 20); michael@0: ctx.arc(data[k++] / 20, data[k++] / 20, data[k++] / 20, 0, Math.PI * 2, false); michael@0: break; michael@0: case SHAPE_ELLIPSE: michael@0: if (formOpen) { michael@0: ctx.lineTo(formOpenX, formOpenY); michael@0: formOpen = false; michael@0: } michael@0: var x = data[k++]; michael@0: var y = data[k++]; michael@0: var rX = data[k++]; michael@0: var rY = data[k++]; michael@0: var radius; michael@0: if (rX !== rY) { michael@0: ctx.save(); michael@0: var ellipseScale; michael@0: if (rX > rY) { michael@0: ellipseScale = rX / rY; michael@0: radius = rY; michael@0: x /= ellipseScale; michael@0: ctx.scale(ellipseScale, 1); michael@0: } else { michael@0: ellipseScale = rY / rX; michael@0: radius = rX; michael@0: y /= ellipseScale; michael@0: ctx.scale(1, ellipseScale); michael@0: } michael@0: } michael@0: ctx.moveTo((x + radius) / 20, y / 20); michael@0: ctx.arc(x / 20, y / 20, radius / 20, 0, Math.PI * 2, false); michael@0: if (rX !== rY) { michael@0: ctx.restore(); michael@0: } michael@0: break; michael@0: default: michael@0: if (commands[j] === 0 && j === commands.length - 1) { michael@0: break; michael@0: } michael@0: console.warn('Unknown drawing command encountered: ' + commands[j]); michael@0: } michael@0: } michael@0: } else { michael@0: for (var j = 0, k = 0; j < commands.length; j++) { michael@0: switch (commands[j]) { michael@0: case SHAPE_MOVE_TO: michael@0: ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio)); michael@0: break; michael@0: case SHAPE_LINE_TO: michael@0: ctx.lineTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio)); michael@0: break; michael@0: case SHAPE_CURVE_TO: michael@0: ctx.quadraticCurveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio)); michael@0: break; michael@0: default: michael@0: console.warn('Drawing command not supported for morph shapes: ' + commands[j]); michael@0: } michael@0: } michael@0: } michael@0: if (!clip) { michael@0: var fillStyle = this.fillStyle; michael@0: if (fillStyle) { michael@0: colorTransform.setFillStyle(ctx, fillStyle.style); michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = fillStyle.smooth; michael@0: var m = fillStyle.transform; michael@0: ctx.save(); michael@0: colorTransform.setAlpha(ctx); michael@0: if (m) { michael@0: ctx.transform(m.a, m.b, m.c, m.d, m.e / 20, m.f / 20); michael@0: } michael@0: ctx.fill(); michael@0: ctx.restore(); michael@0: } michael@0: var lineStyle = this.lineStyle; michael@0: if (lineStyle) { michael@0: colorTransform.setStrokeStyle(ctx, lineStyle.style); michael@0: ctx.save(); michael@0: colorTransform.setAlpha(ctx); michael@0: ctx.lineWidth = Math.max(lineStyle.width / 20, 1); michael@0: ctx.lineCap = lineStyle.lineCap; michael@0: ctx.lineJoin = lineStyle.lineJoin; michael@0: ctx.miterLimit = lineStyle.miterLimit; michael@0: ctx.stroke(); michael@0: ctx.restore(); michael@0: } michael@0: } else { michael@0: ctx.fill(); michael@0: } michael@0: ctx.closePath(); michael@0: }, michael@0: isPointInPath: function (x, y) { michael@0: if (!(this.fillStyle || this.lineStyle)) { michael@0: return false; michael@0: } michael@0: var bounds = this.strokeBounds || this.bounds || this._calculateBounds(); michael@0: if (x < bounds.xMin || x > bounds.xMax || y < bounds.yMin || y > bounds.yMax) { michael@0: return false; michael@0: } michael@0: if (this.fillStyle && this.isPointInFill(x, y)) { michael@0: return true; michael@0: } michael@0: return this.lineStyle && this.lineStyle.width !== undefined && this.isPointInStroke(x, y); michael@0: }, michael@0: isPointInFill: function (x, y) { michael@0: var commands = this.commands; michael@0: var data = this.data; michael@0: var length = commands.length; michael@0: var inside = false; michael@0: var fromX = 0; michael@0: var fromY = 0; michael@0: var toX = 0; michael@0: var toY = 0; michael@0: var localX; michael@0: var localY; michael@0: var cpX; michael@0: var cpY; michael@0: var rX; michael@0: var rY; michael@0: var formOpen = false; michael@0: var formOpenX = 0; michael@0: var formOpenY = 0; michael@0: for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) { michael@0: switch (commands[commandIndex]) { michael@0: case SHAPE_WIDE_MOVE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_MOVE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) { michael@0: inside = !inside; michael@0: } michael@0: formOpen = true; michael@0: formOpenX = toX; michael@0: formOpenY = toY; michael@0: break; michael@0: case SHAPE_WIDE_LINE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_LINE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: if (intersectsLine(x, y, fromX, fromY, toX, toY)) { michael@0: inside = !inside; michael@0: } michael@0: break; michael@0: case SHAPE_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: if (cpY > y === fromY > y && toY > y === fromY > y) { michael@0: break; michael@0: } michael@0: if (fromX >= x && cpX >= x && toX >= x) { michael@0: inside = !inside; michael@0: break; michael@0: } michael@0: var a = fromY - 2 * cpY + toY; michael@0: var c = fromY - y; michael@0: var b = 2 * (cpY - fromY); michael@0: var d = b * b - 4 * a * c; michael@0: if (d < 0) { michael@0: break; michael@0: } michael@0: d = Math.sqrt(d); michael@0: a = 1 / (a + a); michael@0: var t1 = (d - b) * a; michael@0: var t2 = (-b - d) * a; michael@0: if (t1 >= 0 && t1 <= 1 && quadraticBezier(fromX, cpX, toX, t1) > x) { michael@0: inside = !inside; michael@0: } michael@0: if (t2 >= 0 && t2 <= 1 && quadraticBezier(fromX, cpX, toX, t2) > x) { michael@0: inside = !inside; michael@0: } michael@0: break; michael@0: case SHAPE_CUBIC_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: var cp2X = data[dataIndex++]; michael@0: var cp2Y = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: if (cpY > y === fromY > y && cp2Y > y === fromY > y && toY > y === fromY > y) { michael@0: break; michael@0: } michael@0: if (fromX >= x && cpX >= x && cp2X >= x && toX >= x) { michael@0: inside = !inside; michael@0: break; michael@0: } michael@0: var roots = cubicXAtY(fromX, fromY, cpX, cpY, cp2X, cp2Y, toX, toY, y); michael@0: for (var i = roots.length; i--;) { michael@0: if (roots[i] >= x) { michael@0: inside = !inside; michael@0: } michael@0: } michael@0: break; michael@0: case SHAPE_CIRCLE: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: var r = data[dataIndex++]; michael@0: localX = x - toX; michael@0: localY = y - toY; michael@0: if (localX * localX + localY * localY < r * r) { michael@0: inside = !inside; michael@0: } michael@0: toX += r; michael@0: break; michael@0: case SHAPE_ELLIPSE: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: rX = data[dataIndex++]; michael@0: rY = data[dataIndex++]; michael@0: localX = x - cpX; michael@0: localY = y - cpY; michael@0: if (localX * localX / (rX * rX) + localY * localY / (rY * rY) <= 1) { michael@0: inside = !inside; michael@0: } michael@0: toX = cpX + rX; michael@0: toY = cpY; michael@0: break; michael@0: default: michael@0: if (!inWorker) { michael@0: console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]); michael@0: } michael@0: } michael@0: fromX = toX; michael@0: fromY = toY; michael@0: } michael@0: if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) { michael@0: inside = !inside; michael@0: } michael@0: return inside; michael@0: }, michael@0: isPointInStroke: function (x, y) { michael@0: var commands = this.commands; michael@0: var data = this.data; michael@0: var length = commands.length; michael@0: var width = this.lineStyle.width; michael@0: var halfWidth = width / 2; michael@0: var halfWidthSq = halfWidth * halfWidth; michael@0: var minX = x - halfWidth; michael@0: var maxX = x + halfWidth; michael@0: var minY = y - halfWidth; michael@0: var maxY = y + halfWidth; michael@0: var fromX = 0; michael@0: var fromY = 0; michael@0: var toX = 0; michael@0: var toY = 0; michael@0: var localX; michael@0: var localY; michael@0: var cpX; michael@0: var cpY; michael@0: var rX; michael@0: var rY; michael@0: var curveX; michael@0: var curveY; michael@0: var t; michael@0: for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) { michael@0: switch (commands[commandIndex]) { michael@0: case SHAPE_WIDE_MOVE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_MOVE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: break; michael@0: case SHAPE_WIDE_LINE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_LINE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: if (fromX === toX && fromY === toY) { michael@0: break; michael@0: } michael@0: if (maxX < fromX && maxX < toX || minX > fromX && minX > toX || maxY < fromY && maxY < toY || minY > fromY && minY > toY) { michael@0: break; michael@0: } michael@0: if (toX === fromX || toY === fromY) { michael@0: return true; michael@0: } michael@0: t = ((x - fromX) * (toX - fromX) + (y - fromY) * (toY - fromY)) / distanceSq(fromX, fromY, toX, toY); michael@0: if (t < 0) { michael@0: if (distanceSq(x, y, fromX, fromY) <= halfWidthSq) { michael@0: return true; michael@0: } michael@0: break; michael@0: } michael@0: if (t > 1) { michael@0: if (distanceSq(x, y, toX, toY) <= halfWidthSq) { michael@0: return true; michael@0: } michael@0: break; michael@0: } michael@0: if (distanceSq(x, y, fromX + t * (toX - fromX), fromY + t * (toY - fromY)) <= halfWidthSq) { michael@0: return true; michael@0: } michael@0: break; michael@0: case SHAPE_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: var extremeX = quadraticBezierExtreme(fromX, cpX, toX); michael@0: if (maxX < fromX && maxX < extremeX && maxX < toX || minX > fromX && minX > extremeX && minX > toX) { michael@0: break; michael@0: } michael@0: var extremeY = quadraticBezierExtreme(fromY, cpY, toY); michael@0: if (maxY < fromY && maxY < extremeY && maxY < toY || minY > fromY && minY > extremeY && minY > toY) { michael@0: break; michael@0: } michael@0: for (t = 0; t < 1; t += 0.02) { michael@0: curveX = quadraticBezier(fromX, cpX, toX, t); michael@0: if (curveX < minX || curveX > maxX) { michael@0: continue; michael@0: } michael@0: curveY = quadraticBezier(fromY, cpY, toY, t); michael@0: if (curveY < minY || curveY > maxY) { michael@0: continue; michael@0: } michael@0: if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) { michael@0: return true; michael@0: } michael@0: } michael@0: break; michael@0: case SHAPE_CUBIC_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: var cp2X = data[dataIndex++]; michael@0: var cp2Y = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: var extremesX = cubicBezierExtremes(fromX, cpX, cp2X, toX); michael@0: while (extremesX.length < 2) { michael@0: extremesX.push(toX); michael@0: } michael@0: if (maxX < fromX && maxX < toX && maxX < extremesX[0] && maxX < extremesX[1] || minX > fromX && minX > toX && minX > extremesX[0] && minX > extremesX[1]) { michael@0: break; michael@0: } michael@0: var extremesY = cubicBezierExtremes(fromY, cpY, cp2Y, toY); michael@0: while (extremesY.length < 2) { michael@0: extremesY.push(toY); michael@0: } michael@0: if (maxY < fromY && maxY < toY && maxY < extremesY[0] && maxY < extremesY[1] || minY > fromY && minY > toY && minY > extremesY[0] && minY > extremesY[1]) { michael@0: break; michael@0: } michael@0: for (t = 0; t < 1; t += 0.02) { michael@0: curveX = cubicBezier(fromX, cpX, cp2X, toX, t); michael@0: if (curveX < minX || curveX > maxX) { michael@0: continue; michael@0: } michael@0: curveY = cubicBezier(fromY, cpY, cp2Y, toY, t); michael@0: if (curveY < minY || curveY > maxY) { michael@0: continue; michael@0: } michael@0: if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) { michael@0: return true; michael@0: } michael@0: } michael@0: break; michael@0: case SHAPE_CIRCLE: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: var r = data[dataIndex++]; michael@0: toX = cpX + r; michael@0: toY = cpY; michael@0: if (maxX < cpX - r || minX > cpX + r || maxY < cpY - r || minY > cpY + r) { michael@0: break; michael@0: } michael@0: localX = x - cpX; michael@0: localY = y - cpY; michael@0: var rMin = r - halfWidth; michael@0: var rMax = r + halfWidth; michael@0: var distSq = localX * localX + localY * localY; michael@0: if (distSq >= rMin * rMin && distSq <= rMax * rMax) { michael@0: return true; michael@0: } michael@0: break; michael@0: case SHAPE_ELLIPSE: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: rX = data[dataIndex++]; michael@0: rY = data[dataIndex++]; michael@0: toX = cpX + rX; michael@0: toY = cpY; michael@0: localX = Math.abs(x - cpX); michael@0: localY = Math.abs(y - cpY); michael@0: localX -= halfWidth; michael@0: localY -= halfWidth; michael@0: if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) { michael@0: break; michael@0: } michael@0: localX += width; michael@0: localY += width; michael@0: if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) { michael@0: return true; michael@0: } michael@0: break; michael@0: default: michael@0: if (!inWorker) { michael@0: console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]); michael@0: } michael@0: } michael@0: fromX = toX; michael@0: fromY = toY; michael@0: } michael@0: return false; michael@0: }, michael@0: getBounds: function (includeStroke) { michael@0: var bounds = includeStroke ? this.strokeBounds : this.bounds; michael@0: if (!bounds) { michael@0: this._calculateBounds(); michael@0: bounds = includeStroke ? this.strokeBounds : this.bounds; michael@0: } michael@0: return bounds; michael@0: }, michael@0: _calculateBounds: function () { michael@0: var commands = this.commands; michael@0: var data = this.data; michael@0: var length = commands.length; michael@0: var bounds; michael@0: if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_CUBIC_CURVE_TO) { michael@0: bounds = { michael@0: xMin: data[0], michael@0: yMin: data[1] michael@0: }; michael@0: } else { michael@0: bounds = { michael@0: xMin: 0, michael@0: yMin: 0 michael@0: }; michael@0: } michael@0: bounds.xMax = bounds.xMin; michael@0: bounds.yMax = bounds.yMin; michael@0: var fromX = bounds.xMin; michael@0: var fromY = bounds.yMin; michael@0: for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) { michael@0: var toX; michael@0: var toY; michael@0: var cpX; michael@0: var cpY; michael@0: switch (commands[commandIndex]) { michael@0: case SHAPE_WIDE_MOVE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_MOVE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX, toY); michael@0: break; michael@0: case SHAPE_WIDE_LINE_TO: michael@0: dataIndex += 2; michael@0: case SHAPE_LINE_TO: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX, toY); michael@0: break; michael@0: case SHAPE_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX, toY); michael@0: if (cpX < fromX || cpX > toX) { michael@0: extendBoundsByX(bounds, quadraticBezierExtreme(fromX, cpX, toX)); michael@0: } michael@0: if (cpY < fromY || cpY > toY) { michael@0: extendBoundsByY(bounds, quadraticBezierExtreme(fromY, cpY, toY)); michael@0: } michael@0: break; michael@0: case SHAPE_CUBIC_CURVE_TO: michael@0: cpX = data[dataIndex++]; michael@0: cpY = data[dataIndex++]; michael@0: var cp2X = data[dataIndex++]; michael@0: var cp2Y = data[dataIndex++]; michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX, toY); michael@0: var extremes; michael@0: var i; michael@0: if (cpX < fromX || cp2X < fromX || cpX > toX || cp2X > toX) { michael@0: extremes = cubicBezierExtremes(fromX, cpX, cp2X, toX); michael@0: for (i = extremes.length; i--;) { michael@0: extendBoundsByX(bounds, extremes[i]); michael@0: } michael@0: } michael@0: if (cpY < fromY || cp2Y < fromY || cpY > toY || cp2Y > toY) { michael@0: extremes = cubicBezierExtremes(fromY, cpY, cp2Y, toY); michael@0: for (i = extremes.length; i--;) { michael@0: extendBoundsByY(bounds, extremes[i]); michael@0: } michael@0: } michael@0: break; michael@0: case SHAPE_CIRCLE: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: var radius = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX - radius, toY - radius); michael@0: extendBoundsByPoint(bounds, toX + radius, toY + radius); michael@0: toX += radius; michael@0: break; michael@0: case SHAPE_ELLIPSE: michael@0: toX = data[dataIndex++]; michael@0: toY = data[dataIndex++]; michael@0: var radiusX = data[dataIndex++]; michael@0: var radiusY = data[dataIndex++]; michael@0: extendBoundsByPoint(bounds, toX - radiusX, toY - radiusY); michael@0: extendBoundsByPoint(bounds, toX + radiusX, toY + radiusY); michael@0: toX += radiusX; michael@0: break; michael@0: default: michael@0: if (!inWorker) { michael@0: console.warn('Drawing command not handled in bounds calculation: ' + commands[commandIndex]); michael@0: } michael@0: } michael@0: fromX = toX; michael@0: fromY = toY; michael@0: } michael@0: this.bounds = bounds; michael@0: if (this.lineStyle) { michael@0: var halfLineWidth = this.lineStyle.width / 2; michael@0: this.strokeBounds = { michael@0: xMin: bounds.xMin - halfLineWidth, michael@0: yMin: bounds.yMin - halfLineWidth, michael@0: xMax: bounds.xMax + halfLineWidth, michael@0: yMax: bounds.yMax + halfLineWidth michael@0: }; michael@0: return this.strokeBounds; michael@0: } else { michael@0: this.strokeBounds = bounds; michael@0: } michael@0: return bounds; michael@0: }, michael@0: serialize: function () { michael@0: var output = '{'; michael@0: if (this.fillStyle) { michael@0: output += '"fill":' + JSON.stringify(this.fillStyle) + ','; michael@0: } michael@0: if (this.lineStyle) { michael@0: output += '"stroke":' + JSON.stringify(this.lineStyle) + ','; michael@0: } michael@0: output += '"commands":[' + Array.apply([], this.commands).join() + '],'; michael@0: output += '"data":[' + Array.apply([], this.data).join() + ']'; michael@0: return output + '}'; michael@0: } michael@0: }; michael@0: ShapePath.fromPlainObject = function (obj) { michael@0: var path = new ShapePath(obj.fill || null, obj.stroke || null); michael@0: path.commands = new Uint8Array(obj.commands); michael@0: path.data = new Int32Array(obj.data); michael@0: if (!inWorker) { michael@0: finishShapePath(path); michael@0: } michael@0: return path; michael@0: }; michael@0: function distanceSq(x1, y1, x2, y2) { michael@0: var dX = x2 - x1; michael@0: var dY = y2 - y1; michael@0: return dX * dX + dY * dY; michael@0: } michael@0: function intersectsLine(x, y, x1, y1, x2, y2) { michael@0: return y2 > y !== y1 > y && x < (x1 - x2) * (y - y2) / (y1 - y2) + x2; michael@0: } michael@0: function quadraticBezier(from, cp, to, t) { michael@0: var inverseT = 1 - t; michael@0: return from * inverseT * inverseT + 2 * cp * inverseT * t + to * t * t; michael@0: } michael@0: function quadraticBezierExtreme(from, cp, to) { michael@0: var t = (from - cp) / (from - 2 * cp + to); michael@0: if (t < 0) { michael@0: return from; michael@0: } michael@0: if (t > 1) { michael@0: return to; michael@0: } michael@0: return quadraticBezier(from, cp, to, t); michael@0: } michael@0: function cubicBezier(from, cp, cp2, to, t) { michael@0: var tSq = t * t; michael@0: var inverseT = 1 - t; michael@0: var inverseTSq = inverseT * inverseT; michael@0: return from * inverseT * inverseTSq + 3 * cp * t * inverseTSq + 3 * cp2 * inverseT * tSq + to * t * tSq; michael@0: } michael@0: function cubicBezierExtremes(from, cp, cp2, to) { michael@0: var d1 = cp - from; michael@0: var d2 = cp2 - cp; michael@0: d2 *= 2; michael@0: var d3 = to - cp2; michael@0: if (d1 + d3 === d2) { michael@0: d3 *= 1.0001; michael@0: } michael@0: var fHead = 2 * d1 - d2; michael@0: var part1 = d2 - 2 * d1; michael@0: var fCenter = Math.sqrt(part1 * part1 - 4 * d1 * (d1 - d2 + d3)); michael@0: var fTail = 2 * (d1 - d2 + d3); michael@0: var t1 = (fHead + fCenter) / fTail; michael@0: var t2 = (fHead - fCenter) / fTail; michael@0: var result = []; michael@0: if (t1 >= 0 && t1 <= 1) { michael@0: result.push(cubicBezier(from, cp, cp2, to, t1)); michael@0: } michael@0: if (t2 >= 0 && t2 <= 1) { michael@0: result.push(cubicBezier(from, cp, cp2, to, t2)); michael@0: } michael@0: return result; michael@0: } michael@0: function cubicXAtY(x0, y0, cx, cy, cx1, cy1, x1, y1, y) { michael@0: var dX = 3 * (cx - x0); michael@0: var dY = 3 * (cy - y0); michael@0: var bX = 3 * (cx1 - cx) - dX; michael@0: var bY = 3 * (cy1 - cy) - dY; michael@0: var c3X = x1 - x0 - dX - bX; michael@0: var c3Y = y1 - y0 - dY - bY; michael@0: function f(t) { michael@0: return t * (dY + t * (bY + t * c3Y)) + y0 - y; michael@0: } michael@0: function pointAt(t) { michael@0: if (t < 0) { michael@0: t = 0; michael@0: } else if (t > 1) { michael@0: t = 1; michael@0: } michael@0: return x0 + t * (dX + t * (bX + t * c3X)); michael@0: } michael@0: function bisectCubicBezierRange(f, l, r, limit) { michael@0: if (Math.abs(r - l) <= limit) { michael@0: return; michael@0: } michael@0: var middle = 0.5 * (l + r); michael@0: if (f(l) * f(r) <= 0) { michael@0: left = l; michael@0: right = r; michael@0: return; michael@0: } michael@0: bisectCubicBezierRange(f, l, middle, limit); michael@0: bisectCubicBezierRange(f, middle, r, limit); michael@0: } michael@0: var left = 0; michael@0: var right = 1; michael@0: bisectCubicBezierRange(f, 0, 1, 0.05); michael@0: var t0 = findRoot(left, right, f, 50, 0.000001); michael@0: var evalResult = Math.abs(f(t0)); michael@0: if (evalResult > 0.00001) { michael@0: return []; michael@0: } michael@0: var result = []; michael@0: if (t0 <= 1) { michael@0: result.push(pointAt(t0)); michael@0: } michael@0: var a = c3Y; michael@0: var b = t0 * a + bY; michael@0: var c = t0 * b + dY; michael@0: var d = b * b - 4 * a * c; michael@0: if (d < 0) { michael@0: return result; michael@0: } michael@0: d = Math.sqrt(d); michael@0: a = 1 / (a + a); michael@0: var t1 = (d - b) * a; michael@0: var t2 = (-b - d) * a; michael@0: if (t1 >= 0 && t1 <= 1) { michael@0: result.push(pointAt(t1)); michael@0: } michael@0: if (t2 >= 0 && t2 <= 1) { michael@0: result.push(pointAt(t2)); michael@0: } michael@0: return result; michael@0: } michael@0: function findRoot(x0, x2, f, maxIterations, epsilon) { michael@0: var x1; michael@0: var y0; michael@0: var y1; michael@0: var y2; michael@0: var b; michael@0: var c; michael@0: var y10; michael@0: var y20; michael@0: var y21; michael@0: var xm; michael@0: var ym; michael@0: var temp; michael@0: var xmlast = x0; michael@0: y0 = f(x0); michael@0: if (y0 === 0) { michael@0: return x0; michael@0: } michael@0: y2 = f(x2); michael@0: if (y2 === 0) { michael@0: return x2; michael@0: } michael@0: if (y2 * y0 > 0) { michael@0: return x0; michael@0: } michael@0: var __iter = 0; michael@0: for (var i = 0; i < maxIterations; ++i) { michael@0: __iter++; michael@0: x1 = 0.5 * (x2 + x0); michael@0: y1 = f(x1); michael@0: if (y1 === 0) { michael@0: return x1; michael@0: } michael@0: if (Math.abs(x1 - x0) < epsilon) { michael@0: return x1; michael@0: } michael@0: if (y1 * y0 > 0) { michael@0: temp = x0; michael@0: x0 = x2; michael@0: x2 = temp; michael@0: temp = y0; michael@0: y0 = y2; michael@0: y2 = temp; michael@0: } michael@0: y10 = y1 - y0; michael@0: y21 = y2 - y1; michael@0: y20 = y2 - y0; michael@0: if (y2 * y20 < 2 * y1 * y10) { michael@0: x2 = x1; michael@0: y2 = y1; michael@0: } else { michael@0: b = (x1 - x0) / y10; michael@0: c = (y10 - y21) / (y21 * y20); michael@0: xm = x0 - b * y0 * (1 - c * y1); michael@0: ym = f(xm); michael@0: if (ym === 0) { michael@0: return xm; michael@0: } michael@0: if (Math.abs(xm - xmlast) < epsilon) { michael@0: return xm; michael@0: } michael@0: xmlast = xm; michael@0: if (ym * y0 < 0) { michael@0: x2 = xm; michael@0: y2 = ym; michael@0: } else { michael@0: x0 = xm; michael@0: y0 = ym; michael@0: x2 = x1; michael@0: y2 = y1; michael@0: } michael@0: } michael@0: } michael@0: return x1; michael@0: } michael@0: function extendBoundsByPoint(bounds, x, y) { michael@0: if (x < bounds.xMin) { michael@0: bounds.xMin = x; michael@0: } else if (x > bounds.xMax) { michael@0: bounds.xMax = x; michael@0: } michael@0: if (y < bounds.yMin) { michael@0: bounds.yMin = y; michael@0: } else if (y > bounds.yMax) { michael@0: bounds.yMax = y; michael@0: } michael@0: } michael@0: function extendBoundsByX(bounds, x) { michael@0: if (x < bounds.xMin) { michael@0: bounds.xMin = x; michael@0: } else if (x > bounds.xMax) { michael@0: bounds.xMax = x; michael@0: } michael@0: } michael@0: function extendBoundsByY(bounds, y) { michael@0: if (y < bounds.yMin) { michael@0: bounds.yMin = y; michael@0: } else if (y > bounds.yMax) { michael@0: bounds.yMax = y; michael@0: } michael@0: } michael@0: function morph(start, end, ratio) { michael@0: return start + (end - start) * ratio; michael@0: } michael@0: function finishShapePath(path, dictionaryResolved) { michael@0: if (path.fullyInitialized) { michael@0: return path; michael@0: } michael@0: if (!(path instanceof ShapePath)) { michael@0: var untypedPath = path; michael@0: path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph); michael@0: path.commands = new Uint8Array(untypedPath.buffers[0]); michael@0: path.data = new Int32Array(untypedPath.buffers[1]); michael@0: if (untypedPath.isMorph) { michael@0: path.morphData = new Int32Array(untypedPath.buffers[2]); michael@0: } michael@0: path.buffers = null; michael@0: } michael@0: path.fillStyle && initStyle(path.fillStyle, dictionaryResolved); michael@0: path.lineStyle && initStyle(path.lineStyle, dictionaryResolved); michael@0: path.fullyInitialized = true; michael@0: return path; michael@0: } michael@0: var inWorker = typeof window === 'undefined'; michael@0: var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null; michael@0: function buildLinearGradientFactory(colorStops) { michael@0: var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0); michael@0: for (var i = 0; i < colorStops.length; i++) { michael@0: defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color); michael@0: } michael@0: var fn = function createLinearGradient(ctx, colorTransform) { michael@0: var gradient = ctx.createLinearGradient(-1, 0, 1, 0); michael@0: for (var i = 0; i < colorStops.length; i++) { michael@0: colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color); michael@0: } michael@0: return gradient; michael@0: }; michael@0: fn.defaultFillStyle = defaultGradient; michael@0: return fn; michael@0: } michael@0: function buildRadialGradientFactory(focalPoint, colorStops) { michael@0: var defaultGradient = factoryCtx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1); michael@0: for (var i = 0; i < colorStops.length; i++) { michael@0: defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color); michael@0: } michael@0: var fn = function createRadialGradient(ctx, colorTransform) { michael@0: var gradient = ctx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1); michael@0: for (var i = 0; i < colorStops.length; i++) { michael@0: colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color); michael@0: } michael@0: return gradient; michael@0: }; michael@0: fn.defaultFillStyle = defaultGradient; michael@0: return fn; michael@0: } michael@0: function buildBitmapPatternFactory(img, repeat) { michael@0: var defaultPattern = factoryCtx.createPattern(img, repeat); michael@0: var cachedTransform, cachedTransformKey; michael@0: var fn = function createBitmapPattern(ctx, colorTransform) { michael@0: if (!colorTransform.mode) { michael@0: return defaultPattern; michael@0: } michael@0: var key = colorTransform.getTransformFingerprint(); michael@0: if (key === cachedTransformKey) { michael@0: return cachedTransform; michael@0: } michael@0: var canvas = document.createElement('canvas'); michael@0: canvas.width = img.width; michael@0: canvas.height = img.height; michael@0: var ctx = canvas.getContext('2d'); michael@0: colorTransform.setAlpha(ctx, true); michael@0: ctx.drawImage(img, 0, 0); michael@0: cachedTransform = ctx.createPattern(canvas, repeat); michael@0: cachedTransformKey = key; michael@0: return cachedTransform; michael@0: }; michael@0: fn.defaultFillStyle = defaultPattern; michael@0: return fn; michael@0: } michael@0: function initStyle(style, dictionaryResolved) { michael@0: if (style.type === undefined) { michael@0: return; michael@0: } michael@0: switch (style.type) { michael@0: case GRAPHICS_FILL_SOLID: michael@0: break; michael@0: case GRAPHICS_FILL_LINEAR_GRADIENT: michael@0: case GRAPHICS_FILL_RADIAL_GRADIENT: michael@0: case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT: michael@0: var records = style.records, colorStops = []; michael@0: for (var j = 0, n = records.length; j < n; j++) { michael@0: var record = records[j]; michael@0: var colorStr = rgbaObjToStr(record.color); michael@0: colorStops.push({ michael@0: ratio: record.ratio / 255, michael@0: color: colorStr michael@0: }); michael@0: } michael@0: var gradientConstructor; michael@0: var isLinear = style.type === GRAPHICS_FILL_LINEAR_GRADIENT; michael@0: if (isLinear) { michael@0: gradientConstructor = buildLinearGradientFactory(colorStops); michael@0: } else { michael@0: gradientConstructor = buildRadialGradientFactory((style.focalPoint | 0) / 20, colorStops); michael@0: } michael@0: style.style = gradientConstructor; michael@0: break; michael@0: case GRAPHICS_FILL_REPEATING_BITMAP: michael@0: case GRAPHICS_FILL_CLIPPED_BITMAP: michael@0: case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP: michael@0: case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP: michael@0: var bitmap = dictionaryResolved[style.bitmapId]; michael@0: var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP; michael@0: style.style = buildBitmapPatternFactory(bitmap.props.img, repeat ? 'repeat' : 'no-repeat'); michael@0: break; michael@0: default: michael@0: fail('invalid fill style', 'shape'); michael@0: } michael@0: } michael@0: var SOUND_SIZE_8_BIT = 0; michael@0: var SOUND_SIZE_16_BIT = 1; michael@0: var SOUND_TYPE_MONO = 0; michael@0: var SOUND_TYPE_STEREO = 1; michael@0: var SOUND_FORMAT_PCM_BE = 0; michael@0: var SOUND_FORMAT_ADPCM = 1; michael@0: var SOUND_FORMAT_MP3 = 2; michael@0: var SOUND_FORMAT_PCM_LE = 3; michael@0: var SOUND_FORMAT_NELLYMOSER_16 = 4; michael@0: var SOUND_FORMAT_NELLYMOSER_8 = 5; michael@0: var SOUND_FORMAT_NELLYMOSER = 6; michael@0: var SOUND_FORMAT_SPEEX = 11; michael@0: var SOUND_RATES = [ michael@0: 5512, michael@0: 11250, michael@0: 22500, michael@0: 44100 michael@0: ]; michael@0: var WaveHeader = new Uint8Array([ michael@0: 82, michael@0: 73, michael@0: 70, michael@0: 70, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 87, michael@0: 65, michael@0: 86, michael@0: 69, michael@0: 102, michael@0: 109, michael@0: 116, michael@0: 32, michael@0: 16, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 1, michael@0: 0, michael@0: 2, michael@0: 0, michael@0: 68, michael@0: 172, michael@0: 0, michael@0: 0, michael@0: 16, michael@0: 177, michael@0: 2, michael@0: 0, michael@0: 4, michael@0: 0, michael@0: 16, michael@0: 0, michael@0: 100, michael@0: 97, michael@0: 116, michael@0: 97, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 0 michael@0: ]); michael@0: function packageWave(data, sampleRate, channels, size, swapBytes) { michael@0: var sizeInBytes = size >> 3; michael@0: var sizePerSecond = channels * sampleRate * sizeInBytes; michael@0: var sizePerSample = channels * sizeInBytes; michael@0: var dataLength = data.length + (data.length & 1); michael@0: var buffer = new ArrayBuffer(WaveHeader.length + dataLength); michael@0: var bytes = new Uint8Array(buffer); michael@0: bytes.set(WaveHeader); michael@0: if (swapBytes) { michael@0: for (var i = 0, j = WaveHeader.length; i < data.length; i += 2, j += 2) { michael@0: bytes[j] = data[i + 1]; michael@0: bytes[j + 1] = data[i]; michael@0: } michael@0: } else { michael@0: bytes.set(data, WaveHeader.length); michael@0: } michael@0: var view = new DataView(buffer); michael@0: view.setUint32(4, dataLength + 36, true); michael@0: view.setUint16(22, channels, true); michael@0: view.setUint32(24, sampleRate, true); michael@0: view.setUint32(28, sizePerSecond, true); michael@0: view.setUint16(32, sizePerSample, true); michael@0: view.setUint16(34, size, true); michael@0: view.setUint32(40, dataLength, true); michael@0: return { michael@0: data: bytes, michael@0: mimeType: 'audio/wav' michael@0: }; michael@0: } michael@0: function defineSound(tag, dictionary) { michael@0: var channels = tag.soundType == SOUND_TYPE_STEREO ? 2 : 1; michael@0: var samplesCount = tag.samplesCount; michael@0: var sampleRate = SOUND_RATES[tag.soundRate]; michael@0: var data = tag.soundData; michael@0: var pcm, packaged; michael@0: switch (tag.soundFormat) { michael@0: case SOUND_FORMAT_PCM_BE: michael@0: pcm = new Float32Array(samplesCount * channels); michael@0: if (tag.soundSize == SOUND_SIZE_16_BIT) { michael@0: for (var i = 0, j = 0; i < pcm.length; i++, j += 2) michael@0: pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648; michael@0: packaged = packageWave(data, sampleRate, channels, 16, true); michael@0: } else { michael@0: for (var i = 0; i < pcm.length; i++) michael@0: pcm[i] = (data[i] - 128) / 128; michael@0: packaged = packageWave(data, sampleRate, channels, 8, false); michael@0: } michael@0: break; michael@0: case SOUND_FORMAT_PCM_LE: michael@0: pcm = new Float32Array(samplesCount * channels); michael@0: if (tag.soundSize == SOUND_SIZE_16_BIT) { michael@0: for (var i = 0, j = 0; i < pcm.length; i++, j += 2) michael@0: pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648; michael@0: packaged = packageWave(data, sampleRate, channels, 16, false); michael@0: } else { michael@0: for (var i = 0; i < pcm.length; i++) michael@0: pcm[i] = (data[i] - 128) / 128; michael@0: packaged = packageWave(data, sampleRate, channels, 8, false); michael@0: } michael@0: break; michael@0: case SOUND_FORMAT_MP3: michael@0: packaged = { michael@0: data: new Uint8Array(data.subarray(2)), michael@0: mimeType: 'audio/mpeg' michael@0: }; michael@0: break; michael@0: case SOUND_FORMAT_ADPCM: michael@0: var pcm16 = new Int16Array(samplesCount * channels); michael@0: decodeACPCMSoundData(data, pcm16, channels); michael@0: pcm = new Float32Array(samplesCount * channels); michael@0: for (var i = 0; i < pcm.length; i++) michael@0: pcm[i] = pcm16[i] / 32768; michael@0: packaged = packageWave(new Uint8Array(pcm16.buffer), sampleRate, channels, 16, !new Uint8Array(new Uint16Array([ michael@0: 1 michael@0: ]).buffer)[0]); michael@0: break; michael@0: default: michael@0: throw new Error('Unsupported audio format: ' + tag.soundFormat); michael@0: } michael@0: var sound = { michael@0: type: 'sound', michael@0: id: tag.id, michael@0: sampleRate: sampleRate, michael@0: channels: channels, michael@0: pcm: pcm michael@0: }; michael@0: if (packaged) michael@0: sound.packaged = packaged; michael@0: return sound; michael@0: } michael@0: var ACPCMIndexTables = [ michael@0: [ michael@0: -1, michael@0: 2 michael@0: ], michael@0: [ michael@0: -1, michael@0: -1, michael@0: 2, michael@0: 4 michael@0: ], michael@0: [ michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: 2, michael@0: 4, michael@0: 6, michael@0: 8 michael@0: ], michael@0: [ michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: -1, michael@0: 1, michael@0: 2, michael@0: 4, michael@0: 6, michael@0: 8, michael@0: 10, michael@0: 13, michael@0: 16 michael@0: ] michael@0: ]; michael@0: var ACPCMStepSizeTable = [ michael@0: 7, michael@0: 8, michael@0: 9, michael@0: 10, michael@0: 11, michael@0: 12, michael@0: 13, michael@0: 14, michael@0: 16, michael@0: 17, michael@0: 19, michael@0: 21, michael@0: 23, michael@0: 25, michael@0: 28, michael@0: 31, michael@0: 34, michael@0: 37, michael@0: 41, michael@0: 45, michael@0: 50, michael@0: 55, michael@0: 60, michael@0: 66, michael@0: 73, michael@0: 80, michael@0: 88, michael@0: 97, michael@0: 107, michael@0: 118, michael@0: 130, michael@0: 143, michael@0: 157, michael@0: 173, michael@0: 190, michael@0: 209, michael@0: 230, michael@0: 253, michael@0: 279, michael@0: 307, michael@0: 337, michael@0: 371, michael@0: 408, michael@0: 449, michael@0: 494, michael@0: 544, michael@0: 598, michael@0: 658, michael@0: 724, michael@0: 796, michael@0: 876, michael@0: 963, michael@0: 1060, michael@0: 1166, michael@0: 1282, michael@0: 1411, michael@0: 1552, michael@0: 1707, michael@0: 1878, michael@0: 2066, michael@0: 2272, michael@0: 2499, michael@0: 2749, michael@0: 3024, michael@0: 3327, michael@0: 3660, michael@0: 4026, michael@0: 4428, michael@0: 4871, michael@0: 5358, michael@0: 5894, michael@0: 6484, michael@0: 7132, michael@0: 7845, michael@0: 8630, michael@0: 9493, michael@0: 10442, michael@0: 11487, michael@0: 12635, michael@0: 13899, michael@0: 15289, michael@0: 16818, michael@0: 18500, michael@0: 20350, michael@0: 22385, michael@0: 24623, michael@0: 27086, michael@0: 29794, michael@0: 32767 michael@0: ]; michael@0: function decodeACPCMSoundData(data, pcm16, channels) { michael@0: function readBits(n, signed) { michael@0: while (dataBufferLength < n) { michael@0: dataBuffer = dataBuffer << 8 | data[dataPosition++]; michael@0: dataBufferLength += 8; michael@0: } michael@0: dataBufferLength -= n; michael@0: return dataBuffer >>> dataBufferLength & (1 << n) - 1; michael@0: } michael@0: var dataPosition = 0; michael@0: var dataBuffer = 0; michael@0: var dataBufferLength = 0; michael@0: var pcmPosition = 0; michael@0: var codeSize = readBits(2); michael@0: var indexTable = ACPCMIndexTables[codeSize]; michael@0: while (pcmPosition < pcm16.length) { michael@0: var x = pcm16[pcmPosition++] = readBits(16) << 16 >> 16, x2; michael@0: var stepIndex = readBits(6), stepIndex2; michael@0: if (channels > 1) { michael@0: x2 = pcm16[pcmPosition++] = readBits(16) << 16 >> 16; michael@0: stepIndex2 = readBits(6); michael@0: } michael@0: var signMask = 1 << codeSize + 1; michael@0: for (var i = 0; i < 4095; i++) { michael@0: var nibble = readBits(codeSize + 2); michael@0: var step = ACPCMStepSizeTable[stepIndex]; michael@0: var sum = 0; michael@0: for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) { michael@0: if (nibble & currentBit) michael@0: sum += step; michael@0: } michael@0: x += (nibble & signMask ? -1 : 1) * (sum + step); michael@0: pcm16[pcmPosition++] = x = x < -32768 ? -32768 : x > 32767 ? 32767 : x; michael@0: stepIndex += indexTable[nibble & ~signMask]; michael@0: stepIndex = stepIndex < 0 ? 0 : stepIndex > 88 ? 88 : stepIndex; michael@0: if (channels > 1) { michael@0: nibble = readBits(codeSize + 2); michael@0: step = ACPCMStepSizeTable[stepIndex2]; michael@0: sum = 0; michael@0: for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) { michael@0: if (nibble & currentBit) michael@0: sum += step; michael@0: } michael@0: x2 += (nibble & signMask ? -1 : 1) * (sum + step); michael@0: pcm16[pcmPosition++] = x2 = x2 < -32768 ? -32768 : x2 > 32767 ? 32767 : x2; michael@0: stepIndex2 += indexTable[nibble & ~signMask]; michael@0: stepIndex2 = stepIndex2 < 0 ? 0 : stepIndex2 > 88 ? 88 : stepIndex2; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var nextSoundStreamId = 0; michael@0: function SwfSoundStream(samplesCount, sampleRate, channels) { michael@0: this.streamId = nextSoundStreamId++; michael@0: this.samplesCount = samplesCount; michael@0: this.sampleRate = sampleRate; michael@0: this.channels = channels; michael@0: this.format = null; michael@0: this.currentSample = 0; michael@0: } michael@0: SwfSoundStream.prototype = { michael@0: get info() { michael@0: return { michael@0: samplesCount: this.samplesCount, michael@0: sampleRate: this.sampleRate, michael@0: channels: this.channels, michael@0: format: this.format, michael@0: streamId: this.streamId michael@0: }; michael@0: }, michael@0: decode: function (data) { michael@0: throw new Error('SwfSoundStream.decode: not implemented'); michael@0: } michael@0: }; michael@0: function SwfSoundStream_decode_PCM(data) { michael@0: var pcm = new Float32Array(data.length); michael@0: for (var i = 0; i < pcm.length; i++) michael@0: pcm[i] = (data[i] - 128) / 128; michael@0: this.currentSample += pcm.length / this.channels; michael@0: return { michael@0: streamId: this.streamId, michael@0: samplesCount: pcm.length / this.channels, michael@0: pcm: pcm michael@0: }; michael@0: } michael@0: function SwfSoundStream_decode_PCM_be(data) { michael@0: var pcm = new Float32Array(data.length / 2); michael@0: for (var i = 0, j = 0; i < pcm.length; i++, j += 2) michael@0: pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648; michael@0: this.currentSample += pcm.length / this.channels; michael@0: return { michael@0: streamId: this.streamId, michael@0: samplesCount: pcm.length / this.channels, michael@0: pcm: pcm michael@0: }; michael@0: } michael@0: function SwfSoundStream_decode_PCM_le(data) { michael@0: var pcm = new Float32Array(data.length / 2); michael@0: for (var i = 0, j = 0; i < pcm.length; i++, j += 2) michael@0: pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648; michael@0: this.currentSample += pcm.length / this.channels; michael@0: return { michael@0: streamId: this.streamId, michael@0: samplesCount: pcm.length / this.channels, michael@0: pcm: pcm michael@0: }; michael@0: } michael@0: function SwfSoundStream_decode_MP3(data) { michael@0: var samplesCount = data[1] << 8 | data[0]; michael@0: var seek = data[3] << 8 | data[2]; michael@0: this.currentSample += samplesCount; michael@0: return { michael@0: streamId: this.streamId, michael@0: samplesCount: samplesCount, michael@0: data: new Uint8Array(data.subarray(4)), michael@0: seek: seek michael@0: }; michael@0: } michael@0: function createSoundStream(tag) { michael@0: var channels = tag.streamType == SOUND_TYPE_STEREO ? 2 : 1; michael@0: var samplesCount = tag.samplesCount; michael@0: var sampleRate = SOUND_RATES[tag.streamRate]; michael@0: var stream = new SwfSoundStream(samplesCount, sampleRate, channels); michael@0: switch (tag.streamCompression) { michael@0: case SOUND_FORMAT_PCM_BE: michael@0: stream.format = 'wave'; michael@0: if (tag.soundSize == SOUND_SIZE_16_BIT) { michael@0: stream.decode = SwfSoundStream_decode_PCM_be; michael@0: } else { michael@0: stream.decode = SwfSoundStream_decode_PCM; michael@0: } michael@0: break; michael@0: case SOUND_FORMAT_PCM_LE: michael@0: stream.format = 'wave'; michael@0: if (tag.soundSize == SOUND_SIZE_16_BIT) { michael@0: stream.decode = SwfSoundStream_decode_PCM_le; michael@0: } else { michael@0: stream.decode = SwfSoundStream_decode_PCM; michael@0: } michael@0: break; michael@0: case SOUND_FORMAT_MP3: michael@0: stream.format = 'mp3'; michael@0: stream.decode = SwfSoundStream_decode_MP3; michael@0: break; michael@0: default: michael@0: throw new Error('Unsupported audio format: ' + tag.soundFormat); michael@0: } michael@0: return stream; michael@0: } michael@0: function defineText(tag, dictionary) { michael@0: var dependencies = []; michael@0: if (tag.hasFont) { michael@0: var font = dictionary[tag.fontId]; michael@0: tag.font = font.uniqueName; michael@0: dependencies.push(font.id); michael@0: } michael@0: var props = { michael@0: type: 'text', michael@0: id: tag.id, michael@0: variableName: tag.variableName, michael@0: tag: tag michael@0: }; michael@0: if (dependencies.length) michael@0: props.require = dependencies; michael@0: return props; michael@0: } michael@0: var isWorker = typeof window === 'undefined'; michael@0: if (isWorker) { michael@0: importScripts('../../../lib/mp3/mp3.js'); michael@0: self.addEventListener('message', function (e) { michael@0: var data = e.data; michael@0: var sessionId = data.sessionId; michael@0: try { michael@0: switch (data.action) { michael@0: case 'create': michael@0: var session = new Session(sessionId); michael@0: sessions[sessionId] = session; michael@0: break; michael@0: case 'close': michael@0: var session = sessions[sessionId]; michael@0: if (session) { michael@0: session.close(); michael@0: sessions[sessionId] = null; michael@0: } michael@0: break; michael@0: case 'decode': michael@0: var session = sessions[sessionId]; michael@0: if (!session) { michael@0: throw new Error('mp3 decoding session is unavailable'); michael@0: } michael@0: session.decode(data.data); michael@0: break; michael@0: } michael@0: } catch (ex) { michael@0: self.postMessage({ michael@0: sessionId: sessionId, michael@0: action: 'error', michael@0: message: ex.message michael@0: }); michael@0: } michael@0: }, false); michael@0: var sessions = {}; michael@0: function Session(id) { michael@0: this.id = id; michael@0: if (typeof MP3Decoder === 'undefined') { michael@0: throw new Error('mp3 decoder is not available'); michael@0: } michael@0: var decoder = new MP3Decoder(); michael@0: decoder.onframedata = function (frameData, channels, sampleRate, bitRate) { michael@0: self.postMessage({ michael@0: sessionId: this.id, michael@0: action: 'frame', michael@0: frameData: frameData, michael@0: channels: channels, michael@0: sampleRate: sampleRate, michael@0: bitRate: bitRate michael@0: }); michael@0: }.bind(this); michael@0: decoder.onid3tag = function (data) { michael@0: self.postMessage({ michael@0: sessionId: this.id, michael@0: action: 'id3', michael@0: id3Data: data michael@0: }); michael@0: }.bind(this); michael@0: this.decoder = decoder; michael@0: } michael@0: Session.prototype = { michael@0: decode: function (data) { michael@0: this.decoder.push(data); michael@0: }, michael@0: close: function () { michael@0: self.postMessage({ michael@0: sessionId: this.id, michael@0: action: 'closed' michael@0: }); michael@0: } michael@0: }; michael@0: self.console = { michael@0: log: function (s) { michael@0: self.postMessage({ michael@0: action: 'console', michael@0: method: 'log', michael@0: message: s michael@0: }); michael@0: }, michael@0: error: function (s) { michael@0: self.postMessage({ michael@0: action: 'console', michael@0: method: 'error', michael@0: message: s michael@0: }); michael@0: } michael@0: }; michael@0: } else { michael@0: var mp3Worker; michael@0: function createMP3Worker() { michael@0: var worker = new Worker(SHUMWAY_ROOT + 'swf/mp3worker.js'); michael@0: worker.addEventListener('message', function (e) { michael@0: if (e.data.action === 'console') { michael@0: console[e.data.method].call(console, e.data.message); michael@0: } michael@0: }); michael@0: return worker; michael@0: } michael@0: var nextSessionId = 0; michael@0: function MP3DecoderSession() { michael@0: mp3Worker = mp3Worker || createMP3Worker(); michael@0: var sessionId = nextSessionId++; michael@0: this.id = sessionId; michael@0: this.onworkermessage = function (e) { michael@0: if (e.data.sessionId !== sessionId) michael@0: return; michael@0: var action = e.data.action; michael@0: switch (action) { michael@0: case 'closed': michael@0: if (this.onclosed) michael@0: this.onclosed(); michael@0: mp3Worker.removeEventListener('message', this.onworkermessage, false); michael@0: break; michael@0: case 'frame': michael@0: this.onframedata(e.data.frameData, e.data.channels, e.data.sampleRate, e.data.bitRate); michael@0: break; michael@0: case 'id3': michael@0: if (this.onid3tag) michael@0: this.onid3tag(e.data.id3Data); michael@0: break; michael@0: case 'error': michael@0: if (this.onerror) michael@0: this.onerror(e.data.message); michael@0: break; michael@0: } michael@0: }.bind(this); michael@0: mp3Worker.addEventListener('message', this.onworkermessage, false); michael@0: mp3Worker.postMessage({ michael@0: sessionId: sessionId, michael@0: action: 'create' michael@0: }); michael@0: } michael@0: MP3DecoderSession.prototype = { michael@0: pushAsync: function (data) { michael@0: mp3Worker.postMessage({ michael@0: sessionId: this.id, michael@0: action: 'decode', michael@0: data: data michael@0: }); michael@0: }, michael@0: close: function () { michael@0: mp3Worker.postMessage({ michael@0: sessionId: this.id, michael@0: action: 'close' michael@0: }); michael@0: } michael@0: }; michael@0: MP3DecoderSession.processAll = function (data, onloaded) { michael@0: var currentBufferSize = 8000; michael@0: var currentBuffer = new Float32Array(currentBufferSize); michael@0: var bufferPosition = 0; michael@0: var id3Tags = []; michael@0: var sessionAborted = false; michael@0: var session = new MP3DecoderSession(); michael@0: session.onframedata = function (frameData, channels, sampleRate, bitRate) { michael@0: var needed = frameData.length + bufferPosition; michael@0: if (needed > currentBufferSize) { michael@0: do { michael@0: currentBufferSize *= 2; michael@0: } while (needed > currentBufferSize); michael@0: var newBuffer = new Float32Array(currentBufferSize); michael@0: newBuffer.set(currentBuffer); michael@0: currentBuffer = newBuffer; michael@0: } michael@0: currentBuffer.set(frameData, bufferPosition); michael@0: bufferPosition += frameData.length; michael@0: }; michael@0: session.onid3tag = function (tagData) { michael@0: id3Tags.push(tagData); michael@0: }; michael@0: session.onclosed = function () { michael@0: if (sessionAborted) michael@0: return; michael@0: onloaded(currentBuffer.subarray(0, bufferPosition), id3Tags); michael@0: }; michael@0: session.onerror = function (error) { michael@0: if (sessionAborted) michael@0: return; michael@0: sessionAborted = true; michael@0: onloaded(null, null, error); michael@0: }; michael@0: session.pushAsync(data); michael@0: session.close(); michael@0: }; michael@0: } michael@0: SWF.embed = function (file, doc, container, options) { michael@0: var canvas = doc.createElement('canvas'); michael@0: var ctx = canvas.getContext('2d'); michael@0: var loader = new flash.display.Loader(); michael@0: var loaderInfo = loader._contentLoaderInfo; michael@0: var stage = new flash.display.Stage(); michael@0: var pixelRatio = 1; michael@0: var forceHidpiSetting = forceHidpi.value; michael@0: stage._loader = loader; michael@0: loaderInfo._parameters = options.movieParams; michael@0: loaderInfo._url = options.url || (typeof file === 'string' ? file : null); michael@0: loaderInfo._loaderURL = options.loaderURL || loaderInfo._url; michael@0: loader._parent = stage; michael@0: loader._stage = stage; michael@0: function setCanvasSize(width, height) { michael@0: if (pixelRatio === 1) { michael@0: canvas.width = width | 0; michael@0: canvas.height = height | 0; michael@0: return; michael@0: } michael@0: var canvasWidth = Math.floor(width * pixelRatio); michael@0: var canvasHeight = Math.floor(height * pixelRatio); michael@0: canvas.style.width = canvasWidth / pixelRatio + 'px'; michael@0: canvas.style.height = canvasHeight / pixelRatio + 'px'; michael@0: canvas.width = canvasWidth; michael@0: canvas.height = canvasHeight; michael@0: } michael@0: function fitCanvas(container) { michael@0: setCanvasSize(container.clientWidth, container.clientHeight); michael@0: stage._invalid = true; michael@0: } michael@0: loaderInfo._addEventListener('init', function () { michael@0: if (forceHidpiSetting || loaderInfo._swfVersion >= 18) { michael@0: pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; michael@0: } michael@0: canvas._pixelRatio = pixelRatio; michael@0: stage._contentsScaleFactor = pixelRatio; michael@0: if (container.clientHeight) { michael@0: fitCanvas(container); michael@0: window.addEventListener('resize', function () { michael@0: fitCanvas(container); michael@0: }); michael@0: } else { michael@0: setCanvasSize(stage._stageWidth / 20, stage._stageHeight / 20); michael@0: } michael@0: container.setAttribute('style', 'position: relative'); michael@0: canvas.addEventListener('click', function () { michael@0: ShumwayKeyboardListener.focus = stage; michael@0: stage._mouseTarget._dispatchEvent('click'); michael@0: }); michael@0: canvas.addEventListener('dblclick', function () { michael@0: if (stage._mouseTarget._doubleClickEnabled) { michael@0: stage._mouseTarget._dispatchEvent('doubleClick'); michael@0: } michael@0: }); michael@0: canvas.addEventListener('mousedown', function () { michael@0: stage._mouseEvents.push('mousedown'); michael@0: }); michael@0: canvas.addEventListener('mousemove', function (domEvt) { michael@0: var node = this; michael@0: var left = 0; michael@0: var top = 0; michael@0: if (node.offsetParent) { michael@0: do { michael@0: left += node.offsetLeft; michael@0: top += node.offsetTop; michael@0: } while (node = node.offsetParent); michael@0: } michael@0: var m = stage._concatenatedTransform; michael@0: var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx / 20) / m.a; michael@0: var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty / 20) / m.d; michael@0: if (mouseX !== stage._mouseX || mouseY !== stage._mouseY) { michael@0: stage._mouseMoved = true; michael@0: stage._mouseX = mouseX * 20; michael@0: stage._mouseY = mouseY * 20; michael@0: } michael@0: }); michael@0: canvas.addEventListener('mouseup', function () { michael@0: stage._mouseEvents.push('mouseup'); michael@0: }); michael@0: canvas.addEventListener('mouseover', function () { michael@0: stage._mouseMoved = true; michael@0: stage._mouseOver = true; michael@0: }); michael@0: canvas.addEventListener('mouseout', function () { michael@0: stage._mouseMoved = true; michael@0: stage._mouseOver = false; michael@0: }); michael@0: window.addEventListener('message', function (evt) { michael@0: var data = evt.data; michael@0: if (typeof data !== 'object' || data === null) { michael@0: return; michael@0: } michael@0: var type = data.type; michael@0: switch (type) { michael@0: case 'mousemove': michael@0: case 'mouseup': michael@0: case 'mousedown': michael@0: var isMouseMove = type === 'mousemove'; michael@0: stage._mouseMoved = true; michael@0: stage._mouseOver = true; michael@0: stage._mouseX = data.x * 20; michael@0: stage._mouseY = data.y * 20; michael@0: if (!isMouseMove) { michael@0: stage._mouseEvents.push(type); michael@0: } michael@0: break; michael@0: case 'mouseover': michael@0: case 'mouseout': michael@0: stage._mouseMoved = true; michael@0: stage._mouseOver = type === 'mouseover'; michael@0: break; michael@0: case 'keyup': michael@0: case 'keydown': michael@0: 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)); michael@0: break; michael@0: } michael@0: }, false); michael@0: var bgcolor = loaderInfo._backgroundColor; michael@0: if (options.objectParams) { michael@0: var m; michael@0: if (options.objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(options.objectParams.bgcolor))) { michael@0: var hexColor = parseInt(m[1], 16); michael@0: bgcolor = { michael@0: red: hexColor >> 16 & 255, michael@0: green: hexColor >> 8 & 255, michael@0: blue: hexColor & 255, michael@0: alpha: 255 michael@0: }; michael@0: } michael@0: if (options.objectParams.wmode === 'transparent') { michael@0: bgcolor = { michael@0: red: 0, michael@0: green: 0, michael@0: blue: 0, michael@0: alpha: 0 michael@0: }; michael@0: } michael@0: } michael@0: stage._color = bgcolor; michael@0: ctx.fillStyle = rgbaObjToStr(bgcolor); michael@0: ctx.fillRect(0, 0, canvas.width, canvas.height); michael@0: var root = loader._content; michael@0: root._dispatchEvent('added', undefined, true); michael@0: root._dispatchEvent('addedToStage'); michael@0: container.appendChild(canvas); michael@0: stage._domContainer = container; michael@0: if (options.onStageInitialized) { michael@0: options.onStageInitialized(stage); michael@0: } michael@0: var startPromise = options.startPromise || Promise.resolve(); michael@0: startPromise.then(function () { michael@0: renderStage(stage, ctx, options); michael@0: }); michael@0: }); michael@0: if (options.onParsed) { michael@0: loaderInfo._addEventListener('parsed', function () { michael@0: options.onParsed(); michael@0: }); michael@0: } michael@0: if (options.onComplete) { michael@0: loaderInfo._addEventListener('complete', function () { michael@0: options.onComplete(); michael@0: }); michael@0: } michael@0: loader._load(typeof file === 'string' ? new flash.net.URLRequest(file) : file); michael@0: return loader; michael@0: }; michael@0: var rendererOptions = coreOptions.register(new OptionSet('Renderer Options')); michael@0: var traceRenderer = rendererOptions.register(new Option('tr', 'traceRenderer', 'number', 0, 'trace renderer execution')); michael@0: var disableRenderVisitor = rendererOptions.register(new Option('drv', 'disableRenderVisitor', 'boolean', false, 'disable render visitor')); michael@0: var disableMouseVisitor = rendererOptions.register(new Option('dmv', 'disableMouseVisitor', 'boolean', false, 'disable mouse visitor')); michael@0: var showRedrawRegions = rendererOptions.register(new Option('rr', 'showRedrawRegions', 'boolean', false, 'show redraw regions')); michael@0: var renderAsWireframe = rendererOptions.register(new Option('raw', 'renderAsWireframe', 'boolean', false, 'render as wireframe')); michael@0: var showQuadTree = rendererOptions.register(new Option('qt', 'showQuadTree', 'boolean', false, 'show quad tree')); michael@0: var turboMode = rendererOptions.register(new Option('', 'turbo', 'boolean', false, 'turbo mode')); michael@0: var forceHidpi = rendererOptions.register(new Option('', 'forceHidpi', 'boolean', false, 'force hidpi')); michael@0: var skipFrameDraw = rendererOptions.register(new Option('', 'skipFrameDraw', 'boolean', false, 'skip frame when not on time')); michael@0: var hud = rendererOptions.register(new Option('', 'hud', 'boolean', false, 'show hud mode')); michael@0: var dummyAnimation = rendererOptions.register(new Option('', 'dummy', 'boolean', false, 'show test balls animation')); michael@0: var enableConstructChildren = rendererOptions.register(new Option('', 'constructChildren', 'boolean', true, 'Construct Children')); michael@0: var enableEnterFrame = rendererOptions.register(new Option('', 'enterFrame', 'boolean', true, 'Enter Frame')); michael@0: var enableAdvanceFrame = rendererOptions.register(new Option('', 'advanceFrame', 'boolean', true, 'Advance Frame')); michael@0: var CanvasCache = { michael@0: cache: [], michael@0: getCanvas: function getCanvas(protoCanvas) { michael@0: var tempCanvas = this.cache.shift(); michael@0: if (!tempCanvas) { michael@0: tempCanvas = { michael@0: canvas: document.createElement('canvas') michael@0: }; michael@0: tempCanvas.ctx = tempCanvas.canvas.getContext('2d'); michael@0: } michael@0: tempCanvas.canvas.width = protoCanvas.width; michael@0: tempCanvas.canvas.height = protoCanvas.height; michael@0: tempCanvas.ctx.save(); michael@0: return tempCanvas; michael@0: }, michael@0: releaseCanvas: function releaseCanvas(tempCanvas) { michael@0: tempCanvas.ctx.restore(); michael@0: this.cache.push(tempCanvas); michael@0: } michael@0: }; michael@0: function isCanvasVisible(canvas) { michael@0: if (canvas.ownerDocument.hidden) { michael@0: return false; michael@0: } michael@0: if (canvas.mozVisible === false) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: function visitContainer(container, visitor, context) { michael@0: var children = container._children; michael@0: visitor.childrenStart(container); michael@0: for (var i = 0, n = children.length; i < n; i++) { michael@0: var child = children[i]; michael@0: if (!child) { michael@0: continue; michael@0: } michael@0: if (visitor.ignoreVisibleAttribute || child._visible && !child._maskedObject) { michael@0: visitor.visit(child, visitContainer, context); michael@0: } michael@0: } michael@0: visitor.childrenEnd(container); michael@0: } michael@0: var BlendModeNameMap = { michael@0: 'normal': 'normal', michael@0: 'multiply': 'multiply', michael@0: 'screen': 'screen', michael@0: 'lighten': 'lighten', michael@0: 'darken': 'darken', michael@0: 'difference': 'difference', michael@0: 'overlay': 'overlay', michael@0: 'hardlight': 'hard-light' michael@0: }; michael@0: function getBlendModeName(blendMode) { michael@0: return BlendModeNameMap[blendMode] || 'normal'; michael@0: } michael@0: function RenderVisitor(root, ctx, invalidPath, refreshStage) { michael@0: this.root = root; michael@0: this.ctx = ctx; michael@0: this.depth = 0; michael@0: this.invalidPath = invalidPath; michael@0: this.refreshStage = refreshStage; michael@0: this.clipDepth = null; michael@0: this.clipStack = null; michael@0: } michael@0: RenderVisitor.prototype = { michael@0: ignoreVisibleAttribute: false, michael@0: start: function () { michael@0: visitContainer(this.root, this, new RenderingContext(this.refreshStage, this.invalidPath)); michael@0: }, michael@0: startFragment: function (matrix) { michael@0: var root = this.root; michael@0: var currentTransform = root._currentTransform; michael@0: var t = currentTransform; michael@0: if (matrix) { michael@0: t = root._currentTransform = { michael@0: a: matrix.a, michael@0: b: matrix.b, michael@0: c: matrix.c, michael@0: d: matrix.d, michael@0: tx: matrix.tx * 20 | 0, michael@0: ty: matrix.ty * 20 | 0 michael@0: }; michael@0: root._invalidateTransform(); michael@0: } michael@0: var inverse; michael@0: if (t) { michael@0: inverse = new flash.geom.Matrix(t.a, t.b, t.c, t.d, t.tx / 20, t.ty / 20); michael@0: inverse.invert(); michael@0: this.ctx.save(); michael@0: this.ctx.transform(inverse.a, inverse.b, inverse.c, inverse.d, inverse.tx, inverse.ty); michael@0: } michael@0: this.visit(root, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath)); michael@0: if (t) { michael@0: this.ctx.restore(); michael@0: } michael@0: if (matrix) { michael@0: root._currentTransform = currentTransform; michael@0: root._invalidateTransform(); michael@0: } michael@0: }, michael@0: childrenStart: function (parent) { michael@0: if (this.depth === 0) { michael@0: var ctx = this.ctx; michael@0: ctx.save(); michael@0: if (this.invalidPath && !this.refreshStage && !renderAsWireframe.value) { michael@0: this.invalidPath.draw(ctx, false, 0, null); michael@0: ctx.clip(); michael@0: } michael@0: var bgcolor = this.root._color; michael@0: if (bgcolor) { michael@0: if (bgcolor.alpha < 255) { michael@0: ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); michael@0: } michael@0: if (bgcolor.alpha > 0) { michael@0: ctx.fillStyle = rgbaObjToStr(bgcolor); michael@0: if (this.invalidPath && !this.refreshStage && !renderAsWireframe.value) { michael@0: ctx.fill(); michael@0: } else { michael@0: ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); michael@0: } michael@0: } michael@0: } michael@0: ctx.mozFillRule = 'evenodd'; michael@0: } michael@0: this.depth++; michael@0: if (this.clipDepth && this.clipDepth.length > 0) { michael@0: this.clipStack = { michael@0: depth: this.depth, michael@0: clip: this.clipDepth, michael@0: next: this.clipStack michael@0: }; michael@0: this.clipDepth = null; michael@0: } michael@0: }, michael@0: childrenEnd: function (parent) { michael@0: if (this.clipDepth) { michael@0: while (this.clipDepth.length > 0) { michael@0: var clipDepthInfo = this.clipDepth.pop(); michael@0: this.clipEnd(clipDepthInfo); michael@0: this.ctx = clipDepthInfo.ctx; michael@0: } michael@0: this.clipDepth = null; michael@0: } michael@0: if (this.clipStack && this.clipStack.depth === this.depth) { michael@0: this.clipDepth = this.clipStack.clip; michael@0: this.clipStack = this.clipStack.next; michael@0: } michael@0: this.depth--; michael@0: if (this.depth === 0) { michael@0: this.ctx.restore(); michael@0: this.invalidPath = null; michael@0: } michael@0: }, michael@0: visit: function (child, visitContainer, context) { michael@0: var ctx = this.ctx; michael@0: var parentHasClippingMask = context.isClippingMask; michael@0: var parentColorTransform = context.colorTransform; michael@0: var clippingMask = parentHasClippingMask === true; michael@0: if (child._cxform) { michael@0: context.colorTransform = parentColorTransform.applyCXForm(child._cxform); michael@0: } michael@0: if (!clippingMask) { michael@0: while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0].clipDepth) { michael@0: var clipDepthInfo = this.clipDepth.shift(); michael@0: this.clipEnd(clipDepthInfo); michael@0: context.parentCtxs.shift(); michael@0: ctx = this.ctx = clipDepthInfo.ctx; michael@0: } michael@0: if (this.clipDepth && this.clipDepth.length > 0 && child._depth <= this.clipDepth[0].clipDepth) { michael@0: ctx = this.ctx = this.clipDepth[0].maskee.ctx; michael@0: } michael@0: if (child._clipDepth) { michael@0: context.isClippingMask = clippingMask = true; michael@0: var clipDepthInfo = this.clipStart(child); michael@0: if (!this.clipDepth) { michael@0: this.clipDepth = [ michael@0: clipDepthInfo michael@0: ]; michael@0: } else { michael@0: this.clipDepth.unshift(clipDepthInfo); michael@0: } michael@0: context.parentCtxs.unshift(ctx); michael@0: ctx = this.ctx = clipDepthInfo.mask.ctx; michael@0: } michael@0: } michael@0: if (clippingMask && child._isContainer) { michael@0: ctx.save(); michael@0: renderDisplayObject(child, ctx, context); michael@0: for (var i = 0, n = child._children.length; i < n; i++) { michael@0: var child1 = child._children[i]; michael@0: if (!child1) { michael@0: continue; michael@0: } michael@0: if (this.ignoreVisibleAttribute || child1._visible && !child1._maskedObject) { michael@0: this.visit(child1, visitContainer, context); michael@0: } michael@0: } michael@0: ctx.restore(); michael@0: ctx.fill(); michael@0: context.isClippingMask = parentHasClippingMask; michael@0: context.colorTransform = parentColorTransform; michael@0: return; michael@0: } michael@0: ctx.save(); michael@0: ctx.globalCompositeOperation = getBlendModeName(child._blendMode); michael@0: if (child._mask) { michael@0: var clipInfo = this.clipStart(child); michael@0: var mask = clipInfo.mask; michael@0: var maskee = clipInfo.maskee; michael@0: context.parentCtxs.push(ctx); michael@0: var savedClipDepth = this.clipDepth; michael@0: this.clipDepth = null; michael@0: this.ctx = mask.ctx; michael@0: this.visit(child._mask, visitContainer, new RenderingContext(this.refreshStage)); michael@0: this.ctx = ctx; michael@0: this.clipDepth = savedClipDepth; michael@0: renderDisplayObject(child, maskee.ctx, context); michael@0: if (child._isContainer) { michael@0: this.ctx = maskee.ctx; michael@0: visitContainer(child, this, context); michael@0: this.ctx = ctx; michael@0: } michael@0: context.parentCtxs.pop(); michael@0: this.clipEnd(clipInfo); michael@0: } else { michael@0: renderDisplayObject(child, ctx, context); michael@0: if (child._isContainer) { michael@0: visitContainer(child, this, context); michael@0: } michael@0: } michael@0: ctx.restore(); michael@0: if (clippingMask) { michael@0: ctx.fill(); michael@0: } michael@0: context.isClippingMask = parentHasClippingMask; michael@0: context.colorTransform = parentColorTransform; michael@0: }, michael@0: clipStart: function (child) { michael@0: var m = child._parent._getConcatenatedTransform(null, true); michael@0: var tx = m.tx / 20; michael@0: var ty = m.ty / 20; michael@0: var mask = CanvasCache.getCanvas(this.ctx.canvas); michael@0: mask.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty); michael@0: var maskee = CanvasCache.getCanvas(this.ctx.canvas); michael@0: maskee.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty); michael@0: var clipInfo = { michael@0: ctx: this.ctx, michael@0: mask: mask, michael@0: maskee: maskee, michael@0: clipDepth: child._clipDepth michael@0: }; michael@0: return clipInfo; michael@0: }, michael@0: clipEnd: function (clipInfo) { michael@0: var ctx = clipInfo.ctx; michael@0: var mask = clipInfo.mask; michael@0: var maskee = clipInfo.maskee; michael@0: maskee.ctx.globalCompositeOperation = 'destination-in'; michael@0: maskee.ctx.setTransform(1, 0, 0, 1, 0, 0); michael@0: maskee.ctx.drawImage(mask.canvas, 0, 0); michael@0: ctx.save(); michael@0: ctx.setTransform(1, 0, 0, 1, 0, 0); michael@0: ctx.drawImage(maskee.canvas, 0, 0); michael@0: ctx.restore(); michael@0: CanvasCache.releaseCanvas(mask); michael@0: CanvasCache.releaseCanvas(maskee); michael@0: } michael@0: }; michael@0: function RenderingColorTransform() { michael@0: this.mode = null; michael@0: this.transform = [ michael@0: 1, michael@0: 1, michael@0: 1, michael@0: 1, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 0 michael@0: ]; michael@0: } michael@0: RenderingColorTransform.prototype = { michael@0: applyCXForm: function (cxform) { michael@0: var t = this.transform; michael@0: t = [ michael@0: t[0] * cxform.redMultiplier / 256, michael@0: t[1] * cxform.greenMultiplier / 256, michael@0: t[2] * cxform.blueMultiplier / 256, michael@0: t[3] * cxform.alphaMultiplier / 256, michael@0: t[4] * cxform.redMultiplier / 256 + cxform.redOffset, michael@0: t[5] * cxform.greenMultiplier / 256 + cxform.greenOffset, michael@0: t[6] * cxform.blueMultiplier / 256 + cxform.blueOffset, michael@0: t[7] * cxform.alphaMultiplier / 256 + cxform.alphaOffset michael@0: ]; michael@0: var mode; michael@0: var PRECISION = 0.0001; michael@0: if (Math.abs(t[0] - 1) < PRECISION && Math.abs(t[1] - 1) < PRECISION && Math.abs(t[2] - 1) < PRECISION && t[3] >= 0 && Math.abs(t[4]) < PRECISION && Math.abs(t[5]) < PRECISION && Math.abs(t[6]) < PRECISION && Math.abs(t[7]) < PRECISION) { michael@0: mode = Math.abs(t[3] - 1) < PRECISION ? null : 'simple'; michael@0: } else { michael@0: mode = 'complex'; michael@0: } michael@0: var clone = Object.create(RenderingColorTransform.prototype); michael@0: clone.mode = mode; michael@0: clone.transform = t; michael@0: return clone; michael@0: }, michael@0: setFillStyle: function (ctx, style) { michael@0: if (this.mode === 'complex') { michael@0: style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style); michael@0: } else if (typeof style === 'number') { michael@0: style = this.convertNumericColor(style); michael@0: } else if (typeof style === 'function') { michael@0: style = style.defaultFillStyle; michael@0: } michael@0: ctx.fillStyle = style; michael@0: }, michael@0: setStrokeStyle: function (ctx, style) { michael@0: if (this.mode === 'complex') { michael@0: style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style); michael@0: } else if (typeof style === 'number') { michael@0: style = this.convertNumericColor(style); michael@0: } else if (typeof style === 'function') { michael@0: style = style.defaultFillStyle; michael@0: } michael@0: ctx.strokeStyle = style; michael@0: }, michael@0: addGradientColorStop: function (gradient, ratio, style) { michael@0: if (this.mode === 'complex') { michael@0: style = this.convertColor(style); michael@0: } else if (typeof style === 'number') { michael@0: style = this.convertNumericColor(style); michael@0: } michael@0: gradient.addColorStop(ratio, style); michael@0: }, michael@0: setAlpha: function (ctx, force) { michael@0: if (this.mode === 'simple' || force) { michael@0: var t = this.transform; michael@0: ctx.globalAlpha = Math.min(1, Math.max(0, ctx.globalAlpha * t[3])); michael@0: } michael@0: }, michael@0: convertNumericColor: function (num) { michael@0: return '#' + (num | 16777216).toString(16).substr(1); michael@0: }, michael@0: convertColor: function (style) { michael@0: var t = this.transform; michael@0: var m; michael@0: switch (typeof style) { michael@0: case 'string': michael@0: if (style[0] === '#') { michael@0: m = [ michael@0: undefined, michael@0: parseInt(style.substr(1, 2), 16), michael@0: parseInt(style.substr(3, 2), 16), michael@0: parseInt(style.substr(5, 2), 16), michael@0: 1 michael@0: ]; michael@0: } michael@0: m = m || /rgba\(([^,]+),([^,]+),([^,]+),([^)]+)\)/.exec(style); michael@0: if (!m) { michael@0: return style; michael@0: } michael@0: break; michael@0: case 'number': michael@0: m = [ michael@0: style, michael@0: style >> 16 & 255, michael@0: style >> 8 & 255, michael@0: style & 255, michael@0: 1 michael@0: ]; michael@0: break; michael@0: default: michael@0: return style; michael@0: } michael@0: var r = Math.min(255, Math.max(0, m[1] * t[0] + t[4])) | 0; michael@0: var g = Math.min(255, Math.max(0, m[2] * t[1] + t[5])) | 0; michael@0: var b = Math.min(255, Math.max(0, m[3] * t[2] + t[6])) | 0; michael@0: var a = Math.min(1, Math.max(0, m[4] * t[3] + t[7] / 256)); michael@0: return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; michael@0: }, michael@0: getTransformFingerprint: function () { michael@0: return this.transform.join('|'); michael@0: } michael@0: }; michael@0: function RenderingContext(refreshStage, invalidPath) { michael@0: this.refreshStage = refreshStage === true; michael@0: this.invalidPath = invalidPath; michael@0: this.isClippingMask = false; michael@0: this.colorTransform = new RenderingColorTransform(); michael@0: this.parentCtxs = []; michael@0: } michael@0: function renderDisplayObject(child, ctx, context) { michael@0: var m = child._currentTransform; michael@0: if (m) { michael@0: ctx.transform(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20); michael@0: } michael@0: if (!renderAsWireframe.value) { michael@0: if (child._alpha !== 1) { michael@0: ctx.globalAlpha *= child._alpha; michael@0: } michael@0: if (context.invalidPath && !child._invalid && !context.refreshStage) { michael@0: return; michael@0: } michael@0: if (child._graphics) { michael@0: var graphics = child._graphics; michael@0: if (graphics._bitmap) { michael@0: ctx.save(); michael@0: ctx.translate(child._bbox.xMin / 20, child._bbox.yMin / 20); michael@0: context.colorTransform.setAlpha(ctx, true); michael@0: ctx.drawImage(graphics._bitmap, 0, 0); michael@0: ctx.restore(); michael@0: } else { michael@0: var ratio = child.ratio; michael@0: if (ratio === undefined) { michael@0: ratio = 0; michael@0: } michael@0: graphics.draw(ctx, context.isClippingMask, ratio, context.colorTransform); michael@0: } michael@0: } michael@0: if (child.draw) { michael@0: child.draw(ctx, child.ratio, context.colorTransform, context.parentCtxs); michael@0: } michael@0: } else { michael@0: if (!child._invalid && !context.refreshStage) { michael@0: return; michael@0: } michael@0: if (child.getBounds) { michael@0: var b = child.getBounds(null); michael@0: if (b && b.xMax - b.xMin > 0 && b.yMax - b.yMin > 0) { michael@0: if (!child._wireframeStrokeStyle) { michael@0: child._wireframeStrokeStyle = randomStyle(); michael@0: } michael@0: ctx.save(); michael@0: ctx.strokeStyle = child._wireframeStrokeStyle; michael@0: var x = b.xMin / 20; michael@0: var y = b.yMin / 20; michael@0: ctx.strokeRect(x + 0.5, y + 0.5, b.xMax / 20 - x - 1, b.yMax / 20 - y - 1); michael@0: ctx.restore(); michael@0: } michael@0: } michael@0: } michael@0: child._invalid = false; michael@0: } michael@0: function renderQuadTree(ctx, qtree) { michael@0: ctx.strokeRect(qtree.x / 20, qtree.y / 20, qtree.width / 20, qtree.height / 20); michael@0: var nodes = qtree.nodes; michael@0: for (var i = 0; i < nodes.length; i++) { michael@0: renderQuadTree(ctx, nodes[i]); michael@0: } michael@0: } michael@0: var renderingTerminated = false; michael@0: var samplesLeftPlusOne = 0; michael@0: function triggerSampling(count) { michael@0: samplesLeftPlusOne = -count - 1; michael@0: } michael@0: function sampleStart() { michael@0: if (!samplesLeftPlusOne) { michael@0: return; michael@0: } michael@0: if (samplesLeftPlusOne < 0) { michael@0: console.profile('Sample'); michael@0: samplesLeftPlusOne *= -1; michael@0: } michael@0: if (samplesLeftPlusOne > 0) { michael@0: console.info('Sampling Frame: ' + (samplesLeftPlusOne - 1)); michael@0: } michael@0: } michael@0: function sampleEnd() { michael@0: if (!samplesLeftPlusOne) { michael@0: return; michael@0: } michael@0: samplesLeftPlusOne--; michael@0: if (samplesLeftPlusOne === 1) { michael@0: console.profileEnd('Sample'); michael@0: } michael@0: } michael@0: var timeline; michael@0: var hudTimeline; michael@0: function timelineEnter(name) { michael@0: timeline && timeline.enter(name); michael@0: hudTimeline && hudTimeline.enter(name); michael@0: } michael@0: function timelineLeave(name) { michael@0: timeline && timeline.leave(name); michael@0: hudTimeline && hudTimeline.leave(name); michael@0: } michael@0: function timelineWrapBroadcastMessage(domain, message) { michael@0: timelineEnter(message); michael@0: domain.broadcastMessage(message); michael@0: timelineLeave(message); michael@0: } michael@0: function initializeHUD(stage, parentCanvas) { michael@0: var canvas = document.createElement('canvas'); michael@0: var canvasContainer = document.createElement('div'); michael@0: canvasContainer.appendChild(canvas); michael@0: canvasContainer.style.position = 'absolute'; michael@0: canvasContainer.style.top = '0px'; michael@0: canvasContainer.style.left = '0px'; michael@0: canvasContainer.style.width = '100%'; michael@0: canvasContainer.style.height = '150px'; michael@0: canvasContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.4)'; michael@0: canvasContainer.style.pointerEvents = 'none'; michael@0: parentCanvas.parentElement.appendChild(canvasContainer); michael@0: hudTimeline = new Timeline(canvas); michael@0: hudTimeline.setFrameRate(stage._frameRate); michael@0: hudTimeline.refreshEvery(10); michael@0: } michael@0: function createRenderDummyBalls(ctx, stage) { michael@0: var dummyBalls; michael@0: var radius = 10; michael@0: var speed = 1; michael@0: var m = stage._concatenatedTransform; michael@0: var scaleX = m.a, scaleY = m.d; michael@0: dummyBalls = []; michael@0: for (var i = 0; i < 10; i++) { michael@0: dummyBalls.push({ michael@0: position: { michael@0: x: radius + Math.random() * ((ctx.canvas.width - 2 * radius) / scaleX), michael@0: y: radius + Math.random() * ((ctx.canvas.height - 2 * radius) / scaleY) michael@0: }, michael@0: velocity: { michael@0: x: speed * (Math.random() - 0.5), michael@0: y: speed * (Math.random() - 0.5) michael@0: } michael@0: }); michael@0: } michael@0: ctx.fillStyle = 'black'; michael@0: ctx.lineWidth = 2; michael@0: ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); michael@0: return function renderDummyBalls() { michael@0: ctx.fillStyle = 'black'; michael@0: ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); michael@0: ctx.strokeStyle = 'green'; michael@0: dummyBalls.forEach(function (ball) { michael@0: var position = ball.position; michael@0: var velocity = ball.velocity; michael@0: ctx.beginPath(); michael@0: ctx.arc(position.x, position.y, radius, 0, Math.PI * 2, true); michael@0: ctx.stroke(); michael@0: var x = position.x + velocity.x; michael@0: var y = position.y + velocity.y; michael@0: if (x < radius || x > ctx.canvas.width / scaleX - radius) { michael@0: velocity.x *= -1; michael@0: } michael@0: if (y < radius || y > ctx.canvas.height / scaleY - radius) { michael@0: velocity.y *= -1; michael@0: } michael@0: position.x += velocity.x; michael@0: position.y += velocity.y; michael@0: }); michael@0: }; michael@0: } michael@0: function renderStage(stage, ctx, events) { michael@0: var frameWidth, frameHeight; michael@0: if (!timeline && hud.value) { michael@0: initializeHUD(stage, ctx.canvas); michael@0: } michael@0: function updateRenderTransform() { michael@0: frameWidth = ctx.canvas.width; michael@0: frameHeight = ctx.canvas.height; michael@0: var scaleX = frameWidth / stage._stageWidth * 20; michael@0: var scaleY = frameHeight / stage._stageHeight * 20; michael@0: switch (stage._scaleMode) { michael@0: case 'exactFit': michael@0: break; michael@0: case 'noBorder': michael@0: if (scaleX > scaleY) { michael@0: scaleY = scaleX; michael@0: } else { michael@0: scaleX = scaleY; michael@0: } michael@0: break; michael@0: case 'noScale': michael@0: var pixelRatio = ctx.canvas._pixelRatio || 1; michael@0: scaleX = pixelRatio; michael@0: scaleY = pixelRatio; michael@0: break; michael@0: case 'showAll': michael@0: if (scaleX < scaleY) { michael@0: scaleY = scaleX; michael@0: } else { michael@0: scaleX = scaleY; michael@0: } michael@0: break; michael@0: } michael@0: var align = stage._align; michael@0: var offsetX, offsetY; michael@0: if (align.indexOf('L') >= 0) { michael@0: offsetX = 0; michael@0: } else if (align.indexOf('R') >= 0) { michael@0: offsetX = frameWidth - scaleX * stage._stageWidth / 20; michael@0: } else { michael@0: offsetX = (frameWidth - scaleX * stage._stageWidth / 20) / 2; michael@0: } michael@0: if (align.indexOf('T') >= 0) { michael@0: offsetY = 0; michael@0: } else if (align.indexOf('B') >= 0) { michael@0: offsetY = frameHeight - scaleY * stage._stageHeight / 20; michael@0: } else { michael@0: offsetY = (frameHeight - scaleY * stage._stageHeight / 20) / 2; michael@0: } michael@0: ctx.setTransform(scaleX, 0, 0, scaleY, offsetX, offsetY); michael@0: var m = stage._concatenatedTransform; michael@0: m.a = scaleX; michael@0: m.d = scaleY; michael@0: m.tx = offsetX * 20; michael@0: m.ty = offsetY * 20; michael@0: } michael@0: updateRenderTransform(); michael@0: var frameScheduler = new FrameScheduler(); michael@0: stage._frameScheduler = frameScheduler; michael@0: var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout; michael@0: var renderDummyBalls = dummyAnimation.value && createRenderDummyBalls(ctx, stage); michael@0: console.timeEnd('Initialize Renderer'); michael@0: console.timeEnd('Total'); michael@0: var firstRun = true; michael@0: var frameCount = 0; michael@0: var frameFPSAverage = new Shumway.Metrics.Average(120); michael@0: var frameRequested = true; michael@0: function drawFrame(renderFrame, repaint) { michael@0: sampleStart(); michael@0: var refreshStage = false; michael@0: if (stage._invalid) { michael@0: updateRenderTransform(); michael@0: stage._invalid = false; michael@0: refreshStage = true; michael@0: } michael@0: var mouseMoved = false; michael@0: if (stage._mouseMoved) { michael@0: stage._mouseMoved = false; michael@0: mouseMoved = stage._mouseOver; michael@0: } else { michael@0: stage._handleMouseButtons(); michael@0: } michael@0: if (renderFrame || refreshStage || mouseMoved) { michael@0: FrameCounter.clear(); michael@0: var frameStartTime = performance.now(); michael@0: timelineEnter('frame'); michael@0: traceRenderer.value && appendToFrameTerminal('Begin Frame #' + frameCount++, 'purple'); michael@0: var domain = avm2.systemDomain; michael@0: if (renderFrame) { michael@0: timelineEnter('events'); michael@0: if (firstRun) { michael@0: firstRun = false; michael@0: } else { michael@0: enableAdvanceFrame.value && timelineWrapBroadcastMessage(domain, 'advanceFrame'); michael@0: enableEnterFrame.value && timelineWrapBroadcastMessage(domain, 'enterFrame'); michael@0: enableConstructChildren.value && timelineWrapBroadcastMessage(domain, 'constructChildren'); michael@0: } michael@0: timelineWrapBroadcastMessage(domain, 'frameConstructed'); michael@0: timelineWrapBroadcastMessage(domain, 'executeFrame'); michael@0: timelineWrapBroadcastMessage(domain, 'exitFrame'); michael@0: timelineLeave('events'); michael@0: } michael@0: if (stage._deferRenderEvent) { michael@0: stage._deferRenderEvent = false; michael@0: domain.broadcastMessage('render', 'render'); michael@0: } michael@0: var drawEnabled = isCanvasVisible(ctx.canvas) && (refreshStage || renderFrame) && (frameRequested || repaint || !skipFrameDraw.value); michael@0: if (drawEnabled && !repaint && skipFrameDraw.value && frameScheduler.shallSkipDraw) { michael@0: drawEnabled = false; michael@0: frameScheduler.skipDraw(); michael@0: traceRenderer.value && appendToFrameTerminal('Skip Frame Draw', 'red'); michael@0: } michael@0: if (drawEnabled) { michael@0: frameScheduler.startDraw(); michael@0: var invalidPath = null; michael@0: traceRenderer.value && frameWriter.enter('> Invalidation'); michael@0: timelineEnter('invalidate'); michael@0: invalidPath = stage._processInvalidations(refreshStage); michael@0: timelineLeave('invalidate'); michael@0: traceRenderer.value && frameWriter.leave('< Invalidation'); michael@0: if (!disableRenderVisitor.value && !invalidPath.isEmpty) { michael@0: timelineEnter('render'); michael@0: traceRenderer.value && frameWriter.enter('> Rendering'); michael@0: new RenderVisitor(stage, ctx, invalidPath, refreshStage).start(); michael@0: traceRenderer.value && frameWriter.leave('< Rendering'); michael@0: timelineLeave('render'); michael@0: } michael@0: if (showQuadTree.value) { michael@0: ctx.strokeStyle = 'green'; michael@0: renderQuadTree(ctx, stage._qtree); michael@0: } michael@0: if (invalidPath && !refreshStage && showRedrawRegions.value) { michael@0: ctx.strokeStyle = 'red'; michael@0: invalidPath.draw(ctx); michael@0: ctx.stroke(); michael@0: } michael@0: frameScheduler.endDraw(); michael@0: } michael@0: if (mouseMoved && !disableMouseVisitor.value) { michael@0: renderFrame && timelineEnter('mouse'); michael@0: traceRenderer.value && frameWriter.enter('> Mouse Handling'); michael@0: stage._handleMouse(); michael@0: traceRenderer.value && frameWriter.leave('< Mouse Handling'); michael@0: renderFrame && timelineLeave('mouse'); michael@0: ctx.canvas.style.cursor = stage._cursor; michael@0: } michael@0: if (traceRenderer.value) { michael@0: frameWriter.enter('> Frame Counters'); michael@0: for (var name in FrameCounter.counts) { michael@0: frameWriter.writeLn(name + ': ' + FrameCounter.counts[name]); michael@0: } michael@0: frameWriter.leave('< Frame Counters'); michael@0: var frameElapsedTime = performance.now() - frameStartTime; michael@0: var frameFPS = 1000 / frameElapsedTime; michael@0: frameFPSAverage.push(frameFPS); michael@0: traceRenderer.value && appendToFrameTerminal('End Frame Time: ' + frameElapsedTime.toFixed(2) + ' (' + frameFPS.toFixed(2) + ' fps, ' + frameFPSAverage.average().toFixed(2) + ' average fps)', 'purple'); michael@0: } michael@0: timelineLeave('frame'); michael@0: } else { michael@0: traceRenderer.value && appendToFrameTerminal('Skip Frame', 'black'); michael@0: } michael@0: sampleEnd(); michael@0: } michael@0: (function draw() { michael@0: var renderFrame = true; michael@0: if (events.onBeforeFrame) { michael@0: var e = { michael@0: cancel: false michael@0: }; michael@0: events.onBeforeFrame(e); michael@0: renderFrame = !e.cancel; michael@0: } michael@0: if (renderDummyBalls) { michael@0: if (renderFrame) { michael@0: renderDummyBalls(); michael@0: events.onAfterFrame && events.onAfterFrame(); michael@0: } michael@0: setTimeout(draw); michael@0: return; michael@0: } michael@0: frameScheduler.startFrame(stage._frameRate); michael@0: drawFrame(renderFrame, false); michael@0: frameScheduler.endFrame(); michael@0: frameRequested = false; michael@0: if (!frameScheduler.isOnTime) { michael@0: traceRenderer.value && appendToFrameTerminal('Frame Is Late', 'red'); michael@0: } michael@0: if (renderFrame && events.onAfterFrame) { michael@0: events.onAfterFrame(); michael@0: } michael@0: if (renderingTerminated) { michael@0: if (events.onTerminated) { michael@0: events.onTerminated(); michael@0: } michael@0: return; michael@0: } michael@0: setTimeout(draw, turboMode.value ? 0 : frameScheduler.nextFrameIn); michael@0: }()); michael@0: (function frame() { michael@0: if (renderingTerminated) { michael@0: return; michael@0: } michael@0: frameRequested = true; michael@0: if ((stage._invalid || stage._mouseMoved) && !renderDummyBalls) { michael@0: drawFrame(false, true); michael@0: } michael@0: requestAnimationFrame(frame); michael@0: }()); michael@0: } michael@0: var FrameScheduler = function () { michael@0: var STATS_TO_REMEMBER = 50; michael@0: var MAX_DRAWS_TO_SKIP = 2; michael@0: var INTERVAL_PADDING_MS = 4; michael@0: var SPEED_ADJUST_RATE = 0.9; michael@0: function FrameScheduler() { michael@0: this._drawStats = []; michael@0: this._drawStatsSum = 0; michael@0: this._drawStarted = 0; michael@0: this._drawsSkipped = 0; michael@0: this._expectedNextFrameAt = performance.now(); michael@0: this._onTime = true; michael@0: this._trackDelta = false; michael@0: this._delta = 0; michael@0: this._onTimeDelta = 0; michael@0: } michael@0: FrameScheduler.prototype = { michael@0: get shallSkipDraw() { michael@0: if (this._drawsSkipped >= MAX_DRAWS_TO_SKIP) { michael@0: return false; michael@0: } michael@0: var averageDraw = this._drawStats.length < STATS_TO_REMEMBER ? 0 : this._drawStatsSum / this._drawStats.length; michael@0: var estimatedDrawEnd = performance.now() + averageDraw; michael@0: return estimatedDrawEnd + INTERVAL_PADDING_MS > this._expectedNextFrameAt; michael@0: }, michael@0: get nextFrameIn() { michael@0: return Math.max(0, this._expectedNextFrameAt - performance.now()); michael@0: }, michael@0: get isOnTime() { michael@0: return this._onTime; michael@0: }, michael@0: startFrame: function (frameRate) { michael@0: var interval = 1000 / frameRate; michael@0: var adjustedInterval = interval; michael@0: var delta = this._onTimeDelta + this._delta; michael@0: if (delta !== 0) { michael@0: if (delta < 0) { michael@0: adjustedInterval *= SPEED_ADJUST_RATE; michael@0: } else if (delta > 0) { michael@0: adjustedInterval /= SPEED_ADJUST_RATE; michael@0: } michael@0: this._onTimeDelta += interval - adjustedInterval; michael@0: } michael@0: this._expectedNextFrameAt += adjustedInterval; michael@0: this._onTime = true; michael@0: }, michael@0: endFrame: function () { michael@0: var estimatedNextFrameStart = performance.now() + INTERVAL_PADDING_MS; michael@0: if (estimatedNextFrameStart > this._expectedNextFrameAt) { michael@0: if (this._trackDelta) { michael@0: this._onTimeDelta += this._expectedNextFrameAt - estimatedNextFrameStart; michael@0: console.log(this._onTimeDelta); michael@0: } michael@0: this._expectedNextFrameAt = estimatedNextFrameStart; michael@0: this._onTime = false; michael@0: } michael@0: }, michael@0: startDraw: function () { michael@0: this._drawsSkipped = 0; michael@0: this._drawStarted = performance.now(); michael@0: }, michael@0: endDraw: function () { michael@0: var drawTime = performance.now() - this._drawStarted; michael@0: this._drawStats.push(drawTime); michael@0: this._drawStatsSum += drawTime; michael@0: while (this._drawStats.length > STATS_TO_REMEMBER) { michael@0: this._drawStatsSum -= this._drawStats.shift(); michael@0: } michael@0: }, michael@0: skipDraw: function () { michael@0: this._drawsSkipped++; michael@0: }, michael@0: setDelta: function (value) { michael@0: if (!this._trackDelta) { michael@0: return; michael@0: } michael@0: this._delta = value; michael@0: }, michael@0: startTrackDelta: function () { michael@0: this._trackDelta = true; michael@0: }, michael@0: endTrackDelta: function () { michael@0: if (!this._trackDelta) { michael@0: return; michael@0: } michael@0: this._trackDelta = false; michael@0: this._delta = 0; michael@0: this._onTimeDelta = 0; michael@0: } michael@0: }; michael@0: return FrameScheduler; michael@0: }(); michael@0: var tagHandler = function (global) { michael@0: function defineShape($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var $0 = $.bbox = {}; michael@0: bbox($bytes, $stream, $0, swfVersion, tagCode); michael@0: var isMorph = $.isMorph = tagCode === 46 || tagCode === 84; michael@0: if (isMorph) { michael@0: var $1 = $.bboxMorph = {}; michael@0: bbox($bytes, $stream, $1, swfVersion, tagCode); michael@0: } michael@0: var hasStrokes = $.hasStrokes = tagCode === 83 || tagCode === 84; michael@0: if (hasStrokes) { michael@0: var $2 = $.strokeBbox = {}; michael@0: bbox($bytes, $stream, $2, swfVersion, tagCode); michael@0: if (isMorph) { michael@0: var $3 = $.strokeBboxMorph = {}; michael@0: bbox($bytes, $stream, $3, swfVersion, tagCode); michael@0: } michael@0: var reserved = readUb($bytes, $stream, 5); michael@0: $.fillWinding = readUb($bytes, $stream, 1); michael@0: $.nonScalingStrokes = readUb($bytes, $stream, 1); michael@0: $.scalingStrokes = readUb($bytes, $stream, 1); michael@0: } michael@0: if (isMorph) { michael@0: $.offsetMorph = readUi32($bytes, $stream); michael@0: morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: } else { michael@0: shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: } michael@0: return $; michael@0: } michael@0: function placeObject($bytes, $stream, $, swfVersion, tagCode) { michael@0: var flags, hasEvents, clip, hasName, hasRatio, hasCxform, hasMatrix, place; michael@0: var move, hasBackgroundColor, hasVisibility, hasImage, hasClassName, cache; michael@0: var blend, hasFilters, eoe; michael@0: $ || ($ = {}); michael@0: if (tagCode > 4) { michael@0: if (tagCode > 26) { michael@0: flags = readUi16($bytes, $stream); michael@0: } else { michael@0: flags = readUi8($bytes, $stream); michael@0: } michael@0: hasEvents = $.hasEvents = flags >> 7 & 1; michael@0: clip = $.clip = flags >> 6 & 1; michael@0: hasName = $.hasName = flags >> 5 & 1; michael@0: hasRatio = $.hasRatio = flags >> 4 & 1; michael@0: hasCxform = $.hasCxform = flags >> 3 & 1; michael@0: hasMatrix = $.hasMatrix = flags >> 2 & 1; michael@0: place = $.place = flags >> 1 & 1; michael@0: move = $.move = flags & 1; michael@0: if (tagCode === 70) { michael@0: hasBackgroundColor = $.hasBackgroundColor = flags >> 15 & 1; michael@0: hasVisibility = $.hasVisibility = flags >> 14 & 1; michael@0: hasImage = $.hasImage = flags >> 12 & 1; michael@0: hasClassName = $.hasClassName = flags >> 11 & 1; michael@0: cache = $.cache = flags >> 10 & 1; michael@0: blend = $.blend = flags >> 9 & 1; michael@0: hasFilters = $.hasFilters = flags >> 8 & 1; michael@0: } else { michael@0: cache = $.cache = 0; michael@0: blend = $.blend = 0; michael@0: hasFilters = $.hasFilters = 0; michael@0: } michael@0: $.depth = readUi16($bytes, $stream); michael@0: if (hasClassName) { michael@0: $.className = readString($bytes, $stream, 0); michael@0: } michael@0: if (place) { michael@0: $.symbolId = readUi16($bytes, $stream); michael@0: } michael@0: if (hasMatrix) { michael@0: var $0 = $.matrix = {}; michael@0: matrix($bytes, $stream, $0, swfVersion, tagCode); michael@0: } michael@0: if (hasCxform) { michael@0: var $1 = $.cxform = {}; michael@0: cxform($bytes, $stream, $1, swfVersion, tagCode); michael@0: } michael@0: if (hasRatio) { michael@0: $.ratio = readUi16($bytes, $stream); michael@0: } michael@0: if (hasName) { michael@0: $.name = readString($bytes, $stream, 0); michael@0: } michael@0: if (clip) { michael@0: $.clipDepth = readUi16($bytes, $stream); michael@0: } michael@0: if (hasFilters) { michael@0: var count = readUi8($bytes, $stream); michael@0: var $2 = $.filters = []; michael@0: var $3 = count; michael@0: while ($3--) { michael@0: var $4 = {}; michael@0: anyFilter($bytes, $stream, $4, swfVersion, tagCode); michael@0: $2.push($4); michael@0: } michael@0: } michael@0: if (blend) { michael@0: $.blendMode = readUi8($bytes, $stream); michael@0: } michael@0: if (cache) { michael@0: $.bmpCache = readUi8($bytes, $stream); michael@0: } michael@0: if (hasEvents) { michael@0: var reserved = readUi16($bytes, $stream); michael@0: if (swfVersion >= 6) { michael@0: var allFlags = readUi32($bytes, $stream); michael@0: } else { michael@0: var allFlags = readUi16($bytes, $stream); michael@0: } michael@0: var $28 = $.events = []; michael@0: do { michael@0: var $29 = {}; michael@0: var temp = events($bytes, $stream, $29, swfVersion, tagCode); michael@0: eoe = temp.eoe; michael@0: $28.push($29); michael@0: } while (!eoe); michael@0: } michael@0: if (hasBackgroundColor) { michael@0: var $126 = $.backgroundColor = {}; michael@0: argb($bytes, $stream, $126, swfVersion, tagCode); michael@0: } michael@0: if (hasVisibility) { michael@0: $.visibility = readUi8($bytes, $stream); michael@0: } michael@0: } else { michael@0: $.place = 1; michael@0: $.symbolId = readUi16($bytes, $stream); michael@0: $.depth = readUi16($bytes, $stream); michael@0: $.hasMatrix = 1; michael@0: var $30 = $.matrix = {}; michael@0: matrix($bytes, $stream, $30, swfVersion, tagCode); michael@0: if ($stream.remaining()) { michael@0: $.hasCxform = 1; michael@0: var $31 = $.cxform = {}; michael@0: cxform($bytes, $stream, $31, swfVersion, tagCode); michael@0: } michael@0: } michael@0: return $; michael@0: } michael@0: function removeObject($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: if (tagCode === 5) { michael@0: $.symbolId = readUi16($bytes, $stream); michael@0: } michael@0: $.depth = readUi16($bytes, $stream); michael@0: return $; michael@0: } michael@0: function defineImage($bytes, $stream, $, swfVersion, tagCode) { michael@0: var imgData; michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: if (tagCode > 21) { michael@0: var alphaDataOffset = readUi32($bytes, $stream); michael@0: if (tagCode === 90) { michael@0: $.deblock = readFixed8($bytes, $stream); michael@0: } michael@0: imgData = $.imgData = readBinary($bytes, $stream, alphaDataOffset); michael@0: $.alphaData = readBinary($bytes, $stream, 0); michael@0: } else { michael@0: imgData = $.imgData = readBinary($bytes, $stream, 0); michael@0: } michael@0: switch (imgData[0] << 8 | imgData[1]) { michael@0: case 65496: michael@0: case 65497: michael@0: $.mimeType = 'image/jpeg'; michael@0: break; michael@0: case 35152: michael@0: $.mimeType = 'image/png'; michael@0: break; michael@0: case 18249: michael@0: $.mimeType = 'image/gif'; michael@0: break; michael@0: default: michael@0: $.mimeType = 'application/octet-stream'; michael@0: } michael@0: if (tagCode === 6) { michael@0: $.incomplete = 1; michael@0: } michael@0: return $; michael@0: } michael@0: function defineButton($bytes, $stream, $, swfVersion, tagCode) { michael@0: var eob, hasFilters, count, blend; michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: if (tagCode == 7) { michael@0: var $0 = $.characters = []; michael@0: do { michael@0: var $1 = {}; michael@0: var temp = button($bytes, $stream, $1, swfVersion, tagCode); michael@0: eob = temp.eob; michael@0: $0.push($1); michael@0: } while (!eob); michael@0: $.actionsData = readBinary($bytes, $stream, 0); michael@0: } else { michael@0: var trackFlags = readUi8($bytes, $stream); michael@0: $.trackAsMenu = trackFlags >> 7 & 1; michael@0: var actionOffset = readUi16($bytes, $stream); michael@0: var $28 = $.characters = []; michael@0: do { michael@0: var $29 = {}; michael@0: var flags = readUi8($bytes, $stream); michael@0: var eob = $29.eob = !flags; michael@0: if (swfVersion >= 8) { michael@0: blend = $29.blend = flags >> 5 & 1; michael@0: hasFilters = $29.hasFilters = flags >> 4 & 1; michael@0: } else { michael@0: blend = $29.blend = 0; michael@0: hasFilters = $29.hasFilters = 0; michael@0: } michael@0: $29.stateHitTest = flags >> 3 & 1; michael@0: $29.stateDown = flags >> 2 & 1; michael@0: $29.stateOver = flags >> 1 & 1; michael@0: $29.stateUp = flags & 1; michael@0: if (!eob) { michael@0: $29.symbolId = readUi16($bytes, $stream); michael@0: $29.depth = readUi16($bytes, $stream); michael@0: var $30 = $29.matrix = {}; michael@0: matrix($bytes, $stream, $30, swfVersion, tagCode); michael@0: if (tagCode === 34) { michael@0: var $31 = $29.cxform = {}; michael@0: cxform($bytes, $stream, $31, swfVersion, tagCode); michael@0: } michael@0: if (hasFilters) { michael@0: var count = readUi8($bytes, $stream); michael@0: var $2 = $.filters = []; michael@0: var $3 = count; michael@0: while ($3--) { michael@0: var $4 = {}; michael@0: anyFilter($bytes, $stream, $4, swfVersion, tagCode); michael@0: $2.push($4); michael@0: } michael@0: } michael@0: if (blend) { michael@0: $29.blendMode = readUi8($bytes, $stream); michael@0: } michael@0: } michael@0: $28.push($29); michael@0: } while (!eob); michael@0: if (!(!actionOffset)) { michael@0: var $56 = $.buttonActions = []; michael@0: do { michael@0: var $57 = {}; michael@0: buttonCondAction($bytes, $stream, $57, swfVersion, tagCode); michael@0: $56.push($57); michael@0: } while ($stream.remaining() > 0); michael@0: } michael@0: } michael@0: return $; michael@0: } michael@0: function defineJPEGTables($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = 0; michael@0: $.imgData = readBinary($bytes, $stream, 0); michael@0: $.mimeType = 'application/octet-stream'; michael@0: return $; michael@0: } michael@0: function setBackgroundColor($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var $0 = $.color = {}; michael@0: rgb($bytes, $stream, $0, swfVersion, tagCode); michael@0: return $; michael@0: } michael@0: function defineBinaryData($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var reserved = readUi32($bytes, $stream); michael@0: $.data = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function defineFont($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var firstOffset = readUi16($bytes, $stream); michael@0: var glyphCount = $.glyphCount = firstOffset / 2; michael@0: var restOffsets = []; michael@0: var $0 = glyphCount - 1; michael@0: while ($0--) { michael@0: restOffsets.push(readUi16($bytes, $stream)); michael@0: } michael@0: $.offsets = [ michael@0: firstOffset michael@0: ].concat(restOffsets); michael@0: var $1 = $.glyphs = []; michael@0: var $2 = glyphCount; michael@0: while ($2--) { michael@0: var $3 = {}; michael@0: shape($bytes, $stream, $3, swfVersion, tagCode); michael@0: $1.push($3); michael@0: } michael@0: return $; michael@0: } michael@0: function defineLabel($bytes, $stream, $, swfVersion, tagCode) { michael@0: var eot; michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var $0 = $.bbox = {}; michael@0: bbox($bytes, $stream, $0, swfVersion, tagCode); michael@0: var $1 = $.matrix = {}; michael@0: matrix($bytes, $stream, $1, swfVersion, tagCode); michael@0: var glyphBits = $.glyphBits = readUi8($bytes, $stream); michael@0: var advanceBits = $.advanceBits = readUi8($bytes, $stream); michael@0: var $2 = $.records = []; michael@0: do { michael@0: var $3 = {}; michael@0: var temp = textRecord($bytes, $stream, $3, swfVersion, tagCode, glyphBits, advanceBits); michael@0: eot = temp.eot; michael@0: $2.push($3); michael@0: } while (!eot); michael@0: return $; michael@0: } michael@0: function doAction($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: if (tagCode === 59) { michael@0: $.spriteId = readUi16($bytes, $stream); michael@0: } michael@0: $.actionsData = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function defineSound($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var soundFlags = readUi8($bytes, $stream); michael@0: $.soundFormat = soundFlags >> 4 & 15; michael@0: $.soundRate = soundFlags >> 2 & 3; michael@0: $.soundSize = soundFlags >> 1 & 1; michael@0: $.soundType = soundFlags & 1; michael@0: $.samplesCount = readUi32($bytes, $stream); michael@0: $.soundData = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function startSound($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: if (tagCode == 15) { michael@0: $.soundId = readUi16($bytes, $stream); michael@0: } michael@0: if (tagCode == 89) { michael@0: $.soundClassName = readString($bytes, $stream, 0); michael@0: } michael@0: var $0 = $.soundInfo = {}; michael@0: soundInfo($bytes, $stream, $0, swfVersion, tagCode); michael@0: return $; michael@0: } michael@0: function soundStreamHead($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var playbackFlags = readUi8($bytes, $stream); michael@0: $.playbackRate = playbackFlags >> 2 & 3; michael@0: $.playbackSize = playbackFlags >> 1 & 1; michael@0: $.playbackType = playbackFlags & 1; michael@0: var streamFlags = readUi8($bytes, $stream); michael@0: var streamCompression = $.streamCompression = streamFlags >> 4 & 15; michael@0: $.streamRate = streamFlags >> 2 & 3; michael@0: $.streamSize = streamFlags >> 1 & 1; michael@0: $.streamType = streamFlags & 1; michael@0: $.samplesCount = readUi32($bytes, $stream); michael@0: if (streamCompression == 2) { michael@0: $.latencySeek = readSi16($bytes, $stream); michael@0: } michael@0: return $; michael@0: } michael@0: function soundStreamBlock($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.data = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function defineBitmap($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var format = $.format = readUi8($bytes, $stream); michael@0: $.width = readUi16($bytes, $stream); michael@0: $.height = readUi16($bytes, $stream); michael@0: $.hasAlpha = tagCode === 36; michael@0: if (format === 3) { michael@0: $.colorTableSize = readUi8($bytes, $stream); michael@0: } michael@0: $.bmpData = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function defineText($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var $0 = $.bbox = {}; michael@0: bbox($bytes, $stream, $0, swfVersion, tagCode); michael@0: var flags = readUi16($bytes, $stream); michael@0: var hasText = $.hasText = flags >> 7 & 1; michael@0: $.wordWrap = flags >> 6 & 1; michael@0: $.multiline = flags >> 5 & 1; michael@0: $.password = flags >> 4 & 1; michael@0: $.readonly = flags >> 3 & 1; michael@0: var hasColor = $.hasColor = flags >> 2 & 1; michael@0: var hasMaxLength = $.hasMaxLength = flags >> 1 & 1; michael@0: var hasFont = $.hasFont = flags & 1; michael@0: var hasFontClass = $.hasFontClass = flags >> 15 & 1; michael@0: $.autoSize = flags >> 14 & 1; michael@0: var hasLayout = $.hasLayout = flags >> 13 & 1; michael@0: $.noSelect = flags >> 12 & 1; michael@0: $.border = flags >> 11 & 1; michael@0: $.wasStatic = flags >> 10 & 1; michael@0: $.html = flags >> 9 & 1; michael@0: $.useOutlines = flags >> 8 & 1; michael@0: if (hasFont) { michael@0: $.fontId = readUi16($bytes, $stream); michael@0: } michael@0: if (hasFontClass) { michael@0: $.fontClass = readString($bytes, $stream, 0); michael@0: } michael@0: if (hasFont) { michael@0: $.fontHeight = readUi16($bytes, $stream); michael@0: } michael@0: if (hasColor) { michael@0: var $1 = $.color = {}; michael@0: rgba($bytes, $stream, $1, swfVersion, tagCode); michael@0: } michael@0: if (hasMaxLength) { michael@0: $.maxLength = readUi16($bytes, $stream); michael@0: } michael@0: if (hasLayout) { michael@0: $.align = readUi8($bytes, $stream); michael@0: $.leftMargin = readUi16($bytes, $stream); michael@0: $.rightMargin = readUi16($bytes, $stream); michael@0: $.indent = readSi16($bytes, $stream); michael@0: $.leading = readSi16($bytes, $stream); michael@0: } michael@0: $.variableName = readString($bytes, $stream, 0); michael@0: if (hasText) { michael@0: $.initialText = readString($bytes, $stream, 0); michael@0: } michael@0: return $; michael@0: } michael@0: function frameLabel($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.name = readString($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function defineFont2($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.id = readUi16($bytes, $stream); michael@0: var hasLayout = $.hasLayout = readUb($bytes, $stream, 1); michael@0: if (swfVersion > 5) { michael@0: $.shiftJis = readUb($bytes, $stream, 1); michael@0: } else { michael@0: var reserved = readUb($bytes, $stream, 1); michael@0: } michael@0: $.smallText = readUb($bytes, $stream, 1); michael@0: $.ansi = readUb($bytes, $stream, 1); michael@0: var wideOffset = $.wideOffset = readUb($bytes, $stream, 1); michael@0: var wide = $.wide = readUb($bytes, $stream, 1); michael@0: $.italic = readUb($bytes, $stream, 1); michael@0: $.bold = readUb($bytes, $stream, 1); michael@0: if (swfVersion > 5) { michael@0: $.language = readUi8($bytes, $stream); michael@0: } else { michael@0: var reserved = readUi8($bytes, $stream); michael@0: $.language = 0; michael@0: } michael@0: var nameLength = readUi8($bytes, $stream); michael@0: $.name = readString($bytes, $stream, nameLength); michael@0: if (tagCode === 75) { michael@0: $.resolution = 20; michael@0: } michael@0: var glyphCount = $.glyphCount = readUi16($bytes, $stream); michael@0: if (wideOffset) { michael@0: var $0 = $.offsets = []; michael@0: var $1 = glyphCount; michael@0: while ($1--) { michael@0: $0.push(readUi32($bytes, $stream)); michael@0: } michael@0: $.mapOffset = readUi32($bytes, $stream); michael@0: } else { michael@0: var $2 = $.offsets = []; michael@0: var $3 = glyphCount; michael@0: while ($3--) { michael@0: $2.push(readUi16($bytes, $stream)); michael@0: } michael@0: $.mapOffset = readUi16($bytes, $stream); michael@0: } michael@0: var $4 = $.glyphs = []; michael@0: var $5 = glyphCount; michael@0: while ($5--) { michael@0: var $6 = {}; michael@0: shape($bytes, $stream, $6, swfVersion, tagCode); michael@0: $4.push($6); michael@0: } michael@0: if (wide) { michael@0: var $47 = $.codes = []; michael@0: var $48 = glyphCount; michael@0: while ($48--) { michael@0: $47.push(readUi16($bytes, $stream)); michael@0: } michael@0: } else { michael@0: var $49 = $.codes = []; michael@0: var $50 = glyphCount; michael@0: while ($50--) { michael@0: $49.push(readUi8($bytes, $stream)); michael@0: } michael@0: } michael@0: if (hasLayout) { michael@0: $.ascent = readUi16($bytes, $stream); michael@0: $.descent = readUi16($bytes, $stream); michael@0: $.leading = readSi16($bytes, $stream); michael@0: var $51 = $.advance = []; michael@0: var $52 = glyphCount; michael@0: while ($52--) { michael@0: $51.push(readSi16($bytes, $stream)); michael@0: } michael@0: var $53 = $.bbox = []; michael@0: var $54 = glyphCount; michael@0: while ($54--) { michael@0: var $55 = {}; michael@0: bbox($bytes, $stream, $55, swfVersion, tagCode); michael@0: $53.push($55); michael@0: } michael@0: var kerningCount = readUi16($bytes, $stream); michael@0: var $56 = $.kerning = []; michael@0: var $57 = kerningCount; michael@0: while ($57--) { michael@0: var $58 = {}; michael@0: kerning($bytes, $stream, $58, swfVersion, tagCode, wide); michael@0: $56.push($58); michael@0: } michael@0: } michael@0: return $; michael@0: } michael@0: function fileAttributes($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var reserved = readUb($bytes, $stream, 1); michael@0: $.useDirectBlit = readUb($bytes, $stream, 1); michael@0: $.useGpu = readUb($bytes, $stream, 1); michael@0: $.hasMetadata = readUb($bytes, $stream, 1); michael@0: $.doAbc = readUb($bytes, $stream, 1); michael@0: $.noCrossDomainCaching = readUb($bytes, $stream, 1); michael@0: $.relativeUrls = readUb($bytes, $stream, 1); michael@0: $.network = readUb($bytes, $stream, 1); michael@0: var pad = readUb($bytes, $stream, 24); michael@0: return $; michael@0: } michael@0: function doABC($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: if (tagCode === 82) { michael@0: $.flags = readUi32($bytes, $stream); michael@0: } else { michael@0: $.flags = 0; michael@0: } michael@0: if (tagCode === 82) { michael@0: $.name = readString($bytes, $stream, 0); michael@0: } else { michael@0: $.name = ''; michael@0: } michael@0: $.data = readBinary($bytes, $stream, 0); michael@0: return $; michael@0: } michael@0: function exportAssets($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var exportsCount = readUi16($bytes, $stream); michael@0: var $0 = $.exports = []; michael@0: var $1 = exportsCount; michael@0: while ($1--) { michael@0: var $2 = {}; michael@0: $2.symbolId = readUi16($bytes, $stream); michael@0: $2.className = readString($bytes, $stream, 0); michael@0: $0.push($2); michael@0: } michael@0: return $; michael@0: } michael@0: function symbolClass($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var symbolCount = readUi16($bytes, $stream); michael@0: var $0 = $.exports = []; michael@0: var $1 = symbolCount; michael@0: while ($1--) { michael@0: var $2 = {}; michael@0: $2.symbolId = readUi16($bytes, $stream); michael@0: $2.className = readString($bytes, $stream, 0); michael@0: $0.push($2); michael@0: } michael@0: return $; michael@0: } michael@0: function defineScalingGrid($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: $.symbolId = readUi16($bytes, $stream); michael@0: var $0 = $.splitter = {}; michael@0: bbox($bytes, $stream, $0, swfVersion, tagCode); michael@0: return $; michael@0: } michael@0: function defineScene($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var sceneCount = readEncodedU32($bytes, $stream); michael@0: var $0 = $.scenes = []; michael@0: var $1 = sceneCount; michael@0: while ($1--) { michael@0: var $2 = {}; michael@0: $2.offset = readEncodedU32($bytes, $stream); michael@0: $2.name = readString($bytes, $stream, 0); michael@0: $0.push($2); michael@0: } michael@0: var labelCount = readEncodedU32($bytes, $stream); michael@0: var $3 = $.labels = []; michael@0: var $4 = labelCount; michael@0: while ($4--) { michael@0: var $5 = {}; michael@0: $5.frame = readEncodedU32($bytes, $stream); michael@0: $5.name = readString($bytes, $stream, 0); michael@0: $3.push($5); michael@0: } michael@0: return $; michael@0: } michael@0: function bbox($bytes, $stream, $, swfVersion, tagCode) { michael@0: align($bytes, $stream); michael@0: var bits = readUb($bytes, $stream, 5); michael@0: var xMin = readSb($bytes, $stream, bits); michael@0: var xMax = readSb($bytes, $stream, bits); michael@0: var yMin = readSb($bytes, $stream, bits); michael@0: var yMax = readSb($bytes, $stream, bits); michael@0: $.xMin = xMin; michael@0: $.xMax = xMax; michael@0: $.yMin = yMin; michael@0: $.yMax = yMax; michael@0: align($bytes, $stream); michael@0: } michael@0: function rgb($bytes, $stream, $, swfVersion, tagCode) { michael@0: $.red = readUi8($bytes, $stream); michael@0: $.green = readUi8($bytes, $stream); michael@0: $.blue = readUi8($bytes, $stream); michael@0: $.alpha = 255; michael@0: return; michael@0: } michael@0: function rgba($bytes, $stream, $, swfVersion, tagCode) { michael@0: $.red = readUi8($bytes, $stream); michael@0: $.green = readUi8($bytes, $stream); michael@0: $.blue = readUi8($bytes, $stream); michael@0: $.alpha = readUi8($bytes, $stream); michael@0: return; michael@0: } michael@0: function argb($bytes, $stream, $, swfVersion, tagCode) { michael@0: $.alpha = readUi8($bytes, $stream); michael@0: $.red = readUi8($bytes, $stream); michael@0: $.green = readUi8($bytes, $stream); michael@0: $.blue = readUi8($bytes, $stream); michael@0: } michael@0: function fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph) { michael@0: if (tagCode > 22 || isMorph) { michael@0: var $125 = $.color = {}; michael@0: rgba($bytes, $stream, $125, swfVersion, tagCode); michael@0: } else { michael@0: var $126 = $.color = {}; michael@0: rgb($bytes, $stream, $126, swfVersion, tagCode); michael@0: } michael@0: if (isMorph) { michael@0: var $127 = $.colorMorph = {}; michael@0: rgba($bytes, $stream, $127, swfVersion, tagCode); michael@0: } michael@0: return; michael@0: } michael@0: function matrix($bytes, $stream, $, swfVersion, tagCode) { michael@0: align($bytes, $stream); michael@0: var hasScale = readUb($bytes, $stream, 1); michael@0: if (hasScale) { michael@0: var bits = readUb($bytes, $stream, 5); michael@0: $.a = readFb($bytes, $stream, bits); michael@0: $.d = readFb($bytes, $stream, bits); michael@0: } else { michael@0: $.a = 1; michael@0: $.d = 1; michael@0: } michael@0: var hasRotate = readUb($bytes, $stream, 1); michael@0: if (hasRotate) { michael@0: var bits = readUb($bytes, $stream, 5); michael@0: $.b = readFb($bytes, $stream, bits); michael@0: $.c = readFb($bytes, $stream, bits); michael@0: } else { michael@0: $.b = 0; michael@0: $.c = 0; michael@0: } michael@0: var bits = readUb($bytes, $stream, 5); michael@0: var e = readSb($bytes, $stream, bits); michael@0: var f = readSb($bytes, $stream, bits); michael@0: $.tx = e; michael@0: $.ty = f; michael@0: align($bytes, $stream); michael@0: } michael@0: function cxform($bytes, $stream, $, swfVersion, tagCode) { michael@0: align($bytes, $stream); michael@0: var hasOffsets = readUb($bytes, $stream, 1); michael@0: var hasMultipliers = readUb($bytes, $stream, 1); michael@0: var bits = readUb($bytes, $stream, 4); michael@0: if (hasMultipliers) { michael@0: $.redMultiplier = readSb($bytes, $stream, bits); michael@0: $.greenMultiplier = readSb($bytes, $stream, bits); michael@0: $.blueMultiplier = readSb($bytes, $stream, bits); michael@0: if (tagCode > 4) { michael@0: $.alphaMultiplier = readSb($bytes, $stream, bits); michael@0: } else { michael@0: $.alphaMultiplier = 256; michael@0: } michael@0: } else { michael@0: $.redMultiplier = 256; michael@0: $.greenMultiplier = 256; michael@0: $.blueMultiplier = 256; michael@0: $.alphaMultiplier = 256; michael@0: } michael@0: if (hasOffsets) { michael@0: $.redOffset = readSb($bytes, $stream, bits); michael@0: $.greenOffset = readSb($bytes, $stream, bits); michael@0: $.blueOffset = readSb($bytes, $stream, bits); michael@0: if (tagCode > 4) { michael@0: $.alphaOffset = readSb($bytes, $stream, bits); michael@0: } else { michael@0: $.alphaOffset = 0; michael@0: } michael@0: } else { michael@0: $.redOffset = 0; michael@0: $.greenOffset = 0; michael@0: $.blueOffset = 0; michael@0: $.alphaOffset = 0; michael@0: } michael@0: align($bytes, $stream); michael@0: } michael@0: function fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) { michael@0: var $128 = $.matrix = {}; michael@0: matrix($bytes, $stream, $128, swfVersion, tagCode); michael@0: if (isMorph) { michael@0: var $129 = $.matrixMorph = {}; michael@0: matrix($bytes, $stream, $129, swfVersion, tagCode); michael@0: } michael@0: gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type); michael@0: } michael@0: function gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) { michael@0: if (tagCode === 83) { michael@0: $.spreadMode = readUb($bytes, $stream, 2); michael@0: $.interpolationMode = readUb($bytes, $stream, 2); michael@0: } else { michael@0: var pad = readUb($bytes, $stream, 4); michael@0: } michael@0: var count = $.count = readUb($bytes, $stream, 4); michael@0: var $130 = $.records = []; michael@0: var $131 = count; michael@0: while ($131--) { michael@0: var $132 = {}; michael@0: gradientRecord($bytes, $stream, $132, swfVersion, tagCode, isMorph); michael@0: $130.push($132); michael@0: } michael@0: if (type === 19) { michael@0: $.focalPoint = readFixed8($bytes, $stream); michael@0: if (isMorph) { michael@0: $.focalPointMorph = readFixed8($bytes, $stream); michael@0: } michael@0: } michael@0: } michael@0: function gradientRecord($bytes, $stream, $, swfVersion, tagCode, isMorph) { michael@0: $.ratio = readUi8($bytes, $stream); michael@0: if (tagCode > 22) { michael@0: var $133 = $.color = {}; michael@0: rgba($bytes, $stream, $133, swfVersion, tagCode); michael@0: } else { michael@0: var $134 = $.color = {}; michael@0: rgb($bytes, $stream, $134, swfVersion, tagCode); michael@0: } michael@0: if (isMorph) { michael@0: $.ratioMorph = readUi8($bytes, $stream); michael@0: var $135 = $.colorMorph = {}; michael@0: rgba($bytes, $stream, $135, swfVersion, tagCode); michael@0: } michael@0: } michael@0: function morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) { michael@0: var eos, bits; michael@0: var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: var lineBits = temp.lineBits; michael@0: var fillBits = temp.fillBits; michael@0: var $160 = $.records = []; michael@0: do { michael@0: var $161 = {}; michael@0: var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits); michael@0: var eos = temp.eos; michael@0: var flags = temp.flags; michael@0: var type = temp.type; michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var bits = temp.bits; michael@0: $160.push($161); michael@0: } while (!eos); michael@0: var temp = styleBits($bytes, $stream, $, swfVersion, tagCode); michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var $162 = $.recordsMorph = []; michael@0: do { michael@0: var $163 = {}; michael@0: var temp = shapeRecord($bytes, $stream, $163, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits); michael@0: eos = temp.eos; michael@0: var flags = temp.flags; michael@0: var type = temp.type; michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: bits = temp.bits; michael@0: $162.push($163); michael@0: } while (!eos); michael@0: } michael@0: function shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) { michael@0: var eos; michael@0: var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var $160 = $.records = []; michael@0: do { michael@0: var $161 = {}; michael@0: var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits); michael@0: eos = temp.eos; michael@0: var flags = temp.flags; michael@0: var type = temp.type; michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var bits = temp.bits; michael@0: $160.push($161); michael@0: } while (!eos); michael@0: } michael@0: function shapeRecord($bytes, $stream, $, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits) { michael@0: var type = $.type = readUb($bytes, $stream, 1); michael@0: var flags = readUb($bytes, $stream, 5); michael@0: var eos = $.eos = !(type || flags); michael@0: if (type) { michael@0: var temp = shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits); michael@0: var bits = temp.bits; michael@0: } else { michael@0: var temp = shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits); michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var bits = temp.bits; michael@0: } michael@0: return { michael@0: type: type, michael@0: flags: flags, michael@0: eos: eos, michael@0: fillBits: fillBits, michael@0: lineBits: lineBits, michael@0: bits: bits michael@0: }; michael@0: } michael@0: function shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits) { michael@0: var isStraight = 0, tmp = 0, bits = 0, isGeneral = 0, isVertical = 0; michael@0: isStraight = $.isStraight = flags >> 4; michael@0: tmp = flags & 15; michael@0: bits = tmp + 2; michael@0: if (isStraight) { michael@0: isGeneral = $.isGeneral = readUb($bytes, $stream, 1); michael@0: if (isGeneral) { michael@0: $.deltaX = readSb($bytes, $stream, bits); michael@0: $.deltaY = readSb($bytes, $stream, bits); michael@0: } else { michael@0: isVertical = $.isVertical = readUb($bytes, $stream, 1); michael@0: if (isVertical) { michael@0: $.deltaY = readSb($bytes, $stream, bits); michael@0: } else { michael@0: $.deltaX = readSb($bytes, $stream, bits); michael@0: } michael@0: } michael@0: } else { michael@0: $.controlDeltaX = readSb($bytes, $stream, bits); michael@0: $.controlDeltaY = readSb($bytes, $stream, bits); michael@0: $.anchorDeltaX = readSb($bytes, $stream, bits); michael@0: $.anchorDeltaY = readSb($bytes, $stream, bits); michael@0: } michael@0: return { michael@0: bits: bits michael@0: }; michael@0: } michael@0: function shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits) { michael@0: var hasNewStyles = 0, hasLineStyle = 0, hasFillStyle1 = 0; michael@0: var hasFillStyle0 = 0, move = 0; michael@0: if (tagCode > 2) { michael@0: hasNewStyles = $.hasNewStyles = flags >> 4; michael@0: } else { michael@0: hasNewStyles = $.hasNewStyles = 0; michael@0: } michael@0: hasLineStyle = $.hasLineStyle = flags >> 3 & 1; michael@0: hasFillStyle1 = $.hasFillStyle1 = flags >> 2 & 1; michael@0: hasFillStyle0 = $.hasFillStyle0 = flags >> 1 & 1; michael@0: move = $.move = flags & 1; michael@0: if (move) { michael@0: bits = readUb($bytes, $stream, 5); michael@0: $.moveX = readSb($bytes, $stream, bits); michael@0: $.moveY = readSb($bytes, $stream, bits); michael@0: } michael@0: if (hasFillStyle0) { michael@0: $.fillStyle0 = readUb($bytes, $stream, fillBits); michael@0: } michael@0: if (hasFillStyle1) { michael@0: $.fillStyle1 = readUb($bytes, $stream, fillBits); michael@0: } michael@0: if (hasLineStyle) { michael@0: $.lineStyle = readUb($bytes, $stream, lineBits); michael@0: } michael@0: if (hasNewStyles) { michael@0: var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: var lineBits = temp.lineBits; michael@0: var fillBits = temp.fillBits; michael@0: } michael@0: return { michael@0: lineBits: lineBits, michael@0: fillBits: fillBits, michael@0: bits: bits michael@0: }; michael@0: } michael@0: function styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) { michael@0: fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph); michael@0: lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes); michael@0: var temp = styleBits($bytes, $stream, $, swfVersion, tagCode); michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: return { michael@0: fillBits: fillBits, michael@0: lineBits: lineBits michael@0: }; michael@0: } michael@0: function fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph) { michael@0: var count; michael@0: var tmp = readUi8($bytes, $stream); michael@0: if (tagCode > 2 && tmp === 255) { michael@0: count = readUi16($bytes, $stream); michael@0: } else { michael@0: count = tmp; michael@0: } michael@0: var $4 = $.fillStyles = []; michael@0: var $5 = count; michael@0: while ($5--) { michael@0: var $6 = {}; michael@0: fillStyle($bytes, $stream, $6, swfVersion, tagCode, isMorph); michael@0: $4.push($6); michael@0: } michael@0: } michael@0: function lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) { michael@0: var count; michael@0: var tmp = readUi8($bytes, $stream); michael@0: if (tagCode > 2 && tmp === 255) { michael@0: count = readUi16($bytes, $stream); michael@0: } else { michael@0: count = tmp; michael@0: } michael@0: var $138 = $.lineStyles = []; michael@0: var $139 = count; michael@0: while ($139--) { michael@0: var $140 = {}; michael@0: lineStyle($bytes, $stream, $140, swfVersion, tagCode, isMorph, hasStrokes); michael@0: $138.push($140); michael@0: } michael@0: } michael@0: function styleBits($bytes, $stream, $, swfVersion, tagCode) { michael@0: align($bytes, $stream); michael@0: var fillBits = readUb($bytes, $stream, 4); michael@0: var lineBits = readUb($bytes, $stream, 4); michael@0: return { michael@0: fillBits: fillBits, michael@0: lineBits: lineBits michael@0: }; michael@0: } michael@0: function fillStyle($bytes, $stream, $, swfVersion, tagCode, isMorph) { michael@0: var type = $.type = readUi8($bytes, $stream); michael@0: switch (type) { michael@0: case 0: michael@0: fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph); michael@0: break; michael@0: case 16: michael@0: case 18: michael@0: case 19: michael@0: fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type); michael@0: break; michael@0: case 64: michael@0: case 65: michael@0: case 66: michael@0: case 67: michael@0: fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type); michael@0: break; michael@0: default: michael@0: } michael@0: } michael@0: function lineStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) { michael@0: $.width = readUi16($bytes, $stream); michael@0: if (isMorph) { michael@0: $.widthMorph = readUi16($bytes, $stream); michael@0: } michael@0: if (hasStrokes) { michael@0: align($bytes, $stream); michael@0: $.startCapStyle = readUb($bytes, $stream, 2); michael@0: var joinStyle = $.joinStyle = readUb($bytes, $stream, 2); michael@0: var hasFill = $.hasFill = readUb($bytes, $stream, 1); michael@0: $.noHscale = readUb($bytes, $stream, 1); michael@0: $.noVscale = readUb($bytes, $stream, 1); michael@0: $.pixelHinting = readUb($bytes, $stream, 1); michael@0: var reserved = readUb($bytes, $stream, 5); michael@0: $.noClose = readUb($bytes, $stream, 1); michael@0: $.endCapStyle = readUb($bytes, $stream, 2); michael@0: if (joinStyle === 2) { michael@0: $.miterLimitFactor = readFixed8($bytes, $stream); michael@0: } michael@0: if (hasFill) { michael@0: var $141 = $.fillStyle = {}; michael@0: fillStyle($bytes, $stream, $141, swfVersion, tagCode, isMorph); michael@0: } else { michael@0: var $155 = $.color = {}; michael@0: rgba($bytes, $stream, $155, swfVersion, tagCode); michael@0: if (isMorph) { michael@0: var $156 = $.colorMorph = {}; michael@0: rgba($bytes, $stream, $156, swfVersion, tagCode); michael@0: } michael@0: } michael@0: } else { michael@0: if (tagCode > 22) { michael@0: var $157 = $.color = {}; michael@0: rgba($bytes, $stream, $157, swfVersion, tagCode); michael@0: } else { michael@0: var $158 = $.color = {}; michael@0: rgb($bytes, $stream, $158, swfVersion, tagCode); michael@0: } michael@0: if (isMorph) { michael@0: var $159 = $.colorMorph = {}; michael@0: rgba($bytes, $stream, $159, swfVersion, tagCode); michael@0: } michael@0: } michael@0: } michael@0: function fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type) { michael@0: $.bitmapId = readUi16($bytes, $stream); michael@0: var $18 = $.matrix = {}; michael@0: matrix($bytes, $stream, $18, swfVersion, tagCode); michael@0: if (isMorph) { michael@0: var $19 = $.matrixMorph = {}; michael@0: matrix($bytes, $stream, $19, swfVersion, tagCode); michael@0: } michael@0: $.condition = type === 64 || type === 67; michael@0: } michael@0: function filterGlow($bytes, $stream, $, swfVersion, tagCode, type) { michael@0: var count; michael@0: if (type === 4 || type === 7) { michael@0: count = readUi8($bytes, $stream); michael@0: } else { michael@0: count = 1; michael@0: } michael@0: var $5 = $.colors = []; michael@0: var $6 = count; michael@0: while ($6--) { michael@0: var $7 = {}; michael@0: rgba($bytes, $stream, $7, swfVersion, tagCode); michael@0: $5.push($7); michael@0: } michael@0: if (type === 3) { michael@0: var $8 = $.higlightColor = {}; michael@0: rgba($bytes, $stream, $8, swfVersion, tagCode); michael@0: } michael@0: if (type === 4 || type === 7) { michael@0: var $9 = $.ratios = []; michael@0: var $10 = count; michael@0: while ($10--) { michael@0: $9.push(readUi8($bytes, $stream)); michael@0: } michael@0: } michael@0: $.blurX = readFixed($bytes, $stream); michael@0: $.blurY = readFixed($bytes, $stream); michael@0: if (type !== 2) { michael@0: $.angle = readFixed($bytes, $stream); michael@0: $.distance = readFixed($bytes, $stream); michael@0: } michael@0: $.strength = readFixed8($bytes, $stream); michael@0: $.innerShadow = readUb($bytes, $stream, 1); michael@0: $.knockout = readUb($bytes, $stream, 1); michael@0: $.compositeSource = readUb($bytes, $stream, 1); michael@0: if (type === 3) { michael@0: $.onTop = readUb($bytes, $stream, 1); michael@0: } else { michael@0: var reserved = readUb($bytes, $stream, 1); michael@0: } michael@0: if (type === 4 || type === 7) { michael@0: $.passes = readUb($bytes, $stream, 4); michael@0: } else { michael@0: var reserved = readUb($bytes, $stream, 4); michael@0: } michael@0: } michael@0: function filterBlur($bytes, $stream, $, swfVersion, tagCode) { michael@0: $.blurX = readFixed($bytes, $stream); michael@0: $.blurY = readFixed($bytes, $stream); michael@0: $.passes = readUb($bytes, $stream, 5); michael@0: var reserved = readUb($bytes, $stream, 3); michael@0: } michael@0: function filterConvolution($bytes, $stream, $, swfVersion, tagCode) { michael@0: var columns = $.columns = readUi8($bytes, $stream); michael@0: var rows = $.rows = readUi8($bytes, $stream); michael@0: $.divisor = readFloat($bytes, $stream); michael@0: $.bias = readFloat($bytes, $stream); michael@0: var $17 = $.weights = []; michael@0: var $18 = columns * rows; michael@0: while ($18--) { michael@0: $17.push(readFloat($bytes, $stream)); michael@0: } michael@0: var $19 = $.defaultColor = {}; michael@0: rgba($bytes, $stream, $19, swfVersion, tagCode); michael@0: var reserved = readUb($bytes, $stream, 6); michael@0: $.clamp = readUb($bytes, $stream, 1); michael@0: $.preserveAlpha = readUb($bytes, $stream, 1); michael@0: } michael@0: function filterColorMatrix($bytes, $stream, $, swfVersion, tagCode) { michael@0: var $20 = $.matrix = []; michael@0: var $21 = 20; michael@0: while ($21--) { michael@0: $20.push(readFloat($bytes, $stream)); michael@0: } michael@0: } michael@0: function anyFilter($bytes, $stream, $, swfVersion, tagCode) { michael@0: var type = $.type = readUi8($bytes, $stream); michael@0: switch (type) { michael@0: case 0: michael@0: case 2: michael@0: case 3: michael@0: case 4: michael@0: case 7: michael@0: filterGlow($bytes, $stream, $, swfVersion, tagCode, type); michael@0: break; michael@0: case 1: michael@0: filterBlur($bytes, $stream, $, swfVersion, tagCode); michael@0: break; michael@0: case 5: michael@0: filterConvolution($bytes, $stream, $, swfVersion, tagCode); michael@0: break; michael@0: case 6: michael@0: filterColorMatrix($bytes, $stream, $, swfVersion, tagCode); michael@0: break; michael@0: default: michael@0: } michael@0: } michael@0: function events($bytes, $stream, $, swfVersion, tagCode) { michael@0: var flags, keyPress; michael@0: if (swfVersion >= 6) { michael@0: flags = readUi32($bytes, $stream); michael@0: } else { michael@0: flags = readUi16($bytes, $stream); michael@0: } michael@0: var eoe = $.eoe = !flags; michael@0: $.onKeyUp = flags >> 7 & 1; michael@0: $.onKeyDown = flags >> 6 & 1; michael@0: $.onMouseUp = flags >> 5 & 1; michael@0: $.onMouseDown = flags >> 4 & 1; michael@0: $.onMouseMove = flags >> 3 & 1; michael@0: $.onUnload = flags >> 2 & 1; michael@0: $.onEnterFrame = flags >> 1 & 1; michael@0: $.onLoad = flags & 1; michael@0: if (swfVersion >= 6) { michael@0: $.onDragOver = flags >> 15 & 1; michael@0: $.onRollOut = flags >> 14 & 1; michael@0: $.onRollOver = flags >> 13 & 1; michael@0: $.onReleaseOutside = flags >> 12 & 1; michael@0: $.onRelease = flags >> 11 & 1; michael@0: $.onPress = flags >> 10 & 1; michael@0: $.onInitialize = flags >> 9 & 1; michael@0: $.onData = flags >> 8 & 1; michael@0: if (swfVersion >= 7) { michael@0: $.onConstruct = flags >> 18 & 1; michael@0: } else { michael@0: $.onConstruct = 0; michael@0: } michael@0: keyPress = $.keyPress = flags >> 17 & 1; michael@0: $.onDragOut = flags >> 16 & 1; michael@0: } michael@0: if (!eoe) { michael@0: var length = $.length = readUi32($bytes, $stream); michael@0: if (keyPress) { michael@0: $.keyCode = readUi8($bytes, $stream); michael@0: } michael@0: $.actionsData = readBinary($bytes, $stream, length - (keyPress ? 1 : 0)); michael@0: } michael@0: return { michael@0: eoe: eoe michael@0: }; michael@0: } michael@0: function kerning($bytes, $stream, $, swfVersion, tagCode, wide) { michael@0: if (wide) { michael@0: $.code1 = readUi16($bytes, $stream); michael@0: $.code2 = readUi16($bytes, $stream); michael@0: } else { michael@0: $.code1 = readUi8($bytes, $stream); michael@0: $.code2 = readUi8($bytes, $stream); michael@0: } michael@0: $.adjustment = readUi16($bytes, $stream); michael@0: } michael@0: function textEntry($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) { michael@0: $.glyphIndex = readUb($bytes, $stream, glyphBits); michael@0: $.advance = readSb($bytes, $stream, advanceBits); michael@0: } michael@0: function textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags) { michael@0: var hasFont = $.hasFont = flags >> 3 & 1; michael@0: var hasColor = $.hasColor = flags >> 2 & 1; michael@0: var hasMoveY = $.hasMoveY = flags >> 1 & 1; michael@0: var hasMoveX = $.hasMoveX = flags & 1; michael@0: if (hasFont) { michael@0: $.fontId = readUi16($bytes, $stream); michael@0: } michael@0: if (hasColor) { michael@0: if (tagCode === 33) { michael@0: var $4 = $.color = {}; michael@0: rgba($bytes, $stream, $4, swfVersion, tagCode); michael@0: } else { michael@0: var $5 = $.color = {}; michael@0: rgb($bytes, $stream, $5, swfVersion, tagCode); michael@0: } michael@0: } michael@0: if (hasMoveX) { michael@0: $.moveX = readSi16($bytes, $stream); michael@0: } michael@0: if (hasMoveY) { michael@0: $.moveY = readSi16($bytes, $stream); michael@0: } michael@0: if (hasFont) { michael@0: $.fontHeight = readUi16($bytes, $stream); michael@0: } michael@0: } michael@0: function textRecord($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) { michael@0: var glyphCount; michael@0: align($bytes, $stream); michael@0: var flags = readUb($bytes, $stream, 8); michael@0: var eot = $.eot = !flags; michael@0: textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags); michael@0: if (!eot) { michael@0: var tmp = readUi8($bytes, $stream); michael@0: if (swfVersion > 6) { michael@0: glyphCount = $.glyphCount = tmp; michael@0: } else { michael@0: glyphCount = $.glyphCount = tmp & 127; michael@0: } michael@0: var $6 = $.entries = []; michael@0: var $7 = glyphCount; michael@0: while ($7--) { michael@0: var $8 = {}; michael@0: textEntry($bytes, $stream, $8, swfVersion, tagCode, glyphBits, advanceBits); michael@0: $6.push($8); michael@0: } michael@0: } michael@0: return { michael@0: eot: eot michael@0: }; michael@0: } michael@0: function soundEnvelope($bytes, $stream, $, swfVersion, tagCode) { michael@0: $.pos44 = readUi32($bytes, $stream); michael@0: $.volumeLeft = readUi16($bytes, $stream); michael@0: $.volumeRight = readUi16($bytes, $stream); michael@0: } michael@0: function soundInfo($bytes, $stream, $, swfVersion, tagCode) { michael@0: var reserved = readUb($bytes, $stream, 2); michael@0: $.stop = readUb($bytes, $stream, 1); michael@0: $.noMultiple = readUb($bytes, $stream, 1); michael@0: var hasEnvelope = $.hasEnvelope = readUb($bytes, $stream, 1); michael@0: var hasLoops = $.hasLoops = readUb($bytes, $stream, 1); michael@0: var hasOutPoint = $.hasOutPoint = readUb($bytes, $stream, 1); michael@0: var hasInPoint = $.hasInPoint = readUb($bytes, $stream, 1); michael@0: if (hasInPoint) { michael@0: $.inPoint = readUi32($bytes, $stream); michael@0: } michael@0: if (hasOutPoint) { michael@0: $.outPoint = readUi32($bytes, $stream); michael@0: } michael@0: if (hasLoops) { michael@0: $.loopCount = readUi16($bytes, $stream); michael@0: } michael@0: if (hasEnvelope) { michael@0: var envelopeCount = $.envelopeCount = readUi8($bytes, $stream); michael@0: var $1 = $.envelopes = []; michael@0: var $2 = envelopeCount; michael@0: while ($2--) { michael@0: var $3 = {}; michael@0: soundEnvelope($bytes, $stream, $3, swfVersion, tagCode); michael@0: $1.push($3); michael@0: } michael@0: } michael@0: } michael@0: function button($bytes, $stream, $, swfVersion, tagCode) { michael@0: var hasFilters, blend; michael@0: var flags = readUi8($bytes, $stream); michael@0: var eob = $.eob = !flags; michael@0: if (swfVersion >= 8) { michael@0: blend = $.blend = flags >> 5 & 1; michael@0: hasFilters = $.hasFilters = flags >> 4 & 1; michael@0: } else { michael@0: blend = $.blend = 0; michael@0: hasFilters = $.hasFilters = 0; michael@0: } michael@0: $.stateHitTest = flags >> 3 & 1; michael@0: $.stateDown = flags >> 2 & 1; michael@0: $.stateOver = flags >> 1 & 1; michael@0: $.stateUp = flags & 1; michael@0: if (!eob) { michael@0: $.symbolId = readUi16($bytes, $stream); michael@0: $.depth = readUi16($bytes, $stream); michael@0: var $2 = $.matrix = {}; michael@0: matrix($bytes, $stream, $2, swfVersion, tagCode); michael@0: if (tagCode === 34) { michael@0: var $3 = $.cxform = {}; michael@0: cxform($bytes, $stream, $3, swfVersion, tagCode); michael@0: } michael@0: if (hasFilters) { michael@0: $.filterCount = readUi8($bytes, $stream); michael@0: var $4 = $.filters = {}; michael@0: anyFilter($bytes, $stream, $4, swfVersion, tagCode); michael@0: } michael@0: if (blend) { michael@0: $.blendMode = readUi8($bytes, $stream); michael@0: } michael@0: } michael@0: return { michael@0: eob: eob michael@0: }; michael@0: } michael@0: function buttonCondAction($bytes, $stream, $, swfVersion, tagCode) { michael@0: var buttonCondSize = readUi16($bytes, $stream); michael@0: var buttonConditions = readUi16($bytes, $stream); michael@0: $.idleToOverDown = buttonConditions >> 7 & 1; michael@0: $.outDownToIdle = buttonConditions >> 6 & 1; michael@0: $.outDownToOverDown = buttonConditions >> 5 & 1; michael@0: $.overDownToOutDown = buttonConditions >> 4 & 1; michael@0: $.overDownToOverUp = buttonConditions >> 3 & 1; michael@0: $.overUpToOverDown = buttonConditions >> 2 & 1; michael@0: $.overUpToIdle = buttonConditions >> 1 & 1; michael@0: $.idleToOverUp = buttonConditions & 1; michael@0: $.mouseEventFlags = buttonConditions & 511; michael@0: $.keyPress = buttonConditions >> 9 & 127; michael@0: $.overDownToIdle = buttonConditions >> 8 & 1; michael@0: if (!buttonCondSize) { michael@0: $.actionsData = readBinary($bytes, $stream, 0); michael@0: } else { michael@0: $.actionsData = readBinary($bytes, $stream, buttonCondSize - 4); michael@0: } michael@0: } michael@0: function shape($bytes, $stream, $, swfVersion, tagCode) { michael@0: var eos; michael@0: var temp = styleBits($bytes, $stream, $, swfVersion, tagCode); michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var $4 = $.records = []; michael@0: do { michael@0: var $5 = {}; michael@0: var isMorph = false; michael@0: var hasStrokes = false; michael@0: var temp = shapeRecord($bytes, $stream, $5, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits); michael@0: eos = temp.eos; michael@0: var fillBits = temp.fillBits; michael@0: var lineBits = temp.lineBits; michael@0: var bits = bits; michael@0: $4.push($5); michael@0: } while (!eos); michael@0: } michael@0: return { michael@0: 0: undefined, michael@0: 1: undefined, michael@0: 2: defineShape, michael@0: 4: placeObject, michael@0: 5: removeObject, michael@0: 6: defineImage, michael@0: 7: defineButton, michael@0: 8: defineJPEGTables, michael@0: 9: setBackgroundColor, michael@0: 10: defineFont, michael@0: 11: defineLabel, michael@0: 12: doAction, michael@0: 13: undefined, michael@0: 14: defineSound, michael@0: 15: startSound, michael@0: 17: undefined, michael@0: 18: soundStreamHead, michael@0: 19: soundStreamBlock, michael@0: 20: defineBitmap, michael@0: 21: defineImage, michael@0: 22: defineShape, michael@0: 23: undefined, michael@0: 24: undefined, michael@0: 26: placeObject, michael@0: 28: removeObject, michael@0: 32: defineShape, michael@0: 33: defineLabel, michael@0: 34: defineButton, michael@0: 35: defineImage, michael@0: 36: defineBitmap, michael@0: 37: defineText, michael@0: 39: undefined, michael@0: 43: frameLabel, michael@0: 45: soundStreamHead, michael@0: 46: defineShape, michael@0: 48: defineFont2, michael@0: 56: exportAssets, michael@0: 57: undefined, michael@0: 58: undefined, michael@0: 59: doAction, michael@0: 60: undefined, michael@0: 61: undefined, michael@0: 62: undefined, michael@0: 64: undefined, michael@0: 65: undefined, michael@0: 66: undefined, michael@0: 69: fileAttributes, michael@0: 70: placeObject, michael@0: 71: undefined, michael@0: 72: doABC, michael@0: 73: undefined, michael@0: 74: undefined, michael@0: 75: defineFont2, michael@0: 76: symbolClass, michael@0: 77: undefined, michael@0: 78: defineScalingGrid, michael@0: 82: doABC, michael@0: 83: defineShape, michael@0: 84: defineShape, michael@0: 86: defineScene, michael@0: 87: defineBinaryData, michael@0: 88: undefined, michael@0: 89: startSound, michael@0: 90: defineImage, michael@0: 91: undefined michael@0: }; michael@0: }(this); michael@0: var readHeader = function readHeader($bytes, $stream, $, swfVersion, tagCode) { michael@0: $ || ($ = {}); michael@0: var $0 = $.bbox = {}; michael@0: align($bytes, $stream); michael@0: var bits = readUb($bytes, $stream, 5); michael@0: var xMin = readSb($bytes, $stream, bits); michael@0: var xMax = readSb($bytes, $stream, bits); michael@0: var yMin = readSb($bytes, $stream, bits); michael@0: var yMax = readSb($bytes, $stream, bits); michael@0: $0.xMin = xMin; michael@0: $0.xMax = xMax; michael@0: $0.yMin = yMin; michael@0: $0.yMax = yMax; michael@0: align($bytes, $stream); michael@0: var frameRateFraction = readUi8($bytes, $stream); michael@0: $.frameRate = readUi8($bytes, $stream) + frameRateFraction / 256; michael@0: $.frameCount = readUi16($bytes, $stream); michael@0: return $; michael@0: }; michael@0: function readTags(context, stream, swfVersion, final, onprogress, onexception) { michael@0: var tags = context.tags; michael@0: var bytes = stream.bytes; michael@0: var lastSuccessfulPosition; michael@0: var tag = null; michael@0: if (context._readTag) { michael@0: tag = context._readTag; michael@0: context._readTag = null; michael@0: } michael@0: try { michael@0: while (stream.pos < stream.end) { michael@0: lastSuccessfulPosition = stream.pos; michael@0: stream.ensure(2); michael@0: var tagCodeAndLength = readUi16(bytes, stream); michael@0: if (!tagCodeAndLength) { michael@0: final = true; michael@0: break; michael@0: } michael@0: var tagCode = tagCodeAndLength >> 6; michael@0: var length = tagCodeAndLength & 63; michael@0: if (length === 63) { michael@0: stream.ensure(4); michael@0: length = readUi32(bytes, stream); michael@0: } michael@0: if (tag) { michael@0: if (tagCode === 1 && tag.code === 1) { michael@0: tag.repeat++; michael@0: stream.pos += length; michael@0: continue; michael@0: } michael@0: tags.push(tag); michael@0: if (onprogress && tag.id !== undefined) { michael@0: onprogress(context); michael@0: } michael@0: tag = null; michael@0: } michael@0: stream.ensure(length); michael@0: var substream = stream.substream(stream.pos, stream.pos += length); michael@0: var subbytes = substream.bytes; michael@0: var nextTag = { michael@0: code: tagCode michael@0: }; michael@0: if (tagCode === 39) { michael@0: nextTag.type = 'sprite'; michael@0: nextTag.id = readUi16(subbytes, substream); michael@0: nextTag.frameCount = readUi16(subbytes, substream); michael@0: nextTag.tags = []; michael@0: readTags(nextTag, substream, swfVersion, true); michael@0: } else if (tagCode === 1) { michael@0: nextTag.repeat = 1; michael@0: } else { michael@0: var handler = tagHandler[tagCode]; michael@0: if (handler) { michael@0: handler(subbytes, substream, nextTag, swfVersion, tagCode); michael@0: } michael@0: } michael@0: tag = nextTag; michael@0: } michael@0: if (tag && final) { michael@0: tag.finalTag = true; michael@0: tags.push(tag); michael@0: if (onprogress) { michael@0: onprogress(context); michael@0: } michael@0: } else { michael@0: context._readTag = tag; michael@0: } michael@0: } catch (e) { michael@0: if (e !== StreamNoDataError) { michael@0: onexception && onexception(e); michael@0: throw e; michael@0: } michael@0: stream.pos = lastSuccessfulPosition; michael@0: context._readTag = tag; michael@0: } michael@0: } michael@0: function HeadTailBuffer(defaultSize) { michael@0: this.bufferSize = defaultSize || 16; michael@0: this.buffer = new Uint8Array(this.bufferSize); michael@0: this.pos = 0; michael@0: } michael@0: HeadTailBuffer.prototype = { michael@0: push: function (data, need) { michael@0: var bufferLengthNeed = this.pos + data.length; michael@0: if (this.bufferSize < bufferLengthNeed) { michael@0: var newBufferSize = this.bufferSize; michael@0: while (newBufferSize < bufferLengthNeed) { michael@0: newBufferSize <<= 1; michael@0: } michael@0: var newBuffer = new Uint8Array(newBufferSize); michael@0: if (this.bufferSize > 0) { michael@0: newBuffer.set(this.buffer); michael@0: } michael@0: this.buffer = newBuffer; michael@0: this.bufferSize = newBufferSize; michael@0: } michael@0: this.buffer.set(data, this.pos); michael@0: this.pos += data.length; michael@0: if (need) michael@0: return this.pos >= need; michael@0: }, michael@0: getHead: function (size) { michael@0: return this.buffer.subarray(0, size); michael@0: }, michael@0: getTail: function (offset) { michael@0: return this.buffer.subarray(offset, this.pos); michael@0: }, michael@0: removeHead: function (size) { michael@0: var tail = this.getTail(size); michael@0: this.buffer = new Uint8Array(this.bufferSize); michael@0: this.buffer.set(tail); michael@0: this.pos = tail.length; michael@0: }, michael@0: get arrayBuffer() { michael@0: return this.buffer.buffer; michael@0: }, michael@0: get length() { michael@0: return this.pos; michael@0: }, michael@0: createStream: function () { michael@0: return new Stream(this.arrayBuffer, 0, this.length); michael@0: } michael@0: }; michael@0: function CompressedPipe(target, length) { michael@0: this.target = target; michael@0: this.length = length; michael@0: this.initialize = true; michael@0: this.buffer = new HeadTailBuffer(8096); michael@0: this.state = { michael@0: bitBuffer: 0, michael@0: bitLength: 0, michael@0: compression: { michael@0: header: null, michael@0: distanceTable: null, michael@0: literalTable: null, michael@0: sym: null, michael@0: len: null, michael@0: sym2: null michael@0: } michael@0: }; michael@0: this.output = { michael@0: data: new Uint8Array(length), michael@0: available: 0, michael@0: completed: false michael@0: }; michael@0: } michael@0: CompressedPipe.prototype = { michael@0: push: function (data, progressInfo) { michael@0: var buffer = this.buffer; michael@0: if (this.initialize) { michael@0: if (!buffer.push(data, 2)) michael@0: return; michael@0: var headerBytes = buffer.getHead(2); michael@0: verifyDeflateHeader(headerBytes); michael@0: buffer.removeHead(2); michael@0: this.initialize = false; michael@0: } else { michael@0: buffer.push(data); michael@0: } michael@0: var stream = buffer.createStream(); michael@0: stream.bitBuffer = this.state.bitBuffer; michael@0: stream.bitLength = this.state.bitLength; michael@0: var output = this.output; michael@0: var lastAvailable = output.available; michael@0: try { michael@0: do { michael@0: inflateBlock(stream, output, this.state.compression); michael@0: } while (stream.pos < buffer.length && !output.completed); michael@0: } catch (e) { michael@0: if (e !== InflateNoDataError) michael@0: throw e; michael@0: } finally { michael@0: this.state.bitBuffer = stream.bitBuffer; michael@0: this.state.bitLength = stream.bitLength; michael@0: } michael@0: buffer.removeHead(stream.pos); michael@0: this.target.push(output.data.subarray(lastAvailable, output.available), progressInfo); michael@0: } michael@0: }; michael@0: function BodyParser(swfVersion, length, options) { michael@0: this.swf = { michael@0: swfVersion: swfVersion, michael@0: parseTime: 0 michael@0: }; michael@0: this.buffer = new HeadTailBuffer(32768); michael@0: this.initialize = true; michael@0: this.totalRead = 0; michael@0: this.length = length; michael@0: this.options = options; michael@0: } michael@0: BodyParser.prototype = { michael@0: push: function (data, progressInfo) { michael@0: if (data.length === 0) michael@0: return; michael@0: var swf = this.swf; michael@0: var swfVersion = swf.swfVersion; michael@0: var buffer = this.buffer; michael@0: var options = this.options; michael@0: var stream; michael@0: if (this.initialize) { michael@0: var PREFETCH_SIZE = 27; michael@0: if (!buffer.push(data, PREFETCH_SIZE)) michael@0: return; michael@0: stream = buffer.createStream(); michael@0: var bytes = stream.bytes; michael@0: readHeader(bytes, stream, swf); michael@0: var nextTagHeader = readUi16(bytes, stream); michael@0: var FILE_ATTRIBUTES_LENGTH = 4; michael@0: if (nextTagHeader == (SWF_TAG_CODE_FILE_ATTRIBUTES << 6 | FILE_ATTRIBUTES_LENGTH)) { michael@0: stream.ensure(FILE_ATTRIBUTES_LENGTH); michael@0: var substream = stream.substream(stream.pos, stream.pos += FILE_ATTRIBUTES_LENGTH); michael@0: var handler = tagHandler[SWF_TAG_CODE_FILE_ATTRIBUTES]; michael@0: var fileAttributesTag = { michael@0: code: SWF_TAG_CODE_FILE_ATTRIBUTES michael@0: }; michael@0: handler(substream.bytes, substream, fileAttributesTag, swfVersion, SWF_TAG_CODE_FILE_ATTRIBUTES); michael@0: swf.fileAttributes = fileAttributesTag; michael@0: } else { michael@0: stream.pos -= 2; michael@0: swf.fileAttributes = {}; michael@0: } michael@0: if (options.onstart) michael@0: options.onstart(swf); michael@0: swf.tags = []; michael@0: this.initialize = false; michael@0: } else { michael@0: buffer.push(data); michael@0: stream = buffer.createStream(); michael@0: } michael@0: var finalBlock = false; michael@0: if (progressInfo) { michael@0: swf.bytesLoaded = progressInfo.bytesLoaded; michael@0: swf.bytesTotal = progressInfo.bytesTotal; michael@0: finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal; michael@0: } michael@0: var readStartTime = performance.now(); michael@0: readTags(swf, stream, swfVersion, finalBlock, options.onprogress, options.onexception); michael@0: swf.parseTime += performance.now() - readStartTime; michael@0: var read = stream.pos; michael@0: buffer.removeHead(read); michael@0: this.totalRead += read; michael@0: if (options.oncomplete && swf.tags[swf.tags.length - 1].finalTag) { michael@0: options.oncomplete(swf); michael@0: } michael@0: } michael@0: }; michael@0: SWF.parseAsync = function swf_parseAsync(options) { michael@0: var buffer = new HeadTailBuffer(); michael@0: var pipe = { michael@0: push: function (data, progressInfo) { michael@0: if (this.target !== undefined) { michael@0: return this.target.push(data, progressInfo); michael@0: } michael@0: if (!buffer.push(data, 8)) { michael@0: return null; michael@0: } michael@0: var bytes = buffer.getHead(8); michael@0: var magic1 = bytes[0]; michael@0: var magic2 = bytes[1]; michael@0: var magic3 = bytes[2]; michael@0: if ((magic1 === 70 || magic1 === 67) && magic2 === 87 && magic3 === 83) { michael@0: var swfVersion = bytes[3]; michael@0: var compressed = magic1 === 67; michael@0: parseSWF(compressed, swfVersion, progressInfo); michael@0: buffer = null; michael@0: return; michael@0: } michael@0: var isImage = false; michael@0: var imageType; michael@0: if (magic1 === 255 && magic2 === 216 && magic3 === 255) { michael@0: isImage = true; michael@0: imageType = 'image/jpeg'; michael@0: } else if (magic1 === 137 && magic2 === 80 && magic3 === 78) { michael@0: isImage = true; michael@0: imageType = 'image/png'; michael@0: } michael@0: if (isImage) { michael@0: parseImage(data, progressInfo.bytesTotal, imageType); michael@0: } michael@0: buffer = null; michael@0: }, michael@0: close: function () { michael@0: if (buffer) { michael@0: var symbol = { michael@0: command: 'empty', michael@0: data: buffer.buffer.subarray(0, buffer.pos) michael@0: }; michael@0: options.oncomplete && options.oncomplete(symbol); michael@0: } michael@0: if (this.target !== undefined && this.target.close) { michael@0: this.target.close(); michael@0: } michael@0: } michael@0: }; michael@0: function parseSWF(compressed, swfVersion, progressInfo) { michael@0: var stream = buffer.createStream(); michael@0: stream.pos += 4; michael@0: var fileLength = readUi32(null, stream); michael@0: var bodyLength = fileLength - 8; michael@0: var target = new BodyParser(swfVersion, bodyLength, options); michael@0: if (compressed) { michael@0: target = new CompressedPipe(target, bodyLength); michael@0: } michael@0: target.push(buffer.getTail(8), progressInfo); michael@0: pipe['target'] = target; michael@0: } michael@0: function parseImage(data, bytesTotal, type) { michael@0: var buffer = new Uint8Array(bytesTotal); michael@0: buffer.set(data); michael@0: var bufferPos = data.length; michael@0: pipe['target'] = { michael@0: push: function (data) { michael@0: buffer.set(data, bufferPos); michael@0: bufferPos += data.length; michael@0: }, michael@0: close: function () { michael@0: var props = {}; michael@0: var chunks; michael@0: if (type == 'image/jpeg') { michael@0: chunks = parseJpegChunks(props, buffer); michael@0: } else { michael@0: chunks = [ michael@0: buffer michael@0: ]; michael@0: } michael@0: var symbol = { michael@0: type: 'image', michael@0: props: props, michael@0: data: new Blob(chunks, { michael@0: type: type michael@0: }) michael@0: }; michael@0: options.oncomplete && options.oncomplete(symbol); michael@0: } michael@0: }; michael@0: } michael@0: return pipe; michael@0: }; michael@0: SWF.parse = function (buffer, options) { michael@0: if (!options) michael@0: options = {}; michael@0: var pipe = SWF.parseAsync(options); michael@0: var bytes = new Uint8Array(buffer); michael@0: var progressInfo = { michael@0: bytesLoaded: bytes.length, michael@0: bytesTotal: bytes.length michael@0: }; michael@0: pipe.push(bytes, progressInfo); michael@0: pipe.close(); michael@0: }; michael@0: var $RELEASE = false; michael@0: var isWorker = typeof window === 'undefined'; michael@0: if (isWorker && !true) { michael@0: importScripts.apply(null, [ michael@0: '../../lib/DataView.js/DataView.js', michael@0: '../flash/util.js', michael@0: 'config.js', michael@0: 'swf.js', michael@0: 'types.js', michael@0: 'structs.js', michael@0: 'tags.js', michael@0: 'inflate.js', michael@0: 'stream.js', michael@0: 'templates.js', michael@0: 'generator.js', michael@0: 'handlers.js', michael@0: 'parser.js', michael@0: 'bitmap.js', michael@0: 'button.js', michael@0: 'font.js', michael@0: 'image.js', michael@0: 'label.js', michael@0: 'shape.js', michael@0: 'sound.js', michael@0: 'text.js' michael@0: ]); michael@0: } michael@0: function defineSymbol(swfTag, symbols) { michael@0: var symbol; michael@0: switch (swfTag.code) { michael@0: case SWF_TAG_CODE_DEFINE_BITS: michael@0: case SWF_TAG_CODE_DEFINE_BITS_JPEG2: michael@0: case SWF_TAG_CODE_DEFINE_BITS_JPEG3: michael@0: case SWF_TAG_CODE_DEFINE_BITS_JPEG4: michael@0: case SWF_TAG_CODE_JPEG_TABLES: michael@0: symbol = defineImage(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS: michael@0: case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2: michael@0: symbol = defineBitmap(swfTag); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_BUTTON: michael@0: case SWF_TAG_CODE_DEFINE_BUTTON2: michael@0: symbol = defineButton(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_EDIT_TEXT: michael@0: symbol = defineText(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_FONT: michael@0: case SWF_TAG_CODE_DEFINE_FONT2: michael@0: case SWF_TAG_CODE_DEFINE_FONT3: michael@0: case SWF_TAG_CODE_DEFINE_FONT4: michael@0: symbol = defineFont(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_MORPH_SHAPE: michael@0: case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2: michael@0: case SWF_TAG_CODE_DEFINE_SHAPE: michael@0: case SWF_TAG_CODE_DEFINE_SHAPE2: michael@0: case SWF_TAG_CODE_DEFINE_SHAPE3: michael@0: case SWF_TAG_CODE_DEFINE_SHAPE4: michael@0: symbol = defineShape(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_SOUND: michael@0: symbol = defineSound(swfTag, symbols); michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_BINARY_DATA: michael@0: symbol = { michael@0: type: 'binary', michael@0: id: swfTag.id, michael@0: data: swfTag.data michael@0: }; michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_SPRITE: michael@0: var depths = {}; michael@0: var frame = { michael@0: type: 'frame' michael@0: }; michael@0: var frames = []; michael@0: var tags = swfTag.tags; michael@0: var frameScripts = null; michael@0: var frameIndex = 0; michael@0: var soundStream = null; michael@0: for (var i = 0, n = tags.length; i < n; i++) { michael@0: var tag = tags[i]; michael@0: switch (tag.code) { michael@0: case SWF_TAG_CODE_DO_ACTION: michael@0: if (!frameScripts) michael@0: frameScripts = []; michael@0: frameScripts.push(frameIndex); michael@0: frameScripts.push(tag.actionsData); michael@0: break; michael@0: case SWF_TAG_CODE_START_SOUND: michael@0: var startSounds = frame.startSounds || (frame.startSounds = []); michael@0: startSounds.push(tag); michael@0: break; michael@0: case SWF_TAG_CODE_SOUND_STREAM_HEAD: michael@0: try { michael@0: soundStream = createSoundStream(tag); michael@0: frame.soundStream = soundStream.info; michael@0: } catch (e) { michael@0: } michael@0: break; michael@0: case SWF_TAG_CODE_SOUND_STREAM_BLOCK: michael@0: if (soundStream) { michael@0: frame.soundStreamBlock = soundStream.decode(tag.data); michael@0: } michael@0: break; michael@0: case SWF_TAG_CODE_FRAME_LABEL: michael@0: frame.labelName = tag.name; michael@0: break; michael@0: case SWF_TAG_CODE_PLACE_OBJECT: michael@0: case SWF_TAG_CODE_PLACE_OBJECT2: michael@0: case SWF_TAG_CODE_PLACE_OBJECT3: michael@0: depths[tag.depth] = tag; michael@0: break; michael@0: case SWF_TAG_CODE_REMOVE_OBJECT: michael@0: case SWF_TAG_CODE_REMOVE_OBJECT2: michael@0: depths[tag.depth] = null; michael@0: break; michael@0: case SWF_TAG_CODE_SHOW_FRAME: michael@0: frameIndex += tag.repeat; michael@0: frame.repeat = tag.repeat; michael@0: frame.depths = depths; michael@0: frames.push(frame); michael@0: depths = {}; michael@0: frame = { michael@0: type: 'frame' michael@0: }; michael@0: break; michael@0: } michael@0: } michael@0: symbol = { michael@0: type: 'sprite', michael@0: id: swfTag.id, michael@0: frameCount: swfTag.frameCount, michael@0: frames: frames, michael@0: frameScripts: frameScripts michael@0: }; michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_TEXT: michael@0: case SWF_TAG_CODE_DEFINE_TEXT2: michael@0: symbol = defineLabel(swfTag, symbols); michael@0: break; michael@0: } michael@0: if (!symbol) { michael@0: return { michael@0: command: 'error', michael@0: message: 'unknown symbol type: ' + swfTag.code michael@0: }; michael@0: } michael@0: symbol.isSymbol = true; michael@0: symbols[swfTag.id] = symbol; michael@0: return symbol; michael@0: } michael@0: function createParsingContext(commitData) { michael@0: var depths = {}; michael@0: var symbols = {}; michael@0: var frame = { michael@0: type: 'frame' michael@0: }; michael@0: var tagsProcessed = 0; michael@0: var soundStream = null; michael@0: var lastProgressSent = 0; michael@0: return { michael@0: onstart: function (result) { michael@0: commitData({ michael@0: command: 'init', michael@0: result: result michael@0: }); michael@0: }, michael@0: onprogress: function (result) { michael@0: if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) { michael@0: commitData({ michael@0: command: 'progress', michael@0: result: { michael@0: bytesLoaded: result.bytesLoaded, michael@0: bytesTotal: result.bytesTotal michael@0: } michael@0: }); michael@0: lastProgressSent = Date.now(); michael@0: } michael@0: var tags = result.tags; michael@0: for (var n = tags.length; tagsProcessed < n; tagsProcessed++) { michael@0: var tag = tags[tagsProcessed]; michael@0: if ('id' in tag) { michael@0: var symbol = defineSymbol(tag, symbols); michael@0: commitData(symbol, symbol.transferables); michael@0: continue; michael@0: } michael@0: switch (tag.code) { michael@0: case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA: michael@0: frame.sceneData = tag; michael@0: break; michael@0: case SWF_TAG_CODE_DEFINE_SCALING_GRID: michael@0: var symbolUpdate = { michael@0: isSymbol: true, michael@0: id: tag.symbolId, michael@0: updates: { michael@0: scale9Grid: tag.splitter michael@0: } michael@0: }; michael@0: commitData(symbolUpdate); michael@0: break; michael@0: case SWF_TAG_CODE_DO_ABC: michael@0: case SWF_TAG_CODE_DO_ABC_: michael@0: var abcBlocks = frame.abcBlocks; michael@0: if (abcBlocks) michael@0: abcBlocks.push({ michael@0: data: tag.data, michael@0: flags: tag.flags michael@0: }); michael@0: else michael@0: frame.abcBlocks = [ michael@0: { michael@0: data: tag.data, michael@0: flags: tag.flags michael@0: } michael@0: ]; michael@0: break; michael@0: case SWF_TAG_CODE_DO_ACTION: michael@0: var actionBlocks = frame.actionBlocks; michael@0: if (actionBlocks) michael@0: actionBlocks.push(tag.actionsData); michael@0: else michael@0: frame.actionBlocks = [ michael@0: tag.actionsData michael@0: ]; michael@0: break; michael@0: case SWF_TAG_CODE_DO_INIT_ACTION: michael@0: var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []); michael@0: initActionBlocks.push({ michael@0: spriteId: tag.spriteId, michael@0: actionsData: tag.actionsData michael@0: }); michael@0: break; michael@0: case SWF_TAG_CODE_START_SOUND: michael@0: var startSounds = frame.startSounds; michael@0: if (!startSounds) michael@0: frame.startSounds = startSounds = []; michael@0: startSounds.push(tag); michael@0: break; michael@0: case SWF_TAG_CODE_SOUND_STREAM_HEAD: michael@0: try { michael@0: soundStream = createSoundStream(tag); michael@0: frame.soundStream = soundStream.info; michael@0: } catch (e) { michael@0: } michael@0: break; michael@0: case SWF_TAG_CODE_SOUND_STREAM_BLOCK: michael@0: if (soundStream) { michael@0: frame.soundStreamBlock = soundStream.decode(tag.data); michael@0: } michael@0: break; michael@0: case SWF_TAG_CODE_EXPORT_ASSETS: michael@0: var exports = frame.exports; michael@0: if (exports) michael@0: frame.exports = exports.concat(tag.exports); michael@0: else michael@0: frame.exports = tag.exports.slice(0); michael@0: break; michael@0: case SWF_TAG_CODE_SYMBOL_CLASS: michael@0: var symbolClasses = frame.symbolClasses; michael@0: if (symbolClasses) michael@0: frame.symbolClasses = symbolClasses.concat(tag.exports); michael@0: else michael@0: frame.symbolClasses = tag.exports.slice(0); michael@0: break; michael@0: case SWF_TAG_CODE_FRAME_LABEL: michael@0: frame.labelName = tag.name; michael@0: break; michael@0: case SWF_TAG_CODE_PLACE_OBJECT: michael@0: case SWF_TAG_CODE_PLACE_OBJECT2: michael@0: case SWF_TAG_CODE_PLACE_OBJECT3: michael@0: depths[tag.depth] = tag; michael@0: break; michael@0: case SWF_TAG_CODE_REMOVE_OBJECT: michael@0: case SWF_TAG_CODE_REMOVE_OBJECT2: michael@0: depths[tag.depth] = null; michael@0: break; michael@0: case SWF_TAG_CODE_SET_BACKGROUND_COLOR: michael@0: frame.bgcolor = tag.color; michael@0: break; michael@0: case SWF_TAG_CODE_SHOW_FRAME: michael@0: frame.repeat = tag.repeat; michael@0: frame.depths = depths; michael@0: frame.complete = !(!tag.finalTag); michael@0: commitData(frame); michael@0: depths = {}; michael@0: frame = { michael@0: type: 'frame' michael@0: }; michael@0: break; michael@0: } michael@0: } michael@0: }, michael@0: oncomplete: function (result) { michael@0: commitData(result); michael@0: var stats; michael@0: if (typeof result.swfVersion === 'number') { michael@0: var bbox = result.bbox; michael@0: stats = { michael@0: topic: 'parseInfo', michael@0: parseTime: result.parseTime, michael@0: bytesTotal: result.bytesTotal, michael@0: swfVersion: result.swfVersion, michael@0: frameRate: result.frameRate, michael@0: width: (bbox.xMax - bbox.xMin) / 20, michael@0: height: (bbox.yMax - bbox.yMin) / 20, michael@0: isAvm2: !(!result.fileAttributes.doAbc) michael@0: }; michael@0: } michael@0: commitData({ michael@0: command: 'complete', michael@0: stats: stats michael@0: }); michael@0: }, michael@0: onexception: function (e) { michael@0: commitData({ michael@0: type: 'exception', michael@0: message: e.message, michael@0: stack: e.stack michael@0: }); michael@0: } michael@0: }; michael@0: } michael@0: function parseBytes(bytes, commitData) { michael@0: SWF.parse(bytes, createParsingContext(commitData)); michael@0: } michael@0: function ResourceLoader(scope) { michael@0: this.subscription = null; michael@0: var self = this; michael@0: if (!isWorker) { michael@0: this.messenger = { michael@0: postMessage: function (data) { michael@0: self.onmessage({ michael@0: data: data michael@0: }); michael@0: } michael@0: }; michael@0: } else { michael@0: this.messenger = scope; michael@0: scope.onmessage = function (event) { michael@0: self.listener(event.data); michael@0: }; michael@0: } michael@0: } michael@0: ResourceLoader.prototype = { michael@0: terminate: function () { michael@0: this.messenger = null; michael@0: this.listener = null; michael@0: }, michael@0: onmessage: function (event) { michael@0: this.listener(event.data); michael@0: }, michael@0: postMessage: function (data) { michael@0: this.listener && this.listener(data); michael@0: }, michael@0: listener: function (data) { michael@0: if (this.subscription) { michael@0: this.subscription.callback(data.data, data.progress); michael@0: } else if (data === 'pipe:') { michael@0: this.subscription = { michael@0: subscribe: function (callback) { michael@0: this.callback = callback; michael@0: } michael@0: }; michael@0: this.parseLoadedData(this.messenger, this.subscription); michael@0: } else { michael@0: this.parseLoadedData(this.messenger, data); michael@0: } michael@0: }, michael@0: parseLoadedData: function (loader, request, context) { michael@0: function commitData(data, transferables) { michael@0: try { michael@0: loader.postMessage(data, transferables); michael@0: } catch (ex) { michael@0: if (ex != 'DataCloneError') { michael@0: throw ex; michael@0: } michael@0: loader.postMessage(data); michael@0: } michael@0: } michael@0: if (request instanceof ArrayBuffer) { michael@0: parseBytes(request, commitData); michael@0: } else if ('subscribe' in request) { michael@0: var pipe = SWF.parseAsync(createParsingContext(commitData)); michael@0: request.subscribe(function (data, progress) { michael@0: if (data) { michael@0: pipe.push(data, progress); michael@0: } else { michael@0: pipe.close(); michael@0: } michael@0: }); michael@0: } else if (typeof FileReaderSync !== 'undefined') { michael@0: var reader = new FileReaderSync(); michael@0: var buffer = reader.readAsArrayBuffer(request); michael@0: parseBytes(buffer, commitData); michael@0: } else { michael@0: var reader = new FileReader(); michael@0: reader.onload = function () { michael@0: parseBytes(this.result, commitData); michael@0: }; michael@0: reader.readAsArrayBuffer(request); michael@0: } michael@0: } michael@0: }; michael@0: if (isWorker) { michael@0: var loader = new ResourceLoader(this); michael@0: } michael@0: function ActionsDataStream(array, swfVersion) { michael@0: this.array = array; michael@0: this.position = 0; michael@0: this.end = array.length; michael@0: if (swfVersion >= 6) { michael@0: this.readString = this.readUTF8String; michael@0: } else { michael@0: this.readString = this.readANSIString; michael@0: } michael@0: var buffer = new ArrayBuffer(4); michael@0: new Int32Array(buffer)[0] = 1; michael@0: if (!new Uint8Array(buffer)[0]) { michael@0: throw new Error('big-endian platform'); michael@0: } michael@0: } michael@0: ActionsDataStream.prototype = { michael@0: readUI8: function ActionsDataStream_readUI8() { michael@0: return this.array[this.position++]; michael@0: }, michael@0: readUI16: function ActionsDataStream_readUI16() { michael@0: var position = this.position, array = this.array; michael@0: var value = array[position + 1] << 8 | array[position]; michael@0: this.position = position + 2; michael@0: return value; michael@0: }, michael@0: readSI16: function ActionsDataStream_readSI16() { michael@0: var position = this.position, array = this.array; michael@0: var value = array[position + 1] << 8 | array[position]; michael@0: this.position = position + 2; michael@0: return value < 32768 ? value : value - 65536; michael@0: }, michael@0: readInteger: function ActionsDataStream_readInteger() { michael@0: var position = this.position, array = this.array; michael@0: var value = array[position] | array[position + 1] << 8 | array[position + 2] << 16 | array[position + 3] << 24; michael@0: this.position = position + 4; michael@0: return value; michael@0: }, michael@0: readFloat: function ActionsDataStream_readFloat() { michael@0: var position = this.position; michael@0: var array = this.array; michael@0: var buffer = new ArrayBuffer(4); michael@0: var bytes = new Uint8Array(buffer); michael@0: bytes[0] = array[position]; michael@0: bytes[1] = array[position + 1]; michael@0: bytes[2] = array[position + 2]; michael@0: bytes[3] = array[position + 3]; michael@0: this.position = position + 4; michael@0: return new Float32Array(buffer)[0]; michael@0: }, michael@0: readDouble: function ActionsDataStream_readDouble() { michael@0: var position = this.position; michael@0: var array = this.array; michael@0: var buffer = new ArrayBuffer(8); michael@0: var bytes = new Uint8Array(buffer); michael@0: bytes[4] = array[position]; michael@0: bytes[5] = array[position + 1]; michael@0: bytes[6] = array[position + 2]; michael@0: bytes[7] = array[position + 3]; michael@0: bytes[0] = array[position + 4]; michael@0: bytes[1] = array[position + 5]; michael@0: bytes[2] = array[position + 6]; michael@0: bytes[3] = array[position + 7]; michael@0: this.position = position + 8; michael@0: return new Float64Array(buffer)[0]; michael@0: }, michael@0: readBoolean: function ActionsDataStream_readBoolean() { michael@0: return !(!this.readUI8()); michael@0: }, michael@0: readANSIString: function ActionsDataStream_readANSIString() { michael@0: var value = ''; michael@0: var ch; michael@0: while (ch = this.readUI8()) { michael@0: value += String.fromCharCode(ch); michael@0: } michael@0: return value; michael@0: }, michael@0: readUTF8String: function ActionsDataStream_readUTF8String() { michael@0: var value = ''; michael@0: var ch; michael@0: while (ch = this.readUI8()) { michael@0: if (ch < 128) { michael@0: value += String.fromCharCode(ch); michael@0: continue; michael@0: } michael@0: if ((ch & 192) === 128) { michael@0: throw new Error('Invalid UTF8 encoding'); michael@0: } michael@0: var currentPrefix = 192; michael@0: var validBits = 5; michael@0: do { michael@0: var mask = currentPrefix >> 1 | 128; michael@0: if ((ch & mask) === currentPrefix) { michael@0: break; michael@0: } michael@0: currentPrefix = mask; michael@0: --validBits; michael@0: } while (validBits >= 0); michael@0: var code = ch & (1 << validBits) - 1; michael@0: for (var i = 5; i >= validBits; --i) { michael@0: ch = this.readUI8(); michael@0: if ((ch & 192) !== 128) { michael@0: throw new Error('Invalid UTF8 encoding'); michael@0: } michael@0: code = code << 6 | ch & 63; michael@0: } michael@0: if (code >= 65536) { michael@0: value += String.fromCharCode(code - 65536 >> 10 & 1023 | 55296, code & 1023 | 56320); michael@0: } else { michael@0: value += String.fromCharCode(code); michael@0: } michael@0: } michael@0: return value; michael@0: }, michael@0: readBytes: function ActionsDataStream_readBytes(length) { michael@0: var position = this.position; michael@0: var remaining = Math.max(this.end - position, 0); michael@0: if (remaining < length) { michael@0: length = remaining; michael@0: } michael@0: var subarray = this.array.subarray(position, position + length); michael@0: this.position = position + length; michael@0: return subarray; michael@0: } michael@0: }; michael@0: if (typeof GLOBAL !== 'undefined') { michael@0: GLOBAL.ActionsDataStream = ActionsDataStream; michael@0: } michael@0: var AVM1_TRACE_ENABLED = false; michael@0: var AVM1_ERRORS_IGNORED = true; michael@0: var MAX_AVM1_HANG_TIMEOUT = 1000; michael@0: var MAX_AVM1_ERRORS_LIMIT = 1000; michael@0: var MAX_AVM1_STACK_LIMIT = 256; michael@0: function AS2ScopeListItem(scope, next) { michael@0: this.scope = scope; michael@0: this.next = next; michael@0: } michael@0: AS2ScopeListItem.prototype = { michael@0: create: function (scope) { michael@0: return new AS2ScopeListItem(scope, this); michael@0: } michael@0: }; michael@0: function AS2Context(swfVersion) { michael@0: this.swfVersion = swfVersion; michael@0: this.globals = new avm1lib.AS2Globals(this); michael@0: this.initialScope = new AS2ScopeListItem(this.globals, null); michael@0: this.assets = {}; michael@0: this.isActive = false; michael@0: this.executionProhibited = false; michael@0: this.abortExecutionAt = 0; michael@0: this.stackDepth = 0; michael@0: this.isTryCatchListening = false; michael@0: this.errorsIgnored = 0; michael@0: this.deferScriptExecution = true; michael@0: this.pendingScripts = []; michael@0: } michael@0: AS2Context.instance = null; michael@0: AS2Context.prototype = { michael@0: addAsset: function (className, symbolProps) { michael@0: this.assets[className] = symbolProps; michael@0: }, michael@0: resolveTarget: function (target) { michael@0: if (!target) { michael@0: target = this.defaultTarget; michael@0: } else if (typeof target === 'string') { michael@0: target = lookupAS2Children(target, this.defaultTarget, this.globals.asGetPublicProperty('_root')); michael@0: } michael@0: if (typeof target !== 'object' || target === null || !('$nativeObject' in target)) { michael@0: throw new Error('Invalid AS2 target object: ' + Object.prototype.toString.call(target)); michael@0: } michael@0: return target; michael@0: }, michael@0: resolveLevel: function (level) { michael@0: return this.resolveTarget(this.globals['_level' + level]); michael@0: }, michael@0: addToPendingScripts: function (fn) { michael@0: if (!this.deferScriptExecution) { michael@0: return fn(); michael@0: } michael@0: this.pendingScripts.push(fn); michael@0: }, michael@0: flushPendingScripts: function () { michael@0: var scripts = this.pendingScripts; michael@0: while (scripts.length) { michael@0: scripts.shift()(); michael@0: } michael@0: this.deferScriptExecution = false; michael@0: } michael@0: }; michael@0: function AS2Error(error) { michael@0: this.error = error; michael@0: } michael@0: function AS2CriticalError(message, error) { michael@0: this.message = message; michael@0: this.error = error; michael@0: } michael@0: AS2CriticalError.prototype = Object.create(Error.prototype); michael@0: function isAS2MovieClip(obj) { michael@0: return typeof obj === 'object' && obj && obj instanceof avm1lib.AS2MovieClip; michael@0: } michael@0: function as2GetType(v) { michael@0: if (v === null) { michael@0: return 'null'; michael@0: } michael@0: var type = typeof v; michael@0: if (type === 'function') { michael@0: return 'object'; michael@0: } michael@0: if (type === 'object' && isAS2MovieClip(v)) { michael@0: return 'movieclip'; michael@0: } michael@0: return type; michael@0: } michael@0: function as2ToPrimitive(value) { michael@0: return as2GetType(value) !== 'object' ? value : value.valueOf(); michael@0: } michael@0: function as2ToAddPrimitive(value) { michael@0: if (as2GetType(value) !== 'object') { michael@0: return value; michael@0: } michael@0: if (value instanceof Date && AS2Context.instance.swfVersion >= 6) { michael@0: return value.toString(); michael@0: } else { michael@0: return value.valueOf(); michael@0: } michael@0: } michael@0: function as2ToBoolean(value) { michael@0: switch (as2GetType(value)) { michael@0: default: michael@0: case 'undefined': michael@0: case 'null': michael@0: return false; michael@0: case 'boolean': michael@0: return value; michael@0: case 'number': michael@0: return value !== 0 && !isNaN(value); michael@0: case 'string': michael@0: return value.length !== 0; michael@0: case 'movieclip': michael@0: case 'object': michael@0: return true; michael@0: } michael@0: } michael@0: function as2ToNumber(value) { michael@0: value = as2ToPrimitive(value); michael@0: switch (as2GetType(value)) { michael@0: case 'undefined': michael@0: case 'null': michael@0: return AS2Context.instance.swfVersion >= 7 ? NaN : 0; michael@0: case 'boolean': michael@0: return value ? 1 : +0; michael@0: case 'number': michael@0: return value; michael@0: case 'string': michael@0: if (value === '' && AS2Context.instance.swfVersion < 5) { michael@0: return 0; michael@0: } michael@0: return +value; michael@0: default: michael@0: return AS2Context.instance.swfVersion >= 5 ? NaN : 0; michael@0: } michael@0: } michael@0: function as2ToInteger(value) { michael@0: var result = as2ToNumber(value); michael@0: if (isNaN(result)) { michael@0: return 0; michael@0: } michael@0: if (!isFinite(result) || result === 0) { michael@0: return result; michael@0: } michael@0: return (result < 0 ? -1 : 1) * Math.abs(result) | 0; michael@0: } michael@0: function as2ToInt32(value) { michael@0: var result = as2ToNumber(value); michael@0: return isNaN(result) || !isFinite(result) || result === 0 ? 0 : result | 0; michael@0: } michael@0: function as2ToString(value) { michael@0: switch (as2GetType(value)) { michael@0: case 'undefined': michael@0: return AS2Context.instance.swfVersion >= 7 ? 'undefined' : ''; michael@0: case 'null': michael@0: return 'null'; michael@0: case 'boolean': michael@0: return value ? 'true' : 'false'; michael@0: case 'number': michael@0: return value.toString(); michael@0: case 'string': michael@0: return value; michael@0: case 'movieclip': michael@0: return value.$targetPath; michael@0: case 'object': michael@0: var result = value.toString !== Function.prototype.toString ? value.toString() : value; michael@0: if (typeof result === 'string') { michael@0: return result; michael@0: } michael@0: return typeof value === 'function' ? '[type Function]' : '[type Object]'; michael@0: } michael@0: } michael@0: function as2Compare(x, y) { michael@0: var x2 = as2ToPrimitive(x); michael@0: var y2 = as2ToPrimitive(y); michael@0: if (typeof x2 === 'string' && typeof y2 === 'string') { michael@0: return x2 < y2; michael@0: } else { michael@0: return as2ToNumber(x2) < as2ToNumber(y2); michael@0: } michael@0: } michael@0: function as2InstanceOf(obj, constructor) { michael@0: if (obj instanceof constructor) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: function as2ResolveProperty(obj, name) { michael@0: var avm2PublicName = Multiname.getPublicQualifiedName(name); michael@0: if (avm2PublicName in obj) { michael@0: return name; michael@0: } michael@0: if (isNumeric(name)) { michael@0: return null; michael@0: } michael@0: var lowerCaseName = avm2PublicName.toLowerCase(); michael@0: for (var i in obj) { michael@0: if (i.toLowerCase() === lowerCaseName) { michael@0: notImplemented('FIX THIS'); michael@0: } michael@0: } michael@0: return null; michael@0: } michael@0: function as2GetPrototype(obj) { michael@0: return obj && obj.asGetPublicProperty('prototype'); michael@0: } michael@0: function isAvm2Class(obj) { michael@0: return typeof obj === 'object' && obj !== null && 'instanceConstructor' in obj; michael@0: } michael@0: function as2CreatePrototypeProxy(obj) { michael@0: var prototype = obj.asGetPublicProperty('prototype'); michael@0: if (typeof Proxy === 'undefined') { michael@0: console.error('ES6 proxies are not found'); michael@0: return prototype; michael@0: } michael@0: return Proxy.create({ michael@0: getOwnPropertyDescriptor: function (name) { michael@0: return Object.getOwnPropertyDescriptor(prototype, name); michael@0: }, michael@0: getPropertyDescriptor: function (name) { michael@0: for (var p = prototype; p; p = Object.getPrototypeOf(p)) { michael@0: var desc = Object.getOwnPropertyDescriptor(p, name); michael@0: if (desc) michael@0: return desc; michael@0: } michael@0: }, michael@0: getOwnPropertyNames: function () { michael@0: return Object.getOwnPropertyNames(prototype); michael@0: }, michael@0: getPropertyNames: function () { michael@0: var names = Object.getOwnPropertyNames(prototype); michael@0: for (var p = Object.getPrototypeOf(prototype); p; p = Object.getPrototypeOf(p)) { michael@0: names = names.concat(Object.getOwnPropertyNames(p)); michael@0: } michael@0: return names; michael@0: }, michael@0: defineProperty: function (name, desc) { michael@0: if (desc) { michael@0: if (typeof desc.value === 'function' && desc.value._setClass) { michael@0: desc.value._setClass(obj); michael@0: } michael@0: if (typeof desc.get === 'function' && desc.get._setClass) { michael@0: desc.get._setClass(obj); michael@0: } michael@0: if (typeof desc.set === 'function' && desc.set._setClass) { michael@0: desc.set._setClass(obj); michael@0: } michael@0: } michael@0: return Object.defineProperty(prototype, name, desc); michael@0: }, michael@0: delete: function (name) { michael@0: return delete prototype[name]; michael@0: }, michael@0: fix: function () { michael@0: return undefined; michael@0: } michael@0: }); michael@0: } michael@0: function executeActions(actionsData, context, scope) { michael@0: if (context.executionProhibited) { michael@0: return; michael@0: } michael@0: var actionTracer = ActionTracerFactory.get(); michael@0: var scopeContainer = context.initialScope.create(scope); michael@0: var savedContext = AS2Context.instance; michael@0: try { michael@0: AS2Context.instance = context; michael@0: context.isActive = true; michael@0: context.abortExecutionAt = Date.now() + MAX_AVM1_HANG_TIMEOUT; michael@0: context.errorsIgnored = 0; michael@0: context.defaultTarget = scope; michael@0: context.globals.asSetPublicProperty('this', scope); michael@0: actionTracer.message('ActionScript Execution Starts'); michael@0: actionTracer.indent(); michael@0: interpretActions(actionsData, scopeContainer, null, []); michael@0: } catch (e) { michael@0: if (e instanceof AS2CriticalError) { michael@0: console.error('Disabling AVM1 execution'); michael@0: context.executionProhibited = true; michael@0: } michael@0: throw e; michael@0: } finally { michael@0: context.isActive = false; michael@0: actionTracer.unindent(); michael@0: actionTracer.message('ActionScript Execution Stops'); michael@0: AS2Context.instance = savedContext; michael@0: } michael@0: } michael@0: function lookupAS2Children(targetPath, defaultTarget, root) { michael@0: var path = targetPath.split(/[\/.]/g); michael@0: if (path[path.length - 1] === '') { michael@0: path.pop(); michael@0: } michael@0: var obj = defaultTarget; michael@0: if (path[0] === '' || path[0] === '_level0' || path[0] === '_root') { michael@0: obj = root; michael@0: path.shift(); michael@0: } michael@0: while (path.length > 0) { michael@0: var prevObj = obj; michael@0: obj = obj.$lookupChild(path[0]); michael@0: if (!obj) { michael@0: throw new Error(path[0] + ' (expr ' + targetPath + ') is not found in ' + prevObj._target); michael@0: } michael@0: path.shift(); michael@0: } michael@0: return obj; michael@0: } michael@0: function createBuiltinType(obj, args) { michael@0: if (obj === Array) { michael@0: var result = args; michael@0: if (args.length == 1 && typeof args[0] === 'number') { michael@0: result = []; michael@0: result.length = args[0]; michael@0: } michael@0: return result; michael@0: } michael@0: if (obj === Boolean || obj === Number || obj === String || obj === Function) { michael@0: return obj.apply(null, args); michael@0: } michael@0: if (obj === Date) { michael@0: switch (args.length) { michael@0: case 0: michael@0: return new Date(); michael@0: case 1: michael@0: return new Date(args[0]); michael@0: default: michael@0: return new Date(args[0], args[1], args.length > 2 ? args[2] : 1, args.length > 3 ? args[3] : 0, args.length > 4 ? args[4] : 0, args.length > 5 ? args[5] : 0, args.length > 6 ? args[6] : 0); michael@0: } michael@0: } michael@0: if (obj === Object) { michael@0: return {}; michael@0: } michael@0: } michael@0: var AS2_SUPER_STUB = {}; michael@0: function interpretActions(actionsData, scopeContainer, constantPool, registers) { michael@0: var currentContext = AS2Context.instance; michael@0: function setTarget(targetPath) { michael@0: if (!targetPath) { michael@0: currentContext.defaultTarget = scope; michael@0: return; michael@0: } michael@0: try { michael@0: currentContext.defaultTarget = lookupAS2Children(targetPath, defaultTarget, _global.asGetPublicProperty('_root')); michael@0: } catch (e) { michael@0: currentContext.defaultTarget = null; michael@0: throw e; michael@0: } michael@0: } michael@0: function defineFunction(functionName, parametersNames, registersAllocation, actionsData) { michael@0: var ownerClass; michael@0: var fn = function () { michael@0: var newScope = {}; michael@0: newScope.asSetPublicProperty('this', this); michael@0: newScope.asSetPublicProperty('arguments', arguments); michael@0: newScope.asSetPublicProperty('super', AS2_SUPER_STUB); michael@0: newScope.asSetPublicProperty('__class', ownerClass); michael@0: var newScopeContainer = scopeContainer.create(newScope); michael@0: var i; michael@0: for (i = 0; i < arguments.length || i < parametersNames.length; i++) { michael@0: newScope.asSetPublicProperty(parametersNames[i], arguments[i]); michael@0: } michael@0: var registers = []; michael@0: if (registersAllocation) { michael@0: for (i = 0; i < registersAllocation.length; i++) { michael@0: var registerAllocation = registersAllocation[i]; michael@0: if (!registerAllocation) { michael@0: continue; michael@0: } michael@0: if (registerAllocation.type == 'param') { michael@0: registers[i] = arguments[registerAllocation.index]; michael@0: } else { michael@0: switch (registerAllocation.name) { michael@0: case 'this': michael@0: registers[i] = this; michael@0: break; michael@0: case 'arguments': michael@0: registers[i] = arguments; michael@0: break; michael@0: case 'super': michael@0: registers[i] = AS2_SUPER_STUB; michael@0: break; michael@0: case '_global': michael@0: registers[i] = _global; michael@0: break; michael@0: case '_parent': michael@0: registers[i] = scope.asGetPublicProperty('_parent'); michael@0: break; michael@0: case '_root': michael@0: registers[i] = _global.asGetPublicProperty('_root'); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var savedContext = AS2Context.instance; michael@0: var savedIsActive = currentContext.isActive; michael@0: try { michael@0: AS2Context.instance = currentContext; michael@0: if (!savedIsActive) { michael@0: currentContext.abortExecutionAt = Date.now() + MAX_AVM1_HANG_TIMEOUT; michael@0: currentContext.errorsIgnored = 0; michael@0: currentContext.isActive = true; michael@0: } michael@0: currentContext.defaultTarget = scope; michael@0: actionTracer.indent(); michael@0: currentContext.stackDepth++; michael@0: if (currentContext.stackDepth >= MAX_AVM1_STACK_LIMIT) { michael@0: throw new AS2CriticalError('long running script -- AVM1 recursion limit is reached'); michael@0: } michael@0: return interpretActions(actionsData, newScopeContainer, constantPool, registers); michael@0: } finally { michael@0: currentContext.isActive = savedIsActive; michael@0: currentContext.stackDepth--; michael@0: actionTracer.unindent(); michael@0: currentContext.defaultTarget = defaultTarget; michael@0: AS2Context.instance = savedContext; michael@0: } michael@0: }; michael@0: ownerClass = fn; michael@0: fn._setClass = function (class_) { michael@0: ownerClass = class_; michael@0: }; michael@0: fn.instanceConstructor = fn; michael@0: fn.debugName = 'avm1 ' + (functionName || ''); michael@0: if (functionName) { michael@0: fn.name = functionName; michael@0: } michael@0: return fn; michael@0: } michael@0: function deleteProperty(propertyName) { michael@0: for (var p = scopeContainer; p; p = p.next) { michael@0: if (p.scope.asHasProperty(undefined, propertyName, 0)) { michael@0: p.scope.asSetPublicProperty(propertyName, undefined); michael@0: return p.scope.asDeleteProperty(undefined, propertyName, 0); michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: function resolveVariableName(variableName, nonStrict) { michael@0: var obj, name, i; michael@0: if (variableName.indexOf(':') >= 0) { michael@0: var parts = variableName.split(':'); michael@0: obj = lookupAS2Children(parts[0], defaultTarget, _global.asGetPublicProperty('_root')); michael@0: if (!obj) { michael@0: throw new Error(parts[0] + ' is undefined'); michael@0: } michael@0: name = parts[1]; michael@0: } else if (variableName.indexOf('.') >= 0) { michael@0: var objPath = variableName.split('.'); michael@0: name = objPath.pop(); michael@0: obj = _global; michael@0: for (i = 0; i < objPath.length; i++) { michael@0: obj = obj.asGetPublicProperty(objPath[i]) || obj[objPath[i]]; michael@0: if (!obj) { michael@0: throw new Error(objPath.slice(0, i + 1) + ' is undefined'); michael@0: } michael@0: } michael@0: } michael@0: if (!obj) { michael@0: return null; michael@0: } michael@0: var resolvedName = as2ResolveProperty(obj, name); michael@0: var resolved = resolvedName !== null; michael@0: if (resolved || nonStrict) { michael@0: return { michael@0: obj: obj, michael@0: name: resolvedName || name, michael@0: resolved: resolved michael@0: }; michael@0: } michael@0: return null; michael@0: } michael@0: function getThis() { michael@0: var _this = scope.asGetPublicProperty('this'); michael@0: if (_this) { michael@0: return _this; michael@0: } michael@0: for (var p = scopeContainer; p; p = p.next) { michael@0: resolvedName = as2ResolveProperty(p.scope, 'this'); michael@0: if (resolvedName !== null) { michael@0: return p.scope.asGetPublicProperty(resolvedName); michael@0: } michael@0: } michael@0: } michael@0: function getVariable(variableName) { michael@0: if (scope.asHasProperty(undefined, variableName, 0)) { michael@0: return scope.asGetPublicProperty(variableName); michael@0: } michael@0: var target = resolveVariableName(variableName); michael@0: if (target) { michael@0: return target.obj.asGetPublicProperty(target.name); michael@0: } michael@0: var resolvedName, _this = getThis(); michael@0: for (var p = scopeContainer; p; p = p.next) { michael@0: resolvedName = as2ResolveProperty(p.scope, variableName); michael@0: if (resolvedName !== null) { michael@0: return p.scope.asGetPublicProperty(resolvedName); michael@0: } michael@0: } michael@0: if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) { michael@0: return _this.asGetPublicProperty(resolvedName); michael@0: } michael@0: var mc = isAS2MovieClip(defaultTarget) && defaultTarget.$lookupChild(variableName); michael@0: if (mc) { michael@0: return mc; michael@0: } michael@0: } michael@0: function setVariable(variableName, value) { michael@0: if (scope.asHasProperty(undefined, variableName, 0)) { michael@0: scope.asSetPublicProperty(variableName, value); michael@0: return; michael@0: } michael@0: var target = resolveVariableName(variableName, true); michael@0: if (target) { michael@0: target.obj.asSetPublicProperty(target.name, value); michael@0: return; michael@0: } michael@0: var resolvedName, _this = getThis(); michael@0: if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) { michael@0: return _this.asSetPublicProperty(resolvedName, value); michael@0: } michael@0: for (var p = scopeContainer; p.next; p = p.next) { michael@0: resolvedName = as2ResolveProperty(p.scope, variableName); michael@0: if (resolvedName !== null) { michael@0: return p.scope.asSetPublicProperty(resolvedName, value); michael@0: } michael@0: } michael@0: (_this || scope).asSetPublicProperty(variableName, value); michael@0: } michael@0: function getFunction(functionName) { michael@0: var fn = getVariable(functionName); michael@0: if (!(fn instanceof Function)) { michael@0: throw new Error('Function "' + functionName + '" is not found'); michael@0: } michael@0: return fn; michael@0: } michael@0: function getObjectByName(objectName) { michael@0: var obj = getVariable(objectName); michael@0: if (!(obj instanceof Object)) { michael@0: throw new Error('Object "' + objectName + '" is not found'); michael@0: } michael@0: return obj; michael@0: } michael@0: function processWith(obj, withBlock) { michael@0: var newScopeContainer = scopeContainer.create(Object(obj)); michael@0: interpretActions(withBlock, newScopeContainer, constantPool, registers); michael@0: } michael@0: function processTry(catchIsRegisterFlag, finallyBlockFlag, catchBlockFlag, catchTarget, tryBlock, catchBlock, finallyBlock) { michael@0: var savedTryCatchState = currentContext.isTryCatchListening; michael@0: try { michael@0: currentContext.isTryCatchListening = true; michael@0: interpretActions(tryBlock, scopeContainer, constantPool, registers); michael@0: } catch (e) { michael@0: currentContext.isTryCatchListening = savedTryCatchState; michael@0: if (!catchBlockFlag) { michael@0: throw e; michael@0: } michael@0: if (!(e instanceof AS2Error)) { michael@0: throw e; michael@0: } michael@0: if (typeof catchTarget === 'string') { michael@0: scope[catchTarget] = e.error; michael@0: } else { michael@0: registers[catchTarget] = e.error; michael@0: } michael@0: interpretActions(catchBlock, scopeContainer, constantPool, registers); michael@0: } finally { michael@0: currentContext.isTryCatchListening = savedTryCatchState; michael@0: if (finallyBlockFlag) { michael@0: interpretActions(finallyBlock, scopeContainer, constantPool, registers); michael@0: } michael@0: } michael@0: } michael@0: function validateArgsCount(numArgs, maxAmount) { michael@0: if (isNaN(numArgs) || numArgs < 0 || numArgs > maxAmount || numArgs != (0 | numArgs)) { michael@0: throw new Error('Invalid number of arguments: ' + numArgs); michael@0: } michael@0: } michael@0: function readArgs(stack) { michael@0: var numArgs = +stack.pop(); michael@0: validateArgsCount(numArgs, stack.length); michael@0: var args = []; michael@0: for (var i = 0; i < numArgs; i++) { michael@0: args.push(stack.pop()); michael@0: } michael@0: return args; michael@0: } michael@0: var stream = new ActionsDataStream(actionsData, currentContext.swfVersion); michael@0: var _global = currentContext.globals; michael@0: var defaultTarget = currentContext.defaultTarget; michael@0: var stack = []; michael@0: var scope = scopeContainer.scope; michael@0: var isSwfVersion5 = currentContext.swfVersion >= 5; michael@0: var actionTracer = ActionTracerFactory.get(); michael@0: var nextPosition; michael@0: if (scope.$nativeObject && scope.$nativeObject._deferScriptExecution) { michael@0: currentContext.deferScriptExecution = true; michael@0: } michael@0: function skipActions(count) { michael@0: while (count > 0 && stream.position < stream.end) { michael@0: var actionCode = stream.readUI8(); michael@0: var length = actionCode >= 128 ? stream.readUI16() : 0; michael@0: stream.position += length; michael@0: count--; michael@0: } michael@0: nextPosition = stream.position; michael@0: } michael@0: var recoveringFromError = false; michael@0: var stackItemsExpected; michael@0: while (stream.position < stream.end) { michael@0: try { michael@0: var instructionsExecuted = 0; michael@0: var abortExecutionAt = currentContext.abortExecutionAt; michael@0: while (stream.position < stream.end) { michael@0: if (instructionsExecuted++ % 100 === 0 && Date.now() >= abortExecutionAt) { michael@0: throw new AS2CriticalError('long running script -- AVM1 instruction hang timeout'); michael@0: } michael@0: var actionCode = stream.readUI8(); michael@0: var length = actionCode >= 128 ? stream.readUI16() : 0; michael@0: nextPosition = stream.position + length; michael@0: stackItemsExpected = 0; michael@0: actionTracer.print(stream.position, actionCode, stack); michael@0: var frame, type, count, index, target, method, constr, codeSize, offset; michael@0: var name, variableName, methodName, functionName, targetName; michael@0: var paramName, resolvedName, objectName; michael@0: var value, a, b, c, f, sa, sb, obj, args, fn, result, flags, i; michael@0: var dragParams, register; michael@0: switch (actionCode | 0) { michael@0: case 129: michael@0: frame = stream.readUI16(); michael@0: var nextActionCode = stream.readUI8(); michael@0: nextPosition++; michael@0: methodName = nextActionCode === 6 ? 'gotoAndPlay' : 'gotoAndStop'; michael@0: _global[methodName](frame + 1); michael@0: break; michael@0: case 131: michael@0: var urlString = stream.readString(); michael@0: var targetString = stream.readString(); michael@0: _global.getURL(urlString, targetString); michael@0: break; michael@0: case 4: michael@0: _global.nextFrame(); michael@0: break; michael@0: case 5: michael@0: _global.prevFrame(); michael@0: break; michael@0: case 6: michael@0: _global.play(); michael@0: break; michael@0: case 7: michael@0: _global.stop(); michael@0: break; michael@0: case 8: michael@0: _global.toggleHighQuality(); michael@0: break; michael@0: case 9: michael@0: _global.stopAllSounds(); michael@0: break; michael@0: case 138: michael@0: frame = stream.readUI16(); michael@0: count = stream.readUI8(); michael@0: if (!_global.ifFrameLoaded(frame)) { michael@0: skipActions(count); michael@0: } michael@0: break; michael@0: case 139: michael@0: targetName = stream.readString(); michael@0: setTarget(targetName); michael@0: break; michael@0: case 140: michael@0: var label = stream.readString(); michael@0: _global.gotoLabel(label); michael@0: break; michael@0: case 150: michael@0: while (stream.position < nextPosition) { michael@0: type = stream.readUI8(); michael@0: switch (type) { michael@0: case 0: michael@0: value = stream.readString(); michael@0: break; michael@0: case 1: michael@0: value = stream.readFloat(); michael@0: break; michael@0: case 2: michael@0: value = null; michael@0: break; michael@0: case 3: michael@0: value = void 0; michael@0: break; michael@0: case 4: michael@0: value = registers[stream.readUI8()]; michael@0: break; michael@0: case 5: michael@0: value = stream.readBoolean(); michael@0: break; michael@0: case 6: michael@0: value = stream.readDouble(); michael@0: break; michael@0: case 7: michael@0: value = stream.readInteger(); michael@0: break; michael@0: case 8: michael@0: value = constantPool[stream.readUI8()]; michael@0: break; michael@0: case 9: michael@0: value = constantPool[stream.readUI16()]; michael@0: break; michael@0: default: michael@0: throw new Error('Unknown value type: ' + type); michael@0: } michael@0: stack.push(value); michael@0: } michael@0: break; michael@0: case 23: michael@0: stack.pop(); michael@0: break; michael@0: case 10: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: stack.push(a + b); michael@0: break; michael@0: case 11: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: stack.push(b - a); michael@0: break; michael@0: case 12: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: stack.push(a * b); michael@0: break; michael@0: case 13: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: c = b / a; michael@0: stack.push(isSwfVersion5 ? c : isFinite(c) ? c : '#ERROR#'); michael@0: break; michael@0: case 14: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: f = a == b; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 15: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: f = b < a; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 16: michael@0: a = as2ToBoolean(stack.pop()); michael@0: b = as2ToBoolean(stack.pop()); michael@0: f = a && b; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 17: michael@0: a = as2ToBoolean(stack.pop()); michael@0: b = as2ToBoolean(stack.pop()); michael@0: f = a || b; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 18: michael@0: f = !as2ToBoolean(stack.pop()); michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 19: michael@0: sa = as2ToString(stack.pop()); michael@0: sb = as2ToString(stack.pop()); michael@0: f = sa == sb; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 20: michael@0: case 49: michael@0: sa = as2ToString(stack.pop()); michael@0: stack.push(_global.length(sa)); michael@0: break; michael@0: case 33: michael@0: sa = as2ToString(stack.pop()); michael@0: sb = as2ToString(stack.pop()); michael@0: stack.push(sb + sa); michael@0: break; michael@0: case 21: michael@0: count = stack.pop(); michael@0: index = stack.pop(); michael@0: value = as2ToString(stack.pop()); michael@0: stack.push(_global.substring(value, index, count)); michael@0: break; michael@0: case 53: michael@0: count = stack.pop(); michael@0: index = stack.pop(); michael@0: value = as2ToString(stack.pop()); michael@0: stack.push(_global.mbsubstring(value, index, count)); michael@0: break; michael@0: case 41: michael@0: sa = as2ToString(stack.pop()); michael@0: sb = as2ToString(stack.pop()); michael@0: f = sb < sa; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 24: michael@0: stack.push(_global.int(stack.pop())); michael@0: break; michael@0: case 50: michael@0: stack.push(_global.chr(stack.pop())); michael@0: break; michael@0: case 54: michael@0: stack.push(_global.mbchr(stack.pop())); michael@0: break; michael@0: case 51: michael@0: stack.push(_global.ord(stack.pop())); michael@0: break; michael@0: case 55: michael@0: stack.push(_global.mbord(stack.pop())); michael@0: break; michael@0: case 153: michael@0: offset = stream.readSI16(); michael@0: nextPosition += offset; michael@0: break; michael@0: case 157: michael@0: offset = stream.readSI16(); michael@0: f = !(!stack.pop()); michael@0: if (f) { michael@0: nextPosition += offset; michael@0: } michael@0: break; michael@0: case 158: michael@0: label = stack.pop(); michael@0: _global.call(label); michael@0: break; michael@0: case 28: michael@0: variableName = '' + stack.pop(); michael@0: stackItemsExpected++; michael@0: stack.push(getVariable(variableName)); michael@0: break; michael@0: case 29: michael@0: value = stack.pop(); michael@0: variableName = '' + stack.pop(); michael@0: setVariable(variableName, value); michael@0: break; michael@0: case 154: michael@0: flags = stream.readUI8(); michael@0: target = stack.pop(); michael@0: var url = stack.pop(); michael@0: var sendVarsMethod; michael@0: if (flags & 1) { michael@0: sendVarsMethod = 'GET'; michael@0: } else if (flags & 2) { michael@0: sendVarsMethod = 'POST'; michael@0: } michael@0: var loadTargetFlag = flags & 1 << 6; michael@0: if (!loadTargetFlag) { michael@0: _global.getURL(url, target, sendVarsMethod); michael@0: break; michael@0: } michael@0: var loadVariablesFlag = flags & 1 << 7; michael@0: if (loadVariablesFlag) { michael@0: _global.loadVariables(url, target, sendVarsMethod); michael@0: } else { michael@0: _global.loadMovie(url, target, sendVarsMethod); michael@0: } michael@0: break; michael@0: case 159: michael@0: flags = stream.readUI8(); michael@0: var gotoParams = [ michael@0: stack.pop() michael@0: ]; michael@0: if (!(!(flags & 2))) { michael@0: gotoParams.push(stream.readUI16()); michael@0: } michael@0: var gotoMethod = !(!(flags & 1)) ? _global.gotoAndPlay : _global.gotoAndStop; michael@0: gotoMethod.apply(_global, gotoParams); michael@0: break; michael@0: case 32: michael@0: target = stack.pop(); michael@0: setTarget(target); michael@0: break; michael@0: case 34: michael@0: index = stack.pop(); michael@0: target = stack.pop(); michael@0: stackItemsExpected++; michael@0: stack.push(_global.getAS2Property(target, index)); michael@0: break; michael@0: case 35: michael@0: value = stack.pop(); michael@0: index = stack.pop(); michael@0: target = stack.pop(); michael@0: _global.setAS2Property(target, index, value); michael@0: break; michael@0: case 36: michael@0: var depth = stack.pop(); michael@0: target = stack.pop(); michael@0: var source = stack.pop(); michael@0: _global.duplicateMovieClip(source, target, depth); michael@0: break; michael@0: case 37: michael@0: target = stack.pop(); michael@0: _global.removeMovieClip(target); michael@0: break; michael@0: case 39: michael@0: target = stack.pop(); michael@0: var lockcenter = stack.pop(); michael@0: var constrain = !stack.pop() ? null : { michael@0: y2: stack.pop(), michael@0: x2: stack.pop(), michael@0: y1: stack.pop(), michael@0: x1: stack.pop() michael@0: }; michael@0: dragParams = [ michael@0: target, michael@0: lockcenter michael@0: ]; michael@0: if (constrain) { michael@0: dragParams = dragParams.push(constrain.x1, constrain.y1, constrain.x2, constrain.y2); michael@0: } michael@0: _global.startDrag.apply(_global, dragParams); michael@0: break; michael@0: case 40: michael@0: _global.stopDrag(); michael@0: break; michael@0: case 141: michael@0: count = stream.readUI8(); michael@0: frame = stack.pop(); michael@0: if (!_global.ifFrameLoaded(frame)) { michael@0: skipActions(count); michael@0: } michael@0: break; michael@0: case 38: michael@0: value = stack.pop(); michael@0: _global.trace(value); michael@0: break; michael@0: case 52: michael@0: stack.push(_global.getTimer()); michael@0: break; michael@0: case 48: michael@0: stack.push(_global.random(stack.pop())); michael@0: break; michael@0: case 61: michael@0: functionName = stack.pop(); michael@0: args = readArgs(stack); michael@0: stackItemsExpected++; michael@0: fn = getFunction(functionName); michael@0: result = fn.apply(scope, args); michael@0: stack.push(result); michael@0: break; michael@0: case 82: michael@0: methodName = stack.pop(); michael@0: obj = stack.pop(); michael@0: args = readArgs(stack); michael@0: stackItemsExpected++; michael@0: if (methodName !== null && methodName !== undefined && methodName !== '') { michael@0: if (obj === null || obj === undefined) { michael@0: throw new Error('Cannot call method ' + methodName + ' of ' + typeof obj); michael@0: } else if (obj !== AS2_SUPER_STUB) { michael@0: target = Object(obj); michael@0: } else { michael@0: target = as2GetPrototype(getVariable('__class').__super); michael@0: obj = getVariable('this'); michael@0: } michael@0: resolvedName = as2ResolveProperty(target, methodName); michael@0: if (resolvedName === null) { michael@0: throw new Error('Method ' + methodName + ' is not defined.'); michael@0: } michael@0: result = target.asGetPublicProperty(resolvedName).apply(obj, args); michael@0: } else if (obj !== AS2_SUPER_STUB) { michael@0: result = obj.apply(obj, args); michael@0: } else { michael@0: result = getVariable('__class').__super.apply(getVariable('this'), args); michael@0: } michael@0: stack.push(result); michael@0: break; michael@0: case 136: michael@0: count = stream.readUI16(); michael@0: constantPool = []; michael@0: for (i = 0; i < count; i++) { michael@0: constantPool.push(stream.readString()); michael@0: } michael@0: break; michael@0: case 155: michael@0: functionName = stream.readString(); michael@0: count = stream.readUI16(); michael@0: args = []; michael@0: for (i = 0; i < count; i++) { michael@0: args.push(stream.readString()); michael@0: } michael@0: codeSize = stream.readUI16(); michael@0: nextPosition += codeSize; michael@0: fn = defineFunction(functionName, args, null, stream.readBytes(codeSize)); michael@0: if (functionName) { michael@0: scope.asSetPublicProperty(functionName, fn); michael@0: } else { michael@0: stack.push(fn); michael@0: } michael@0: break; michael@0: case 60: michael@0: value = stack.pop(); michael@0: name = stack.pop(); michael@0: scope.asSetPublicProperty(name, value); michael@0: break; michael@0: case 65: michael@0: name = stack.pop(); michael@0: scope.asSetPublicProperty(name, undefined); michael@0: break; michael@0: case 58: michael@0: name = stack.pop(); michael@0: obj = stack.pop(); michael@0: obj.asSetPublicProperty(name, undefined); michael@0: stack.push(obj.asDeleteProperty(undefined, name, 0)); michael@0: break; michael@0: case 59: michael@0: name = stack.pop(); michael@0: result = deleteProperty(name); michael@0: stack.push(result); michael@0: break; michael@0: case 70: michael@0: objectName = stack.pop(); michael@0: stack.push(null); michael@0: obj = getObjectByName(objectName); michael@0: forEachPublicProperty(obj, function (name) { michael@0: stack.push(name); michael@0: }); michael@0: break; michael@0: case 73: michael@0: a = stack.pop(); michael@0: b = stack.pop(); michael@0: stack.push(a == b); michael@0: break; michael@0: case 78: michael@0: name = stack.pop(); michael@0: obj = stack.pop(); michael@0: if (name === 'prototype') { michael@0: stack.push(as2CreatePrototypeProxy(obj)); michael@0: } else { michael@0: resolvedName = as2ResolveProperty(Object(obj), name); michael@0: stack.push(resolvedName === null ? undefined : obj.asGetPublicProperty(resolvedName)); michael@0: } michael@0: break; michael@0: case 66: michael@0: obj = readArgs(stack); michael@0: stack.push(obj); michael@0: break; michael@0: case 67: michael@0: count = +stack.pop(); michael@0: validateArgsCount(count, stack.length >> 1); michael@0: obj = {}; michael@0: for (i = 0; i < count; i++) { michael@0: value = stack.pop(); michael@0: name = stack.pop(); michael@0: obj.asSetPublicProperty(name, value); michael@0: } michael@0: stack.push(obj); michael@0: break; michael@0: case 83: michael@0: methodName = stack.pop(); michael@0: obj = stack.pop(); michael@0: args = readArgs(stack); michael@0: stackItemsExpected++; michael@0: if (methodName !== null && methodName !== undefined && methodName !== '') { michael@0: resolvedName = as2ResolveProperty(obj, methodName); michael@0: if (resolvedName === null) { michael@0: throw new Error('Method ' + methodName + ' is not defined.'); michael@0: } michael@0: if (obj === null || obj === undefined) { michael@0: throw new Error('Cannot call new using method ' + resolvedName + ' of ' + typeof obj); michael@0: } michael@0: method = obj.asGetPublicProperty(resolvedName); michael@0: } else { michael@0: if (obj === null || obj === undefined) { michael@0: throw new Error('Cannot call new using ' + typeof obj); michael@0: } michael@0: method = obj; michael@0: } michael@0: if (isAvm2Class(obj)) { michael@0: result = construct(obj, args); michael@0: } else { michael@0: result = Object.create(as2GetPrototype(method) || as2GetPrototype(Object)); michael@0: method.apply(result, args); michael@0: } michael@0: result.constructor = method; michael@0: stack.push(result); michael@0: break; michael@0: case 64: michael@0: objectName = stack.pop(); michael@0: obj = getObjectByName(objectName); michael@0: args = readArgs(stack); michael@0: stackItemsExpected++; michael@0: result = createBuiltinType(obj, args); michael@0: if (typeof result === 'undefined') { michael@0: if (isAvm2Class(obj)) { michael@0: result = construct(obj, args); michael@0: } else { michael@0: result = Object.create(as2GetPrototype(obj) || as2GetPrototype(Object)); michael@0: obj.apply(result, args); michael@0: } michael@0: result.constructor = obj; michael@0: } michael@0: stack.push(result); michael@0: break; michael@0: case 79: michael@0: value = stack.pop(); michael@0: name = stack.pop(); michael@0: obj = stack.pop(); michael@0: obj.asSetPublicProperty(name, value); michael@0: break; michael@0: case 69: michael@0: obj = stack.pop(); michael@0: stack.push(as2GetType(obj) === 'movieclip' ? obj._target : void 0); michael@0: break; michael@0: case 148: michael@0: codeSize = stream.readUI16(); michael@0: obj = stack.pop(); michael@0: nextPosition += codeSize; michael@0: processWith(obj, stream.readBytes(codeSize)); michael@0: break; michael@0: case 74: michael@0: stack.push(as2ToNumber(stack.pop())); michael@0: break; michael@0: case 75: michael@0: stack.push(as2ToString(stack.pop())); michael@0: break; michael@0: case 68: michael@0: obj = stack.pop(); michael@0: result = as2GetType(obj); michael@0: stack.push(result); michael@0: break; michael@0: case 71: michael@0: a = as2ToAddPrimitive(stack.pop()); michael@0: b = as2ToAddPrimitive(stack.pop()); michael@0: if (typeof a === 'string' || typeof b === 'string') { michael@0: stack.push(as2ToString(b) + as2ToString(a)); michael@0: } else { michael@0: stack.push(as2ToNumber(b) + as2ToNumber(a)); michael@0: } michael@0: break; michael@0: case 72: michael@0: a = stack.pop(); michael@0: b = stack.pop(); michael@0: stack.push(as2Compare(b, a)); michael@0: break; michael@0: case 63: michael@0: a = as2ToNumber(stack.pop()); michael@0: b = as2ToNumber(stack.pop()); michael@0: stack.push(b % a); michael@0: break; michael@0: case 96: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b & a); michael@0: break; michael@0: case 99: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b << a); michael@0: break; michael@0: case 97: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b | a); michael@0: break; michael@0: case 100: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b >> a); michael@0: break; michael@0: case 101: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b >>> a); michael@0: break; michael@0: case 98: michael@0: a = as2ToInt32(stack.pop()); michael@0: b = as2ToInt32(stack.pop()); michael@0: stack.push(b ^ a); michael@0: break; michael@0: case 81: michael@0: a = as2ToNumber(stack.pop()); michael@0: a--; michael@0: stack.push(a); michael@0: break; michael@0: case 80: michael@0: a = as2ToNumber(stack.pop()); michael@0: a++; michael@0: stack.push(a); michael@0: break; michael@0: case 76: michael@0: stack.push(stack[stack.length - 1]); michael@0: break; michael@0: case 62: michael@0: return stack.pop(); michael@0: case 77: michael@0: stack.push(stack.pop(), stack.pop()); michael@0: break; michael@0: case 135: michael@0: register = stream.readUI8(); michael@0: registers[register] = stack[stack.length - 1]; michael@0: break; michael@0: case 84: michael@0: constr = stack.pop(); michael@0: obj = stack.pop(); michael@0: stack.push(as2InstanceOf(Object(obj), constr)); michael@0: break; michael@0: case 85: michael@0: obj = stack.pop(); michael@0: stack.push(null); michael@0: forEachPublicProperty(obj, function (name) { michael@0: stack.push(name); michael@0: }); michael@0: break; michael@0: case 102: michael@0: a = stack.pop(); michael@0: b = stack.pop(); michael@0: stack.push(b === a); michael@0: break; michael@0: case 103: michael@0: a = stack.pop(); michael@0: b = stack.pop(); michael@0: stack.push(as2Compare(a, b)); michael@0: break; michael@0: case 104: michael@0: sa = as2ToString(stack.pop()); michael@0: sb = as2ToString(stack.pop()); michael@0: f = sb > sa; michael@0: stack.push(isSwfVersion5 ? f : f ? 1 : 0); michael@0: break; michael@0: case 142: michael@0: functionName = stream.readString(); michael@0: count = stream.readUI16(); michael@0: var registerCount = stream.readUI8(); michael@0: flags = stream.readUI16(); michael@0: var registerAllocation = []; michael@0: args = []; michael@0: for (i = 0; i < count; i++) { michael@0: register = stream.readUI8(); michael@0: paramName = stream.readString(); michael@0: args.push(paramName); michael@0: if (register) { michael@0: registerAllocation[register] = { michael@0: type: 'param', michael@0: name: paramName, michael@0: index: i michael@0: }; michael@0: } michael@0: } michael@0: codeSize = stream.readUI16(); michael@0: nextPosition += codeSize; michael@0: var j = 1; michael@0: if (flags & 1) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: 'this' michael@0: }; michael@0: } michael@0: if (flags & 4) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: 'arguments' michael@0: }; michael@0: } michael@0: if (flags & 16) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: 'super' michael@0: }; michael@0: } michael@0: if (flags & 64) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: '_root' michael@0: }; michael@0: } michael@0: if (flags & 128) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: '_parent' michael@0: }; michael@0: } michael@0: if (flags & 256) { michael@0: registerAllocation[j++] = { michael@0: type: 'var', michael@0: name: '_global' michael@0: }; michael@0: } michael@0: fn = defineFunction(functionName, args, registerAllocation, stream.readBytes(codeSize)); michael@0: if (functionName) { michael@0: scope.asSetPublicProperty(functionName, fn); michael@0: } else { michael@0: stack.push(fn); michael@0: } michael@0: break; michael@0: case 105: michael@0: var constrSuper = stack.pop(); michael@0: constr = stack.pop(); michael@0: obj = Object.create(constrSuper.traitsPrototype || as2GetPrototype(constrSuper), { michael@0: constructor: { michael@0: value: constr, michael@0: enumerable: false michael@0: } michael@0: }); michael@0: constr.__super = constrSuper; michael@0: constr.prototype = obj; michael@0: break; michael@0: case 43: michael@0: obj = stack.pop(); michael@0: constr = stack.pop(); michael@0: stack.push(as2InstanceOf(obj, constr) ? obj : null); michael@0: break; michael@0: case 44: michael@0: constr = stack.pop(); michael@0: count = +stack.pop(); michael@0: validateArgsCount(count, stack.length); michael@0: var interfaces = []; michael@0: for (i = 0; i < count; i++) { michael@0: interfaces.push(stack.pop()); michael@0: } michael@0: constr.$interfaces = interfaces; michael@0: break; michael@0: case 143: michael@0: flags = stream.readUI8(); michael@0: var catchIsRegisterFlag = !(!(flags & 4)); michael@0: var finallyBlockFlag = !(!(flags & 2)); michael@0: var catchBlockFlag = !(!(flags & 1)); michael@0: var trySize = stream.readUI16(); michael@0: var catchSize = stream.readUI16(); michael@0: var finallySize = stream.readUI16(); michael@0: var catchTarget = catchIsRegisterFlag ? stream.readUI8() : stream.readString(); michael@0: nextPosition += trySize + catchSize + finallySize; michael@0: processTry(catchIsRegisterFlag, finallyBlockFlag, catchBlockFlag, catchTarget, stream.readBytes(trySize), stream.readBytes(catchSize), stream.readBytes(finallySize)); michael@0: break; michael@0: case 42: michael@0: obj = stack.pop(); michael@0: throw new AS2Error(obj); michael@0: case 45: michael@0: args = readArgs(stack); michael@0: stackItemsExpected++; michael@0: result = _global.fscommand.apply(null, args); michael@0: stack.push(result); michael@0: break; michael@0: case 137: michael@0: var mode = stream.readUI8(); michael@0: break; michael@0: case 0: michael@0: return; michael@0: default: michael@0: throw new Error('Unknown action code: ' + actionCode); michael@0: } michael@0: stream.position = nextPosition; michael@0: recoveringFromError = false; michael@0: } michael@0: } catch (e) { michael@0: if (!AVM1_ERRORS_IGNORED && !currentContext.isTryCatchListening || e instanceof AS2CriticalError) { michael@0: throw e; michael@0: } michael@0: if (e instanceof AS2Error) { michael@0: throw e; michael@0: } michael@0: var AVM1_ERROR_TYPE = 1; michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'error', michael@0: error: AVM1_ERROR_TYPE michael@0: }); michael@0: stream.position = nextPosition; michael@0: if (stackItemsExpected > 0) { michael@0: while (stackItemsExpected--) { michael@0: stack.push(undefined); michael@0: } michael@0: } michael@0: if (!recoveringFromError) { michael@0: if (currentContext.errorsIgnored++ >= MAX_AVM1_ERRORS_LIMIT) { michael@0: throw new AS2CriticalError('long running script -- AVM1 errors limit is reached'); michael@0: } michael@0: console.error('AVM1 error: ' + e); michael@0: avm2.exceptions.push({ michael@0: source: 'avm1', michael@0: message: e.message, michael@0: stack: e.stack michael@0: }); michael@0: recoveringFromError = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var ActionTracerFactory = function () { michael@0: var indentation = 0; michael@0: var tracer = { michael@0: print: function (position, actionCode, stack) { michael@0: var stackDump = []; michael@0: for (var q = 0; q < stack.length; q++) { michael@0: var item = stack[q]; michael@0: stackDump.push(item && typeof item === 'object' ? '[' + (item.constructor && item.constructor.name ? item.constructor.name : 'Object') + ']' : item); michael@0: } michael@0: var indent = new Array(indentation + 1).join('..'); michael@0: console.log('AVM1 trace: ' + indent + position + ': ' + ActionNamesMap[actionCode] + '(' + actionCode.toString(16) + '), ' + 'stack=' + stackDump); michael@0: }, michael@0: indent: function () { michael@0: indentation++; michael@0: }, michael@0: unindent: function () { michael@0: indentation--; michael@0: }, michael@0: message: function (str) { michael@0: console.log('AVM1 trace: ------- ' + str); michael@0: } michael@0: }; michael@0: var nullTracer = { michael@0: print: function () { michael@0: }, michael@0: indent: function () { michael@0: }, michael@0: unindent: function () { michael@0: }, michael@0: message: function () { michael@0: } michael@0: }; michael@0: function ActionTracerFactory() { michael@0: } michael@0: ActionTracerFactory.get = function () { michael@0: return AVM1_TRACE_ENABLED ? tracer : nullTracer; michael@0: }; michael@0: return ActionTracerFactory; michael@0: }(); michael@0: var ActionNamesMap = { michael@0: 0: 'EOA', michael@0: 4: 'ActionNextFrame', michael@0: 5: 'ActionPreviousFrame', michael@0: 6: 'ActionPlay', michael@0: 7: 'ActionStop', michael@0: 8: 'ActionToggleQuality', michael@0: 9: 'ActionStopSounds', michael@0: 10: 'ActionAdd', michael@0: 11: 'ActionSubtract', michael@0: 12: 'ActionMultiply', michael@0: 13: 'ActionDivide', michael@0: 14: 'ActionEquals', michael@0: 15: 'ActionLess', michael@0: 16: 'ActionAnd', michael@0: 17: 'ActionOr', michael@0: 18: 'ActionNot', michael@0: 19: 'ActionStringEquals', michael@0: 20: 'ActionStringLength', michael@0: 21: 'ActionStringExtract', michael@0: 23: 'ActionPop', michael@0: 24: 'ActionToInteger', michael@0: 28: 'ActionGetVariable', michael@0: 29: 'ActionSetVariable', michael@0: 32: 'ActionSetTarget2', michael@0: 33: 'ActionStringAdd', michael@0: 34: 'ActionGetProperty', michael@0: 35: 'ActionSetProperty', michael@0: 36: 'ActionCloneSprite', michael@0: 37: 'ActionRemoveSprite', michael@0: 38: 'ActionTrace', michael@0: 39: 'ActionStartDrag', michael@0: 40: 'ActionEndDrag', michael@0: 41: 'ActionStringLess', michael@0: 42: 'ActionThrow', michael@0: 43: 'ActionCastOp', michael@0: 44: 'ActionImplementsOp', michael@0: 45: 'ActionFSCommand2', michael@0: 48: 'ActionRandomNumber', michael@0: 49: 'ActionMBStringLength', michael@0: 50: 'ActionCharToAscii', michael@0: 51: 'ActionAsciiToChar', michael@0: 52: 'ActionGetTime', michael@0: 53: 'ActionMBStringExtrac', michael@0: 54: 'ActionMBCharToAscii', michael@0: 55: 'ActionMBAsciiToChar', michael@0: 58: 'ActionDelete', michael@0: 59: 'ActionDelete2', michael@0: 60: 'ActionDefineLocal', michael@0: 61: 'ActionCallFunction', michael@0: 62: 'ActionReturn', michael@0: 63: 'ActionModulo', michael@0: 64: 'ActionNewObject', michael@0: 65: 'ActionDefineLocal2', michael@0: 66: 'ActionInitArray', michael@0: 67: 'ActionInitObject', michael@0: 68: 'ActionTypeOf', michael@0: 69: 'ActionTargetPath', michael@0: 70: 'ActionEnumerate', michael@0: 71: 'ActionAdd2', michael@0: 72: 'ActionLess2', michael@0: 73: 'ActionEquals2', michael@0: 74: 'ActionToNumber', michael@0: 75: 'ActionToString', michael@0: 76: 'ActionPushDuplicate', michael@0: 77: 'ActionStackSwap', michael@0: 78: 'ActionGetMember', michael@0: 79: 'ActionSetMember', michael@0: 80: 'ActionIncrement', michael@0: 81: 'ActionDecrement', michael@0: 82: 'ActionCallMethod', michael@0: 83: 'ActionNewMethod', michael@0: 84: 'ActionInstanceOf', michael@0: 85: 'ActionEnumerate2', michael@0: 96: 'ActionBitAnd', michael@0: 97: 'ActionBitOr', michael@0: 98: 'ActionBitXor', michael@0: 99: 'ActionBitLShift', michael@0: 100: 'ActionBitRShift', michael@0: 101: 'ActionBitURShift', michael@0: 102: 'ActionStrictEquals', michael@0: 103: 'ActionGreater', michael@0: 104: 'ActionStringGreater', michael@0: 105: 'ActionExtends', michael@0: 129: 'ActionGotoFrame', michael@0: 131: 'ActionGetURL', michael@0: 135: 'ActionStoreRegister', michael@0: 136: 'ActionConstantPool', michael@0: 137: 'ActionStrictMode', michael@0: 138: 'ActionWaitForFrame', michael@0: 139: 'ActionSetTarget', michael@0: 140: 'ActionGoToLabel', michael@0: 141: 'ActionWaitForFrame2', michael@0: 142: 'ActionDefineFunction', michael@0: 143: 'ActionTry', michael@0: 148: 'ActionWith', michael@0: 150: 'ActionPush', michael@0: 153: 'ActionJump', michael@0: 154: 'ActionGetURL2', michael@0: 155: 'ActionDefineFunction', michael@0: 157: 'ActionIf', michael@0: 158: 'ActionCall', michael@0: 159: 'ActionGotoFrame2' michael@0: }; michael@0: if (typeof GLOBAL !== 'undefined') { michael@0: GLOBAL.createBuiltinType = createBuiltinType; michael@0: GLOBAL.executeActions = executeActions; michael@0: GLOBAL.AS2Context = AS2Context; michael@0: } michael@0: var jsGlobal = function () { michael@0: return this || (1, eval)('this'); michael@0: }(); michael@0: var inBrowser = typeof console != 'undefined'; michael@0: var release = true; michael@0: var debug = !true; michael@0: if (!jsGlobal.performance) { michael@0: jsGlobal.performance = {}; michael@0: } michael@0: if (!jsGlobal.performance.now) { michael@0: jsGlobal.performance.now = dateNow; michael@0: } michael@0: function log(message) { michael@0: var optionalParams = []; michael@0: for (var _i = 0; _i < arguments.length - 1; _i++) { michael@0: optionalParams[_i] = arguments[_i + 1]; michael@0: } michael@0: jsGlobal.print(message); michael@0: } michael@0: function warn(message) { michael@0: var optionalParams = []; michael@0: for (var _i = 0; _i < arguments.length - 1; _i++) { michael@0: optionalParams[_i] = arguments[_i + 1]; michael@0: } michael@0: if (inBrowser) { michael@0: console.warn(message); michael@0: } else { michael@0: jsGlobal.print(message); michael@0: } michael@0: } michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (CharacterCodes) { michael@0: CharacterCodes[CharacterCodes['_0'] = 48] = '_0'; michael@0: CharacterCodes[CharacterCodes['_1'] = 49] = '_1'; michael@0: CharacterCodes[CharacterCodes['_2'] = 50] = '_2'; michael@0: CharacterCodes[CharacterCodes['_3'] = 51] = '_3'; michael@0: CharacterCodes[CharacterCodes['_4'] = 52] = '_4'; michael@0: CharacterCodes[CharacterCodes['_5'] = 53] = '_5'; michael@0: CharacterCodes[CharacterCodes['_6'] = 54] = '_6'; michael@0: CharacterCodes[CharacterCodes['_7'] = 55] = '_7'; michael@0: CharacterCodes[CharacterCodes['_8'] = 56] = '_8'; michael@0: CharacterCodes[CharacterCodes['_9'] = 57] = '_9'; michael@0: }(Shumway.CharacterCodes || (Shumway.CharacterCodes = {}))); michael@0: var CharacterCodes = Shumway.CharacterCodes; michael@0: Shumway.UINT32_CHAR_BUFFER_LENGTH = 10; michael@0: Shumway.UINT32_MAX = 4294967295; michael@0: Shumway.UINT32_MAX_DIV_10 = 429496729; michael@0: Shumway.UINT32_MAX_MOD_10 = 5; michael@0: function isString(value) { michael@0: return typeof value === 'string'; michael@0: } michael@0: Shumway.isString = isString; michael@0: function isFunction(value) { michael@0: return typeof value === 'function'; michael@0: } michael@0: Shumway.isFunction = isFunction; michael@0: function isNumber(value) { michael@0: return typeof value === 'number'; michael@0: } michael@0: Shumway.isNumber = isNumber; michael@0: function isNumberOrString(value) { michael@0: return typeof value === 'number' || typeof value === 'string'; michael@0: } michael@0: Shumway.isNumberOrString = isNumberOrString; michael@0: function isObject(value) { michael@0: return typeof value === 'object' || typeof value === 'function'; michael@0: } michael@0: Shumway.isObject = isObject; michael@0: function toNumber(x) { michael@0: return +x; michael@0: } michael@0: Shumway.toNumber = toNumber; michael@0: function isNumericString(value) { michael@0: return String(Number(value)) === value; michael@0: } michael@0: Shumway.isNumericString = isNumericString; michael@0: function isNumeric(value) { michael@0: if (typeof value === 'number') { michael@0: return true; michael@0: } else if (typeof value === 'string') { michael@0: return isIndex(value) || isNumericString(value); michael@0: } else { michael@0: Debug.notImplemented(typeof value); michael@0: } michael@0: } michael@0: Shumway.isNumeric = isNumeric; michael@0: function isIndex(value) { michael@0: var index = 0; michael@0: if (typeof value === 'number') { michael@0: index = value | 0; michael@0: if (value === index && index >= 0) { michael@0: return true; michael@0: } michael@0: return value >>> 0 === value; michael@0: } michael@0: if (typeof value !== 'string') { michael@0: return false; michael@0: } michael@0: var length = value.length; michael@0: if (length === 0) { michael@0: return false; michael@0: } michael@0: if (value === '0') { michael@0: return true; michael@0: } michael@0: if (length > Shumway.UINT32_CHAR_BUFFER_LENGTH) { michael@0: return false; michael@0: } michael@0: var i = 0; michael@0: index = value.charCodeAt(i++) - 48; michael@0: if (index < 1 || index > 9) { michael@0: return false; michael@0: } michael@0: var oldIndex = 0; michael@0: var c = 0; michael@0: while (i < length) { michael@0: c = value.charCodeAt(i++) - 48; michael@0: if (c < 0 || c > 9) { michael@0: return false; michael@0: } michael@0: oldIndex = index; michael@0: index = 10 * index + c; michael@0: } michael@0: if (oldIndex < Shumway.UINT32_MAX_DIV_10 || oldIndex === Shumway.UINT32_MAX_DIV_10 && c <= Shumway.UINT32_MAX_MOD_10) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: Shumway.isIndex = isIndex; michael@0: function isNullOrUndefined(value) { michael@0: return value == undefined; michael@0: } michael@0: Shumway.isNullOrUndefined = isNullOrUndefined; michael@0: (function (Debug) { michael@0: function backtrace() { michael@0: try { michael@0: throw new Error(); michael@0: } catch (e) { michael@0: return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; michael@0: } michael@0: } michael@0: Debug.backtrace = backtrace; michael@0: function error(message) { michael@0: if (!inBrowser) { michael@0: warn(Debug.backtrace()); michael@0: } michael@0: throw new Error(message); michael@0: } michael@0: Debug.error = error; michael@0: function assert(condition) { michael@0: var args = []; michael@0: for (var _i = 0; _i < arguments.length - 1; _i++) { michael@0: args[_i] = arguments[_i + 1]; michael@0: } michael@0: if (condition === '') { michael@0: condition = true; michael@0: } michael@0: if (!condition) { michael@0: var message = Array.prototype.slice.call(arguments); michael@0: message.shift(); michael@0: Debug.error(message.join('')); michael@0: } michael@0: } michael@0: Debug.assert = assert; michael@0: function assertNotImplemented(condition, message) { michael@0: if (!condition) { michael@0: Debug.error('NotImplemented: ' + message); michael@0: } michael@0: } michael@0: Debug.assertNotImplemented = assertNotImplemented; michael@0: function warning(message) { michael@0: true; michael@0: } michael@0: Debug.warning = warning; michael@0: function notUsed(message) { michael@0: true; michael@0: } michael@0: Debug.notUsed = notUsed; michael@0: function notImplemented(message) { michael@0: true; michael@0: } michael@0: Debug.notImplemented = notImplemented; michael@0: function somewhatImplemented(message) { michael@0: Debug.warning('somewhatImplemented: ' + message); michael@0: } michael@0: Debug.somewhatImplemented = somewhatImplemented; michael@0: function unexpected(message) { michael@0: Debug.assert(false, 'Unexpected: ' + message); michael@0: } michael@0: Debug.unexpected = unexpected; michael@0: }(Shumway.Debug || (Shumway.Debug = {}))); michael@0: var Debug = Shumway.Debug; michael@0: function getTicks() { michael@0: return performance.now(); michael@0: } michael@0: Shumway.getTicks = getTicks; michael@0: (function (ArrayUtilities) { michael@0: function popManyInto(src, count, dst) { michael@0: true; michael@0: for (var i = count - 1; i >= 0; i--) { michael@0: dst[i] = src.pop(); michael@0: } michael@0: dst.length = count; michael@0: } michael@0: ArrayUtilities.popManyInto = popManyInto; michael@0: }(Shumway.ArrayUtilities || (Shumway.ArrayUtilities = {}))); michael@0: var ArrayUtilities = Shumway.ArrayUtilities; michael@0: (function (ObjectUtilities) { michael@0: function boxValue(value) { michael@0: if (Shumway.isNullOrUndefined(value) || Shumway.isObject(value)) { michael@0: return value; michael@0: } michael@0: return Object(value); michael@0: } michael@0: ObjectUtilities.boxValue = boxValue; michael@0: function toKeyValueArray(object) { michael@0: var hasOwnProperty = Object.prototype.hasOwnProperty; michael@0: var array = []; michael@0: for (var k in object) { michael@0: if (hasOwnProperty.call(object, k)) { michael@0: array.push([ michael@0: k, michael@0: object[k] michael@0: ]); michael@0: } michael@0: } michael@0: return array; michael@0: } michael@0: ObjectUtilities.toKeyValueArray = toKeyValueArray; michael@0: function hasOwnProperty(object, name) { michael@0: return Object.prototype.hasOwnProperty.call(object, name); michael@0: } michael@0: ObjectUtilities.hasOwnProperty = hasOwnProperty; michael@0: function createEmptyObject() { michael@0: return Object.create(null); michael@0: } michael@0: ObjectUtilities.createEmptyObject = createEmptyObject; michael@0: function createMap() { michael@0: return Object.create(null); michael@0: } michael@0: ObjectUtilities.createMap = createMap; michael@0: function createArrayMap() { michael@0: return []; michael@0: } michael@0: ObjectUtilities.createArrayMap = createArrayMap; michael@0: function defineReadOnlyProperty(object, name, value) { michael@0: Object.defineProperty(object, name, { michael@0: value: value, michael@0: writable: false, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: ObjectUtilities.defineReadOnlyProperty = defineReadOnlyProperty; michael@0: function getOwnPropertyDescriptors(object) { michael@0: var o = ObjectUtilities.createMap(); michael@0: var properties = Object.getOwnPropertyNames(object); michael@0: for (var i = 0; i < properties.length; i++) { michael@0: o[properties[i]] = Object.getOwnPropertyDescriptor(object, properties[i]); michael@0: } michael@0: return o; michael@0: } michael@0: ObjectUtilities.getOwnPropertyDescriptors = getOwnPropertyDescriptors; michael@0: function cloneObject(object) { michael@0: var clone = ObjectUtilities.createEmptyObject(); michael@0: for (var property in object) { michael@0: clone[property] = object[property]; michael@0: } michael@0: return clone; michael@0: } michael@0: ObjectUtilities.cloneObject = cloneObject; michael@0: function copyProperties(object, template) { michael@0: for (var property in template) { michael@0: object[property] = template[property]; michael@0: } michael@0: } michael@0: ObjectUtilities.copyProperties = copyProperties; michael@0: function getLatestGetterOrSetterPropertyDescriptor(object, name) { michael@0: var descriptor = {}; michael@0: while (object) { michael@0: var tmp = Object.getOwnPropertyDescriptor(object, name); michael@0: if (tmp) { michael@0: descriptor.get = descriptor.get || tmp.get; michael@0: descriptor.set = descriptor.set || tmp.set; michael@0: } michael@0: if (descriptor.get && descriptor.set) { michael@0: break; michael@0: } michael@0: object = Object.getPrototypeOf(object); michael@0: } michael@0: return descriptor; michael@0: } michael@0: ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor = getLatestGetterOrSetterPropertyDescriptor; michael@0: function defineNonEnumerableGetterOrSetter(obj, name, value, isGetter) { michael@0: var descriptor = ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor(obj, name); michael@0: descriptor.configurable = true; michael@0: descriptor.enumerable = false; michael@0: if (isGetter) { michael@0: descriptor.get = value; michael@0: } else { michael@0: descriptor.set = value; michael@0: } michael@0: Object.defineProperty(obj, name, descriptor); michael@0: } michael@0: ObjectUtilities.defineNonEnumerableGetterOrSetter = defineNonEnumerableGetterOrSetter; michael@0: function defineNonEnumerableGetter(obj, name, getter) { michael@0: Object.defineProperty(obj, name, { michael@0: get: getter, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: ObjectUtilities.defineNonEnumerableGetter = defineNonEnumerableGetter; michael@0: function defineNonEnumerableSetter(obj, name, setter) { michael@0: Object.defineProperty(obj, name, { michael@0: set: setter, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: ObjectUtilities.defineNonEnumerableSetter = defineNonEnumerableSetter; michael@0: function defineNonEnumerableProperty(obj, name, value) { michael@0: Object.defineProperty(obj, name, { michael@0: value: value, michael@0: writable: true, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: ObjectUtilities.defineNonEnumerableProperty = defineNonEnumerableProperty; michael@0: function defineNonEnumerableForwardingProperty(obj, name, otherName) { michael@0: Object.defineProperty(obj, name, { michael@0: get: FunctionUtilities.makeForwardingGetter(otherName), michael@0: set: FunctionUtilities.makeForwardingSetter(otherName), michael@0: writable: true, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: ObjectUtilities.defineNonEnumerableForwardingProperty = defineNonEnumerableForwardingProperty; michael@0: function defineNewNonEnumerableProperty(obj, name, value) { michael@0: true; michael@0: ObjectUtilities.defineNonEnumerableProperty(obj, name, value); michael@0: } michael@0: ObjectUtilities.defineNewNonEnumerableProperty = defineNewNonEnumerableProperty; michael@0: }(Shumway.ObjectUtilities || (Shumway.ObjectUtilities = {}))); michael@0: var ObjectUtilities = Shumway.ObjectUtilities; michael@0: (function (FunctionUtilities) { michael@0: function makeForwardingGetter(target) { michael@0: return new Function('return this["' + target + '"]'); michael@0: } michael@0: FunctionUtilities.makeForwardingGetter = makeForwardingGetter; michael@0: function makeForwardingSetter(target) { michael@0: return new Function('value', 'this["' + target + '"] = value;'); michael@0: } michael@0: FunctionUtilities.makeForwardingSetter = makeForwardingSetter; michael@0: function bindSafely(fn, object) { michael@0: true; michael@0: var f = fn.bind(object); michael@0: f.boundTo = object; michael@0: return f; michael@0: } michael@0: FunctionUtilities.bindSafely = bindSafely; michael@0: }(Shumway.FunctionUtilities || (Shumway.FunctionUtilities = {}))); michael@0: var FunctionUtilities = Shumway.FunctionUtilities; michael@0: (function (StringUtilities) { michael@0: function toSafeString(value) { michael@0: if (typeof value === 'string') { michael@0: return '"' + value + '"'; michael@0: } michael@0: if (typeof value === 'number' || typeof value === 'boolean') { michael@0: return String(value); michael@0: } michael@0: return typeof value; michael@0: } michael@0: StringUtilities.toSafeString = toSafeString; michael@0: function toSafeArrayString(array) { michael@0: var str = []; michael@0: for (var i = 0; i < array.length; i++) { michael@0: str.push(toSafeString(array[i])); michael@0: } michael@0: return str.join(', '); michael@0: } michael@0: StringUtilities.toSafeArrayString = toSafeArrayString; michael@0: function utf8decode(str) { michael@0: var bytes = new Uint8Array(str.length * 4); michael@0: var b = 0; michael@0: for (var i = 0, j = str.length; i < j; i++) { michael@0: var code = str.charCodeAt(i); michael@0: if (code <= 127) { michael@0: bytes[b++] = code; michael@0: continue; michael@0: } michael@0: if (55296 <= code && code <= 56319) { michael@0: var codeLow = str.charCodeAt(i + 1); michael@0: if (56320 <= codeLow && codeLow <= 57343) { michael@0: code = ((code & 1023) << 10) + (codeLow & 1023) + 65536; michael@0: ++i; michael@0: } michael@0: } michael@0: if ((code & 4292870144) !== 0) { michael@0: bytes[b++] = 248 | code >>> 24 & 3; michael@0: bytes[b++] = 128 | code >>> 18 & 63; michael@0: bytes[b++] = 128 | code >>> 12 & 63; michael@0: bytes[b++] = 128 | code >>> 6 & 63; michael@0: bytes[b++] = 128 | code & 63; michael@0: } else if ((code & 4294901760) !== 0) { michael@0: bytes[b++] = 240 | code >>> 18 & 7; michael@0: bytes[b++] = 128 | code >>> 12 & 63; michael@0: bytes[b++] = 128 | code >>> 6 & 63; michael@0: bytes[b++] = 128 | code & 63; michael@0: } else if ((code & 4294965248) !== 0) { michael@0: bytes[b++] = 224 | code >>> 12 & 15; michael@0: bytes[b++] = 128 | code >>> 6 & 63; michael@0: bytes[b++] = 128 | code & 63; michael@0: } else { michael@0: bytes[b++] = 192 | code >>> 6 & 31; michael@0: bytes[b++] = 128 | code & 63; michael@0: } michael@0: } michael@0: return bytes.subarray(0, b); michael@0: } michael@0: StringUtilities.utf8decode = utf8decode; michael@0: function utf8encode(bytes) { michael@0: var j = 0, str = ''; michael@0: while (j < bytes.length) { michael@0: var b1 = bytes[j++] & 255; michael@0: if (b1 <= 127) { michael@0: str += String.fromCharCode(b1); michael@0: } else { michael@0: var currentPrefix = 192; michael@0: var validBits = 5; michael@0: do { michael@0: var mask = currentPrefix >> 1 | 128; michael@0: if ((b1 & mask) === currentPrefix) michael@0: break; michael@0: currentPrefix = currentPrefix >> 1 | 128; michael@0: --validBits; michael@0: } while (validBits >= 0); michael@0: if (validBits <= 0) { michael@0: str += String.fromCharCode(b1); michael@0: continue; michael@0: } michael@0: var code = b1 & (1 << validBits) - 1; michael@0: var invalid = false; michael@0: for (var i = 5; i >= validBits; --i) { michael@0: var bi = bytes[j++]; michael@0: if ((bi & 192) != 128) { michael@0: invalid = true; michael@0: break; michael@0: } michael@0: code = code << 6 | bi & 63; michael@0: } michael@0: if (invalid) { michael@0: for (var k = j - (7 - i); k < j; ++k) { michael@0: str += String.fromCharCode(bytes[k] & 255); michael@0: } michael@0: continue; michael@0: } michael@0: if (code >= 65536) { michael@0: str += String.fromCharCode(code - 65536 >> 10 & 1023 | 55296, code & 1023 | 56320); michael@0: } else { michael@0: str += String.fromCharCode(code); michael@0: } michael@0: } michael@0: } michael@0: return str; michael@0: } michael@0: StringUtilities.utf8encode = utf8encode; michael@0: function base64ArrayBuffer(arrayBuffer) { michael@0: var base64 = ''; michael@0: var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; michael@0: var bytes = new Uint8Array(arrayBuffer); michael@0: var byteLength = bytes.byteLength; michael@0: var byteRemainder = byteLength % 3; michael@0: var mainLength = byteLength - byteRemainder; michael@0: var a, b, c, d; michael@0: var chunk; michael@0: for (var i = 0; i < mainLength; i = i + 3) { michael@0: chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; michael@0: a = (chunk & 16515072) >> 18; michael@0: b = (chunk & 258048) >> 12; michael@0: c = (chunk & 4032) >> 6; michael@0: d = chunk & 63; michael@0: base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; michael@0: } michael@0: if (byteRemainder == 1) { michael@0: chunk = bytes[mainLength]; michael@0: a = (chunk & 252) >> 2; michael@0: b = (chunk & 3) << 4; michael@0: base64 += encodings[a] + encodings[b] + '=='; michael@0: } else if (byteRemainder == 2) { michael@0: chunk = bytes[mainLength] << 8 | bytes[mainLength + 1]; michael@0: a = (chunk & 64512) >> 10; michael@0: b = (chunk & 1008) >> 4; michael@0: c = (chunk & 15) << 2; michael@0: base64 += encodings[a] + encodings[b] + encodings[c] + '='; michael@0: } michael@0: return base64; michael@0: } michael@0: StringUtilities.base64ArrayBuffer = base64ArrayBuffer; michael@0: function escapeString(str) { michael@0: if (str !== undefined) { michael@0: str = str.replace(/[^\w$]/gi, '$'); michael@0: if (/^\d/.test(str)) { michael@0: str = '$' + str; michael@0: } michael@0: } michael@0: return str; michael@0: } michael@0: StringUtilities.escapeString = escapeString; michael@0: function fromCharCodeArray(buffer) { michael@0: var str = '', SLICE = 1024 * 16; michael@0: for (var i = 0; i < buffer.length; i += SLICE) { michael@0: var chunk = Math.min(buffer.length - i, SLICE); michael@0: str += String.fromCharCode.apply(null, buffer.subarray(i, i + chunk)); michael@0: } michael@0: return str; michael@0: } michael@0: StringUtilities.fromCharCodeArray = fromCharCodeArray; michael@0: var _encoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$_'; michael@0: function variableLengthEncodeInt32(n) { michael@0: var e = _encoding; michael@0: var bitCount = 32 - IntegerUtilities.leadingZeros(n); michael@0: var l = Math.ceil(bitCount / 6); michael@0: var s = e[l]; michael@0: for (var i = l - 1; i >= 0; i--) { michael@0: var offset = i * 6; michael@0: s += e[n >> offset & 63]; michael@0: } michael@0: true; michael@0: return s; michael@0: } michael@0: StringUtilities.variableLengthEncodeInt32 = variableLengthEncodeInt32; michael@0: function toEncoding(n) { michael@0: return _encoding[n]; michael@0: } michael@0: StringUtilities.toEncoding = toEncoding; michael@0: function fromEncoding(s) { michael@0: var c = s.charCodeAt(0); michael@0: var e = 0; michael@0: if (c >= 65 && c <= 90) { michael@0: return c - 65; michael@0: } else if (c >= 97 && c <= 122) { michael@0: return c - 71; michael@0: } else if (c >= 48 && c <= 57) { michael@0: return c + 4; michael@0: } else if (c === 36) { michael@0: return 62; michael@0: } else if (c === 95) { michael@0: return 63; michael@0: } michael@0: } michael@0: StringUtilities.fromEncoding = fromEncoding; michael@0: function variableLengthDecodeInt32(s) { michael@0: var l = StringUtilities.fromEncoding(s[0]); michael@0: var n = 0; michael@0: for (var i = 0; i < l; i++) { michael@0: var offset = (l - i - 1) * 6; michael@0: n |= StringUtilities.fromEncoding(s[1 + i]) << offset; michael@0: } michael@0: return n; michael@0: } michael@0: StringUtilities.variableLengthDecodeInt32 = variableLengthDecodeInt32; michael@0: }(Shumway.StringUtilities || (Shumway.StringUtilities = {}))); michael@0: var StringUtilities = Shumway.StringUtilities; michael@0: (function (HashUtilities) { michael@0: var _md5R = new Uint8Array([ michael@0: 7, michael@0: 12, michael@0: 17, michael@0: 22, michael@0: 7, michael@0: 12, michael@0: 17, michael@0: 22, michael@0: 7, michael@0: 12, michael@0: 17, michael@0: 22, michael@0: 7, michael@0: 12, michael@0: 17, michael@0: 22, michael@0: 5, michael@0: 9, michael@0: 14, michael@0: 20, michael@0: 5, michael@0: 9, michael@0: 14, michael@0: 20, michael@0: 5, michael@0: 9, michael@0: 14, michael@0: 20, michael@0: 5, michael@0: 9, michael@0: 14, michael@0: 20, michael@0: 4, michael@0: 11, michael@0: 16, michael@0: 23, michael@0: 4, michael@0: 11, michael@0: 16, michael@0: 23, michael@0: 4, michael@0: 11, michael@0: 16, michael@0: 23, michael@0: 4, michael@0: 11, michael@0: 16, michael@0: 23, michael@0: 6, michael@0: 10, michael@0: 15, michael@0: 21, michael@0: 6, michael@0: 10, michael@0: 15, michael@0: 21, michael@0: 6, michael@0: 10, michael@0: 15, michael@0: 21, michael@0: 6, michael@0: 10, michael@0: 15, michael@0: 21 michael@0: ]); michael@0: var _md5K = new Int32Array([ michael@0: -680876936, michael@0: -389564586, michael@0: 606105819, michael@0: -1044525330, michael@0: -176418897, michael@0: 1200080426, michael@0: -1473231341, michael@0: -45705983, michael@0: 1770035416, michael@0: -1958414417, michael@0: -42063, michael@0: -1990404162, michael@0: 1804603682, michael@0: -40341101, michael@0: -1502002290, michael@0: 1236535329, michael@0: -165796510, michael@0: -1069501632, michael@0: 643717713, michael@0: -373897302, michael@0: -701558691, michael@0: 38016083, michael@0: -660478335, michael@0: -405537848, michael@0: 568446438, michael@0: -1019803690, michael@0: -187363961, michael@0: 1163531501, michael@0: -1444681467, michael@0: -51403784, michael@0: 1735328473, michael@0: -1926607734, michael@0: -378558, michael@0: -2022574463, michael@0: 1839030562, michael@0: -35309556, michael@0: -1530992060, michael@0: 1272893353, michael@0: -155497632, michael@0: -1094730640, michael@0: 681279174, michael@0: -358537222, michael@0: -722521979, michael@0: 76029189, michael@0: -640364487, michael@0: -421815835, michael@0: 530742520, michael@0: -995338651, michael@0: -198630844, michael@0: 1126891415, michael@0: -1416354905, michael@0: -57434055, michael@0: 1700485571, michael@0: -1894986606, michael@0: -1051523, michael@0: -2054922799, michael@0: 1873313359, michael@0: -30611744, michael@0: -1560198380, michael@0: 1309151649, michael@0: -145523070, michael@0: -1120210379, michael@0: 718787259, michael@0: -343485551 michael@0: ]); michael@0: function hashBytesTo32BitsMD5(data, offset, length) { michael@0: var r = _md5R; michael@0: var k = _md5K; michael@0: var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878; michael@0: var paddedLength = length + 72 & ~63; michael@0: var padded = new Uint8Array(paddedLength); michael@0: var i, j, n; michael@0: for (i = 0; i < length; ++i) { michael@0: padded[i] = data[offset++]; michael@0: } michael@0: padded[i++] = 128; michael@0: n = paddedLength - 8; michael@0: while (i < n) { michael@0: padded[i++] = 0; michael@0: } michael@0: padded[i++] = length << 3 & 255; michael@0: padded[i++] = length >> 5 & 255; michael@0: padded[i++] = length >> 13 & 255; michael@0: padded[i++] = length >> 21 & 255; michael@0: padded[i++] = length >>> 29 & 255; michael@0: padded[i++] = 0; michael@0: padded[i++] = 0; michael@0: padded[i++] = 0; michael@0: var w = new Int32Array(16); michael@0: for (i = 0; i < paddedLength;) { michael@0: for (j = 0; j < 16; ++j, i += 4) { michael@0: w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24; michael@0: } michael@0: var a = h0, b = h1, c = h2, d = h3, f, g; michael@0: for (j = 0; j < 64; ++j) { michael@0: if (j < 16) { michael@0: f = b & c | ~b & d; michael@0: g = j; michael@0: } else if (j < 32) { michael@0: f = d & b | ~d & c; michael@0: g = 5 * j + 1 & 15; michael@0: } else if (j < 48) { michael@0: f = b ^ c ^ d; michael@0: g = 3 * j + 5 & 15; michael@0: } else { michael@0: f = c ^ (b | ~d); michael@0: g = 7 * j & 15; michael@0: } michael@0: var tmp = d, rotateArg = a + f + k[j] + w[g] | 0, rotate = r[j]; michael@0: d = c; michael@0: c = b; michael@0: b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0; michael@0: a = tmp; michael@0: } michael@0: h0 = h0 + a | 0; michael@0: h1 = h1 + b | 0; michael@0: h2 = h2 + c | 0; michael@0: h3 = h3 + d | 0; michael@0: } michael@0: return h0; michael@0: } michael@0: HashUtilities.hashBytesTo32BitsMD5 = hashBytesTo32BitsMD5; michael@0: function hashBytesTo32BitsAdler(data, offset, length) { michael@0: var a = 1; michael@0: var b = 0; michael@0: var end = offset + length; michael@0: for (var i = offset; i < end; ++i) { michael@0: a = (a + (data[i] & 255)) % 65521; michael@0: b = (b + a) % 65521; michael@0: } michael@0: return b << 16 | a; michael@0: } michael@0: HashUtilities.hashBytesTo32BitsAdler = hashBytesTo32BitsAdler; michael@0: }(Shumway.HashUtilities || (Shumway.HashUtilities = {}))); michael@0: var HashUtilities = Shumway.HashUtilities; michael@0: (function (IntegerUtilities) { michael@0: function bitCount(i) { michael@0: i = i - (i >> 1 & 1431655765); michael@0: i = (i & 858993459) + (i >> 2 & 858993459); michael@0: return (i + (i >> 4) & 252645135) * 16843009 >> 24; michael@0: } michael@0: IntegerUtilities.bitCount = bitCount; michael@0: function ones(i) { michael@0: i = i - (i >> 1 & 1431655765); michael@0: i = (i & 858993459) + (i >> 2 & 858993459); michael@0: return (i + (i >> 4) & 252645135) * 16843009 >> 24; michael@0: } michael@0: IntegerUtilities.ones = ones; michael@0: function leadingZeros(i) { michael@0: i |= i >> 1; michael@0: i |= i >> 2; michael@0: i |= i >> 4; michael@0: i |= i >> 8; michael@0: i |= i >> 16; michael@0: return 32 - IntegerUtilities.ones(i); michael@0: } michael@0: IntegerUtilities.leadingZeros = leadingZeros; michael@0: function trailingZeros(i) { michael@0: return IntegerUtilities.ones((i & -i) - 1); michael@0: } michael@0: IntegerUtilities.trailingZeros = trailingZeros; michael@0: function getFlags(i, flags) { michael@0: var str = ''; michael@0: for (var i = 0; i < flags.length; i++) { michael@0: if (i & 1 << i) { michael@0: str += flags[i] + ' '; michael@0: } michael@0: } michael@0: if (str.length === 0) { michael@0: return ''; michael@0: } michael@0: return str.trim(); michael@0: } michael@0: IntegerUtilities.getFlags = getFlags; michael@0: function isPowerOfTwo(x) { michael@0: return x && (x & x - 1) === 0; michael@0: } michael@0: IntegerUtilities.isPowerOfTwo = isPowerOfTwo; michael@0: }(Shumway.IntegerUtilities || (Shumway.IntegerUtilities = {}))); michael@0: var IntegerUtilities = Shumway.IntegerUtilities; michael@0: var IndentingWriter = function () { michael@0: function IndentingWriter(suppressOutput, outFn) { michael@0: if (typeof suppressOutput === 'undefined') { michael@0: suppressOutput = false; michael@0: } michael@0: this._tab = ' '; michael@0: this._padding = ''; michael@0: this._suppressOutput = suppressOutput; michael@0: this._out = outFn || IndentingWriter._consoleOutFn; michael@0: } michael@0: IndentingWriter.prototype.writeLn = function (str) { michael@0: if (!this._suppressOutput) { michael@0: this._out(this._padding + str); michael@0: } michael@0: }; michael@0: IndentingWriter.prototype.writeLns = function (str) { michael@0: var lines = str.split('\n'); michael@0: for (var i = 0; i < lines.length; i++) { michael@0: this.writeLn(lines[i]); michael@0: } michael@0: }; michael@0: IndentingWriter.prototype.debugLn = function (str) { michael@0: this.colorLn(IndentingWriter.PURPLE, str); michael@0: }; michael@0: IndentingWriter.prototype.yellowLn = function (str) { michael@0: this.colorLn(IndentingWriter.YELLOW, str); michael@0: }; michael@0: IndentingWriter.prototype.greenLn = function (str) { michael@0: this.colorLn(IndentingWriter.GREEN, str); michael@0: }; michael@0: IndentingWriter.prototype.redLn = function (str) { michael@0: this.colorLn(IndentingWriter.RED, str); michael@0: }; michael@0: IndentingWriter.prototype.colorLn = function (color, str) { michael@0: if (!this._suppressOutput) { michael@0: if (!inBrowser) { michael@0: this._out(this._padding + color + str + IndentingWriter.ENDC); michael@0: } else { michael@0: this._out(this._padding + str); michael@0: } michael@0: } michael@0: }; michael@0: IndentingWriter.prototype.enter = function (str) { michael@0: if (!this._suppressOutput) { michael@0: this._out(this._padding + str); michael@0: } michael@0: this.indent(); michael@0: }; michael@0: IndentingWriter.prototype.leaveAndEnter = function (str) { michael@0: this.leave(str); michael@0: this.indent(); michael@0: }; michael@0: IndentingWriter.prototype.leave = function (str) { michael@0: this.outdent(); michael@0: if (!this._suppressOutput) { michael@0: this._out(this._padding + str); michael@0: } michael@0: }; michael@0: IndentingWriter.prototype.indent = function () { michael@0: this._padding += this._tab; michael@0: }; michael@0: IndentingWriter.prototype.outdent = function () { michael@0: if (this._padding.length > 0) { michael@0: this._padding = this._padding.substring(0, this._padding.length - this._tab.length); michael@0: } michael@0: }; michael@0: IndentingWriter.prototype.writeArray = function (arr, detailed, noNumbers) { michael@0: if (typeof detailed === 'undefined') { michael@0: detailed = false; michael@0: } michael@0: if (typeof noNumbers === 'undefined') { michael@0: noNumbers = false; michael@0: } michael@0: detailed = detailed || false; michael@0: for (var i = 0, j = arr.length; i < j; i++) { michael@0: var prefix = ''; michael@0: if (detailed) { michael@0: if (arr[i] === null) { michael@0: prefix = 'null'; michael@0: } else if (arr[i] === undefined) { michael@0: prefix = 'undefined'; michael@0: } else { michael@0: prefix = arr[i].constructor.name; michael@0: } michael@0: prefix += ' '; michael@0: } michael@0: var number = noNumbers ? '' : ('' + i).padRight(' ', 4); michael@0: this.writeLn(number + prefix + arr[i]); michael@0: } michael@0: }; michael@0: IndentingWriter.PURPLE = '\x1b[94m'; michael@0: IndentingWriter.YELLOW = '\x1b[93m'; michael@0: IndentingWriter.GREEN = '\x1b[92m'; michael@0: IndentingWriter.RED = '\x1b[91m'; michael@0: IndentingWriter.ENDC = '\x1b[0m'; michael@0: IndentingWriter._consoleOutFn = inBrowser ? console.info.bind(console) : print; michael@0: return IndentingWriter; michael@0: }(); michael@0: Shumway.IndentingWriter = IndentingWriter; michael@0: var SortedListNode = function () { michael@0: function SortedListNode(value, next) { michael@0: this.value = value; michael@0: this.next = next; michael@0: } michael@0: return SortedListNode; michael@0: }(); michael@0: var SortedList = function () { michael@0: function SortedList(compare) { michael@0: true; michael@0: this._compare = compare; michael@0: this._head = null; michael@0: this._length = 0; michael@0: } michael@0: SortedList.prototype.push = function (value) { michael@0: true; michael@0: this._length++; michael@0: if (!this._head) { michael@0: this._head = new SortedListNode(value, null); michael@0: return; michael@0: } michael@0: var curr = this._head; michael@0: var prev = null; michael@0: var node = new SortedListNode(value, null); michael@0: var compare = this._compare; michael@0: while (curr) { michael@0: if (compare(curr.value, node.value) > 0) { michael@0: if (prev) { michael@0: node.next = curr; michael@0: prev.next = node; michael@0: } else { michael@0: node.next = this._head; michael@0: this._head = node; michael@0: } michael@0: return; michael@0: } michael@0: prev = curr; michael@0: curr = curr.next; michael@0: } michael@0: prev.next = node; michael@0: }; michael@0: SortedList.prototype.forEach = function (visitor) { michael@0: var curr = this._head; michael@0: var last = null; michael@0: while (curr) { michael@0: var result = visitor(curr.value); michael@0: if (result === SortedList.RETURN) { michael@0: return; michael@0: } else if (result === SortedList.DELETE) { michael@0: if (!last) { michael@0: curr = this._head = this._head.next; michael@0: } else { michael@0: curr = last.next = curr.next; michael@0: } michael@0: } else { michael@0: last = curr; michael@0: curr = curr.next; michael@0: } michael@0: } michael@0: }; michael@0: SortedList.prototype.isEmpty = function () { michael@0: return !this._head; michael@0: }; michael@0: SortedList.prototype.pop = function () { michael@0: if (!this._head) { michael@0: return undefined; michael@0: } michael@0: this._length--; michael@0: var ret = this._head; michael@0: this._head = this._head.next; michael@0: return ret.value; michael@0: }; michael@0: SortedList.prototype.contains = function (value) { michael@0: var curr = this._head; michael@0: while (curr) { michael@0: if (curr.value === value) { michael@0: return true; michael@0: } michael@0: curr = curr.next; michael@0: } michael@0: return false; michael@0: }; michael@0: SortedList.prototype.toString = function () { michael@0: var str = '['; michael@0: var curr = this._head; michael@0: while (curr) { michael@0: str += curr.value.toString(); michael@0: curr = curr.next; michael@0: if (curr) { michael@0: str += ','; michael@0: } michael@0: } michael@0: str += ']'; michael@0: return str; michael@0: }; michael@0: SortedList.RETURN = 1; michael@0: SortedList.DELETE = 2; michael@0: return SortedList; michael@0: }(); michael@0: Shumway.SortedList = SortedList; michael@0: var CIRCULAR_BUFFER_MASK = 4095; michael@0: var CIRCULAR_BUFFER_SIZE = 4096; michael@0: var CircularBuffer = function () { michael@0: function CircularBuffer(Type) { michael@0: this.index = 0; michael@0: this.start = 0; michael@0: this.array = new Type(CIRCULAR_BUFFER_SIZE); michael@0: } michael@0: CircularBuffer.prototype.get = function (i) { michael@0: return this.array[i]; michael@0: }; michael@0: CircularBuffer.prototype.forEachInReverse = function (visitor) { michael@0: if (this.isEmpty()) { michael@0: return; michael@0: } michael@0: var i = this.index === 0 ? CIRCULAR_BUFFER_SIZE - 1 : this.index - 1; michael@0: while (i !== this.start) { michael@0: if (visitor(this.array[i], i)) { michael@0: break; michael@0: } michael@0: i = i === 0 ? CIRCULAR_BUFFER_SIZE - 1 : i - 1; michael@0: } michael@0: }; michael@0: CircularBuffer.prototype.write = function (value) { michael@0: this.array[this.index] = value; michael@0: this.index = this.index + 1 & CIRCULAR_BUFFER_MASK; michael@0: if (this.index === this.start) { michael@0: this.start = this.start + 1 & CIRCULAR_BUFFER_MASK; michael@0: } michael@0: }; michael@0: CircularBuffer.prototype.isFull = function () { michael@0: return (this.index + 1 & CIRCULAR_BUFFER_MASK) === this.start; michael@0: }; michael@0: CircularBuffer.prototype.isEmpty = function () { michael@0: return this.index === this.start; michael@0: }; michael@0: return CircularBuffer; michael@0: }(); michael@0: Shumway.CircularBuffer = CircularBuffer; michael@0: }(Shumway || (Shumway = {}))); michael@0: var assert = Shumway.Debug.assert; michael@0: var IndentingWriter = Shumway.IndentingWriter; michael@0: var assert = Shumway.Debug.assert; michael@0: var $DEBUG; michael@0: var release = true; michael@0: var c4CoerceNonPrimitiveParameters = false; michael@0: var c4CoerceNonPrimitive = false; michael@0: var c4AsTypeLate = true; michael@0: var error = Shumway.Debug.error; michael@0: var assertNotImplemented = Shumway.Debug.assertNotImplemented; michael@0: var warning = Shumway.Debug.warning; michael@0: var notImplemented = Shumway.Debug.notImplemented; michael@0: var somewhatImplemented = Shumway.Debug.somewhatImplemented; michael@0: var unexpected = Shumway.Debug.unexpected; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter; michael@0: var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter; michael@0: var bindSafely = Shumway.FunctionUtilities.bindSafely; michael@0: var cloneObject = Shumway.ObjectUtilities.cloneObject; michael@0: var copyProperties = Shumway.ObjectUtilities.copyProperties; michael@0: var toSafeString = Shumway.StringUtilities.toSafeString; michael@0: var toSafeArrayString = Shumway.StringUtilities.toSafeArrayString; michael@0: var getLatestGetterOrSetterPropertyDescriptor = Shumway.ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter; michael@0: var defineNonEnumerableSetter = Shumway.ObjectUtilities.defineNonEnumerableSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineNonEnumerableForwardingProperty = Shumway.ObjectUtilities.defineNonEnumerableForwardingProperty; michael@0: var defineNewNonEnumerableProperty = Shumway.ObjectUtilities.defineNewNonEnumerableProperty; michael@0: var isNumeric = Shumway.isNumeric; michael@0: var isNullOrUndefined = Shumway.isNullOrUndefined; michael@0: var isPowerOfTwo = Shumway.IntegerUtilities.isPowerOfTwo; michael@0: function time(fn, count) { michael@0: var start = performance.now(); michael@0: for (var i = 0; i < count; i++) { michael@0: fn(); michael@0: } michael@0: var time = (performance.now() - start) / count; michael@0: console.info('Took: ' + time.toFixed(2) + 'ms.'); michael@0: return time; michael@0: } michael@0: function clamp(x, min, max) { michael@0: if (x < min) { michael@0: return min; michael@0: } else if (x > max) { michael@0: return max; michael@0: } michael@0: return x; michael@0: } michael@0: var fromCharCodeArray = Shumway.StringUtilities.fromCharCodeArray; michael@0: function hasOwnProperty(object, name) { michael@0: return Object.prototype.hasOwnProperty.call(object, name); michael@0: } michael@0: var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray; michael@0: var boxValue = Shumway.ObjectUtilities.boxValue; michael@0: function isObject(value) { michael@0: return typeof value === 'object' || typeof value === 'function'; michael@0: } michael@0: function isString(value) { michael@0: return typeof value === 'string'; michael@0: } michael@0: function isFunction(value) { michael@0: return typeof value === 'function'; michael@0: } michael@0: function isNumber(value) { michael@0: return typeof value === 'number'; michael@0: } michael@0: function toNumber(x) { michael@0: return +x; michael@0: } michael@0: function setBitFlags(flags, flag, value) { michael@0: return value ? flags | flag : flags & ~flag; michael@0: } michael@0: function getBitFlags(flags, flag) { michael@0: return !(!(flags & flag)); michael@0: } michael@0: (function () { michael@0: function extendBuiltin(proto, prop, f) { michael@0: if (!proto[prop]) { michael@0: Object.defineProperty(proto, prop, { michael@0: value: f, michael@0: writable: true, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: } michael@0: } michael@0: var Sp = String.prototype; michael@0: function removeColors(s) { michael@0: return s.replace(/\033\[[0-9]*m/g, ''); michael@0: } michael@0: extendBuiltin(Sp, 'padRight', function (c, n) { michael@0: var str = this; michael@0: var length = removeColors(str).length; michael@0: if (!c || length >= n) { michael@0: return str; michael@0: } michael@0: var max = (n - length) / c.length; michael@0: for (var i = 0; i < max; i++) { michael@0: str += c; michael@0: } michael@0: return str; michael@0: }); michael@0: extendBuiltin(Sp, 'padLeft', function (c, n) { michael@0: var str = this; michael@0: var length = str.length; michael@0: if (!c || length >= n) { michael@0: return str; michael@0: } michael@0: var max = (n - length) / c.length; michael@0: for (var i = 0; i < max; i++) { michael@0: str = c + str; michael@0: } michael@0: return str; michael@0: }); michael@0: extendBuiltin(Sp, 'trim', function () { michael@0: return this.replace(/^\s+|\s+$/g, ''); michael@0: }); michael@0: extendBuiltin(Sp, 'endsWith', function (str) { michael@0: return this.indexOf(str, this.length - str.length) !== -1; michael@0: }); michael@0: var Ap = Array.prototype; michael@0: extendBuiltin(Ap, 'popMany', function (count) { michael@0: true; michael@0: var start = this.length - count; michael@0: var res = this.slice(start, this.length); michael@0: this.splice(start, count); michael@0: return res; michael@0: }); michael@0: extendBuiltin(Ap, 'pushMany', function (array) { michael@0: for (var i = 0; i < array.length; i++) { michael@0: this.push(array[i]); michael@0: } michael@0: }); michael@0: extendBuiltin(Ap, 'clone', function () { michael@0: return this.slice(0); michael@0: }); michael@0: extendBuiltin(Ap, 'first', function () { michael@0: true; michael@0: return this[0]; michael@0: }); michael@0: extendBuiltin(Ap, 'last', function () { michael@0: true; michael@0: return this[this.length - 1]; michael@0: }); michael@0: extendBuiltin(Ap, 'peek', function () { michael@0: true; michael@0: return this[this.length - 1]; michael@0: }); michael@0: extendBuiltin(Ap, 'empty', function () { michael@0: return this.length === 0; michael@0: }); michael@0: extendBuiltin(Ap, 'pushUnique', function (v) { michael@0: for (var i = 0, j = this.length; i < j; i++) { michael@0: if (this[i] === v) { michael@0: return; michael@0: } michael@0: } michael@0: this.push(v); michael@0: }); michael@0: var uniquesMap; michael@0: if (typeof Map !== 'undefined' && (uniquesMap = new Map()).clear) { michael@0: extendBuiltin(Ap, 'unique', function () { michael@0: var unique = []; michael@0: for (var i = 0; i < this.length; i++) { michael@0: if (uniquesMap.has(this[i])) { michael@0: continue; michael@0: } michael@0: unique.push(this[i]); michael@0: uniquesMap.set(this[i], true); michael@0: } michael@0: uniquesMap.clear(); michael@0: return unique; michael@0: }); michael@0: } else { michael@0: extendBuiltin(Ap, 'unique', function () { michael@0: var unique = []; michael@0: for (var i = 0; i < this.length; i++) { michael@0: unique.pushUnique(this[i]); michael@0: } michael@0: return unique; michael@0: }); michael@0: } michael@0: extendBuiltin(Ap, 'replace', function (x, y) { michael@0: if (x === y) { michael@0: return 0; michael@0: } michael@0: var count = 0; michael@0: for (var i = 0; i < this.length; i++) { michael@0: if (this[i] === x) { michael@0: this[i] = y; michael@0: count++; michael@0: } michael@0: } michael@0: return count; michael@0: }); michael@0: extendBuiltin(Ap, 'count', function (x) { michael@0: var count = 0; michael@0: for (var i = 0; i < this.length; i++) { michael@0: if (this[i] === x) { michael@0: count++; michael@0: } michael@0: } michael@0: return count; michael@0: }); michael@0: extendBuiltin(Ap, 'notEmpty', function () { michael@0: return this.length > 0; michael@0: }); michael@0: extendBuiltin(Ap, 'contains', function (val) { michael@0: return this.indexOf(val) >= 0; michael@0: }); michael@0: extendBuiltin(Ap, 'top', function () { michael@0: return this.length && this[this.length - 1]; michael@0: }); michael@0: extendBuiltin(Ap, 'mapWithIndex', function (fn) { michael@0: var arr = []; michael@0: for (var i = 0; i < this.length; i++) { michael@0: arr.push(fn(this[i], i)); michael@0: } michael@0: return arr; michael@0: }); michael@0: }()); michael@0: var utf8decode = Shumway.StringUtilities.utf8decode; michael@0: var utf8encode = Shumway.StringUtilities.utf8encode; michael@0: var escapeString = Shumway.StringUtilities.escapeString; michael@0: var bitCount = Shumway.IntegerUtilities.bitCount; michael@0: var ones = Shumway.IntegerUtilities.ones; michael@0: var leadingZeros = Shumway.IntegerUtilities.leadingZeros; michael@0: var trailingZeros = Shumway.IntegerUtilities.trailingZeros; michael@0: var getFlags = Shumway.IntegerUtilities.getFlags; michael@0: function BitSetFunctor(length) { michael@0: var ADDRESS_BITS_PER_WORD = 5; michael@0: var BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; michael@0: var BIT_INDEX_MASK = BITS_PER_WORD - 1; michael@0: var SIZE = length + (BITS_PER_WORD - 1) >> ADDRESS_BITS_PER_WORD << ADDRESS_BITS_PER_WORD; michael@0: function BitSet() { michael@0: this.count = 0; michael@0: this.dirty = 0; michael@0: this.size = SIZE; michael@0: this.bits = new Uint32Array(SIZE >> ADDRESS_BITS_PER_WORD); michael@0: } michael@0: function BitSetS() { michael@0: this.count = 0; michael@0: this.dirty = 0; michael@0: this.size = SIZE; michael@0: this.bits = 0; michael@0: } michael@0: var singleword = SIZE >> ADDRESS_BITS_PER_WORD === 1; michael@0: var Ctor = singleword ? BitSetS : BitSet; michael@0: Ctor.ADDRESS_BITS_PER_WORD = ADDRESS_BITS_PER_WORD; michael@0: Ctor.BITS_PER_WORD = BITS_PER_WORD; michael@0: Ctor.BIT_INDEX_MASK = BIT_INDEX_MASK; michael@0: Ctor.singleword = singleword; michael@0: BitSet.prototype = { michael@0: recount: function recount() { michael@0: if (!this.dirty) { michael@0: return; michael@0: } michael@0: var bits = this.bits; michael@0: var c = 0; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var v = bits[i]; michael@0: v = v - (v >> 1 & 1431655765); michael@0: v = (v & 858993459) + (v >> 2 & 858993459); michael@0: c += (v + (v >> 4) & 252645135) * 16843009 >> 24; michael@0: } michael@0: this.count = c; michael@0: this.dirty = 0; michael@0: }, michael@0: set: function set(i) { michael@0: var n = i >> ADDRESS_BITS_PER_WORD; michael@0: var old = this.bits[n]; michael@0: var b = old | 1 << (i & BIT_INDEX_MASK); michael@0: this.bits[n] = b; michael@0: this.dirty |= old ^ b; michael@0: }, michael@0: setAll: function setAll() { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: bits[i] = 4294967295; michael@0: } michael@0: this.count = this.size; michael@0: this.dirty = 0; michael@0: }, michael@0: assign: function assign(set) { michael@0: this.count = set.count; michael@0: this.dirty = set.dirty; michael@0: this.size = set.size; michael@0: for (var i = 0, j = this.bits.length; i < j; i++) { michael@0: this.bits[i] = set.bits[i]; michael@0: } michael@0: }, michael@0: clear: function clear(i) { michael@0: var n = i >> ADDRESS_BITS_PER_WORD; michael@0: var old = this.bits[n]; michael@0: var b = old & ~(1 << (i & BIT_INDEX_MASK)); michael@0: this.bits[n] = b; michael@0: this.dirty |= old ^ b; michael@0: }, michael@0: get: function get(i) { michael@0: var word = this.bits[i >> ADDRESS_BITS_PER_WORD]; michael@0: return (word & 1 << (i & BIT_INDEX_MASK)) !== 0; michael@0: }, michael@0: clearAll: function clearAll() { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: bits[i] = 0; michael@0: } michael@0: this.count = 0; michael@0: this.dirty = 0; michael@0: }, michael@0: _union: function _union(other) { michael@0: var dirty = this.dirty; michael@0: var bits = this.bits; michael@0: var otherBits = other.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var old = bits[i]; michael@0: var b = old | otherBits[i]; michael@0: bits[i] = b; michael@0: dirty |= old ^ b; michael@0: } michael@0: this.dirty = dirty; michael@0: }, michael@0: intersect: function intersect(other) { michael@0: var dirty = this.dirty; michael@0: var bits = this.bits; michael@0: var otherBits = other.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var old = bits[i]; michael@0: var b = old & otherBits[i]; michael@0: bits[i] = b; michael@0: dirty |= old ^ b; michael@0: } michael@0: this.dirty = dirty; michael@0: }, michael@0: subtract: function subtract(other) { michael@0: var dirty = this.dirty; michael@0: var bits = this.bits; michael@0: var otherBits = other.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var old = bits[i]; michael@0: var b = old & ~otherBits[i]; michael@0: bits[i] = b; michael@0: dirty |= old ^ b; michael@0: } michael@0: this.dirty = dirty; michael@0: }, michael@0: negate: function negate() { michael@0: var dirty = this.dirty; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var old = bits[i]; michael@0: var b = ~old; michael@0: bits[i] = b; michael@0: dirty |= old ^ b; michael@0: } michael@0: this.dirty = dirty; michael@0: }, michael@0: forEach: function forEach(fn) { michael@0: true; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(i * BITS_PER_WORD + k); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: toArray: function toArray() { michael@0: var set = []; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(i * BITS_PER_WORD + k); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }, michael@0: equals: function equals(other) { michael@0: if (this.size !== other.size) { michael@0: return false; michael@0: } michael@0: var bits = this.bits; michael@0: var otherBits = other.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: if (bits[i] !== otherBits[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: }, michael@0: contains: function contains(other) { michael@0: if (this.size !== other.size) { michael@0: return false; michael@0: } michael@0: var bits = this.bits; michael@0: var otherBits = other.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: if ((bits[i] | otherBits[i]) !== bits[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: }, michael@0: toBitString: function toBitString(on, off) { michael@0: on = on || '1'; michael@0: off = off || '0'; michael@0: var str = ''; michael@0: for (var i = 0; i < length; i++) { michael@0: str += this.get(i) ? on : off; michael@0: } michael@0: return str; michael@0: }, michael@0: length: length, michael@0: toString: function toString(names) { michael@0: var set = []; michael@0: for (var i = 0; i < length; i++) { michael@0: if (this.get(i)) { michael@0: set.push(names ? names[i] : i); michael@0: } michael@0: } michael@0: return set.join(', '); michael@0: }, michael@0: isEmpty: function isEmpty() { michael@0: this.recount(); michael@0: return this.count === 0; michael@0: }, michael@0: clone: function clone() { michael@0: var set = new BitSet(); michael@0: set._union(this); michael@0: return set; michael@0: } michael@0: }; michael@0: BitSetS.prototype = { michael@0: recount: function recount() { michael@0: if (!this.dirty) { michael@0: return; michael@0: } michael@0: var c = 0; michael@0: var v = this.bits; michael@0: v = v - (v >> 1 & 1431655765); michael@0: v = (v & 858993459) + (v >> 2 & 858993459); michael@0: c += (v + (v >> 4) & 252645135) * 16843009 >> 24; michael@0: this.count = c; michael@0: this.dirty = 0; michael@0: }, michael@0: set: function set(i) { michael@0: var old = this.bits; michael@0: var b = old | 1 << (i & BIT_INDEX_MASK); michael@0: this.bits = b; michael@0: this.dirty |= old ^ b; michael@0: }, michael@0: setAll: function setAll() { michael@0: this.bits = 4294967295; michael@0: this.count = this.size; michael@0: this.dirty = 0; michael@0: }, michael@0: assign: function assign(set) { michael@0: this.count = set.count; michael@0: this.dirty = set.dirty; michael@0: this.size = set.size; michael@0: this.bits = set.bits; michael@0: }, michael@0: clear: function clear(i) { michael@0: var old = this.bits; michael@0: var b = old & ~(1 << (i & BIT_INDEX_MASK)); michael@0: this.bits = b; michael@0: this.dirty |= old ^ b; michael@0: }, michael@0: get: function get(i) { michael@0: return (this.bits & 1 << (i & BIT_INDEX_MASK)) !== 0; michael@0: }, michael@0: clearAll: function clearAll() { michael@0: this.bits = 0; michael@0: this.count = 0; michael@0: this.dirty = 0; michael@0: }, michael@0: _union: function _union(other) { michael@0: var old = this.bits; michael@0: var b = old | other.bits; michael@0: this.bits = b; michael@0: this.dirty = old ^ b; michael@0: }, michael@0: intersect: function intersect(other) { michael@0: var old = this.bits; michael@0: var b = old & other.bits; michael@0: this.bits = b; michael@0: this.dirty = old ^ b; michael@0: }, michael@0: subtract: function subtract(other) { michael@0: var old = this.bits; michael@0: var b = old & ~other.bits; michael@0: this.bits = b; michael@0: this.dirty = old ^ b; michael@0: }, michael@0: negate: function negate() { michael@0: var old = this.bits; michael@0: var b = ~old; michael@0: this.bits = b; michael@0: this.dirty = old ^ b; michael@0: }, michael@0: forEach: function forEach(fn) { michael@0: true; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(k); michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: toArray: function toArray() { michael@0: var set = []; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(k); michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }, michael@0: equals: function equals(other) { michael@0: return this.bits === other.bits; michael@0: }, michael@0: contains: function contains(other) { michael@0: var bits = this.bits; michael@0: return (bits | other.bits) === bits; michael@0: }, michael@0: isEmpty: function isEmpty() { michael@0: this.recount(); michael@0: return this.count === 0; michael@0: }, michael@0: clone: function clone() { michael@0: var set = new BitSetS(); michael@0: set._union(this); michael@0: return set; michael@0: }, michael@0: toBitString: BitSet.prototype.toBitString, michael@0: toString: BitSet.prototype.toString, michael@0: length: length michael@0: }; michael@0: return Ctor; michael@0: } michael@0: var Map = function () { michael@0: function map() { michael@0: this.elements = {}; michael@0: } michael@0: map.prototype.set = function set(k, v) { michael@0: this.elements[k] = v; michael@0: }; michael@0: map.prototype.get = function get(k) { michael@0: if (this.has(k)) { michael@0: return this.elements[k]; michael@0: } michael@0: return undefined; michael@0: }; michael@0: map.prototype.has = function has(k) { michael@0: return Object.prototype.hasOwnProperty.call(this.elements, k); michael@0: }; michael@0: map.prototype.remove = function remove(k) { michael@0: if (this.has(k)) { michael@0: delete this.elements[k]; michael@0: } michael@0: }; michael@0: return map; michael@0: }(); michael@0: (function checkWeakMap() { michael@0: if (typeof this.WeakMap === 'function') michael@0: return; michael@0: var id = 0; michael@0: function WeakMap() { michael@0: this.id = '$weakmap' + id++; michael@0: } michael@0: ; michael@0: WeakMap.prototype = { michael@0: has: function (obj) { michael@0: return obj.hasOwnProperty(this.id); michael@0: }, michael@0: get: function (obj, defaultValue) { michael@0: return obj.hasOwnProperty(this.id) ? obj[this.id] : defaultValue; michael@0: }, michael@0: set: function (obj, value) { michael@0: Object.defineProperty(obj, this.id, { michael@0: value: value, michael@0: enumerable: false, michael@0: configurable: true michael@0: }); michael@0: } michael@0: }; michael@0: this.WeakMap = WeakMap; michael@0: }()); michael@0: var Callback = function () { michael@0: function callback() { michael@0: this.queues = {}; michael@0: } michael@0: callback.prototype.register = function register(type, callback) { michael@0: var queue = this.queues[type]; michael@0: if (queue) { michael@0: if (queue.indexOf(callback) > -1) { michael@0: return; michael@0: } michael@0: } else { michael@0: queue = this.queues[type] = []; michael@0: } michael@0: queue.push(callback); michael@0: }; michael@0: callback.prototype.unregister = function unregister(type, callback) { michael@0: var queue = this.queues[type]; michael@0: if (!queue) { michael@0: return; michael@0: } michael@0: var i = queue.indexOf(callback); michael@0: if (i !== -1) { michael@0: queue.splice(i, 1); michael@0: } michael@0: if (queue.length === 0) { michael@0: this.queues[type] = null; michael@0: } michael@0: }; michael@0: callback.prototype.notify = function notify(type, args) { michael@0: var queue = this.queues[type]; michael@0: if (!queue) { michael@0: return; michael@0: } michael@0: queue = queue.slice(); michael@0: var args = sliceArguments(arguments, 0); michael@0: for (var i = 0; i < queue.length; i++) { michael@0: if (false) { michael@0: Counter.count('callback(' + type + ').notify'); michael@0: } michael@0: var callback = queue[i]; michael@0: callback.apply(null, args); michael@0: } michael@0: }; michael@0: callback.prototype.notify1 = function notify1(type, value) { michael@0: var queue = this.queues[type]; michael@0: if (!queue) { michael@0: return; michael@0: } michael@0: queue = queue.slice(); michael@0: for (var i = 0; i < queue.length; i++) { michael@0: if (false) { michael@0: Counter.count('callback(' + type + ').notify1'); michael@0: } michael@0: var callback = queue[i]; michael@0: callback(type, value); michael@0: } michael@0: }; michael@0: return callback; michael@0: }(); michael@0: function lazyClass(holder, name, initialize) { michael@0: Object.defineProperty(holder, name, { michael@0: get: function () { michael@0: var start = performance.now(); michael@0: var value = initialize(); michael@0: print('Initialized Class: ' + name + ' ' + (performance.now() - start).toFixed(4)); michael@0: Object.defineProperty(holder, name, { michael@0: value: value, michael@0: writable: true michael@0: }); michael@0: return value; michael@0: }, michael@0: configurable: true michael@0: }); michael@0: } michael@0: var hashBytesTo32BitsAdler = Shumway.HashUtilities.hashBytesTo32BitsAdler; michael@0: var hashBytesTo32BitsMD5 = Shumway.HashUtilities.hashBytesTo32BitsMD5; michael@0: var variableLengthEncodeInt32 = Shumway.StringUtilities.variableLengthEncodeInt32; michael@0: var fromEncoding = Shumway.StringUtilities.fromEncoding; michael@0: var variableLengthDecodeIdentifier = Shumway.StringUtilities.variableLengthDecodeInt32; michael@0: var toEncoding = Shumway.StringUtilities.toEncoding; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (Options) { michael@0: var Argument = function () { michael@0: function Argument(shortName, longName, type, options) { michael@0: this.shortName = shortName; michael@0: this.longName = longName; michael@0: this.type = type; michael@0: options = options || {}; michael@0: this.positional = options.positional; michael@0: this.parseFn = options.parse; michael@0: this.value = options.defaultValue; michael@0: } michael@0: Argument.prototype.parse = function (value) { michael@0: if (this.type === 'boolean') { michael@0: true; michael@0: this.value = value; michael@0: } else if (this.type === 'number') { michael@0: true; michael@0: this.value = parseInt(value, 10); michael@0: } else { michael@0: this.value = value; michael@0: } michael@0: if (this.parseFn) { michael@0: this.parseFn(this.value); michael@0: } michael@0: }; michael@0: return Argument; michael@0: }(); michael@0: Options.Argument = Argument; michael@0: var ArgumentParser = function () { michael@0: function ArgumentParser() { michael@0: this.args = []; michael@0: } michael@0: ArgumentParser.prototype.addArgument = function (shortName, longName, type, options) { michael@0: var argument = new Argument(shortName, longName, type, options); michael@0: this.args.push(argument); michael@0: return argument; michael@0: }; michael@0: ArgumentParser.prototype.addBoundOption = function (option) { michael@0: var options = { michael@0: parse: function (x) { michael@0: option.value = x; michael@0: } michael@0: }; michael@0: this.args.push(new Argument(option.shortName, option.longName, option.type, options)); michael@0: }; michael@0: ArgumentParser.prototype.addBoundOptionSet = function (optionSet) { michael@0: var self = this; michael@0: optionSet.options.forEach(function (x) { michael@0: if (x instanceof OptionSet) { michael@0: self.addBoundOptionSet(x); michael@0: } else { michael@0: true; michael@0: self.addBoundOption(x); michael@0: } michael@0: }); michael@0: }; michael@0: ArgumentParser.prototype.getUsage = function () { michael@0: var str = ''; michael@0: this.args.forEach(function (x) { michael@0: if (!x.positional) { michael@0: str += '[-' + x.shortName + '|--' + x.longName + (x.type === 'boolean' ? '' : ' ' + x.type[0].toUpperCase()) + ']'; michael@0: } else { michael@0: str += x.longName; michael@0: } michael@0: str += ' '; michael@0: }); michael@0: return str; michael@0: }; michael@0: ArgumentParser.prototype.parse = function (args) { michael@0: var nonPositionalArgumentMap = {}; michael@0: var positionalArgumentList = []; michael@0: this.args.forEach(function (x) { michael@0: if (x.positional) { michael@0: positionalArgumentList.push(x); michael@0: } else { michael@0: nonPositionalArgumentMap['-' + x.shortName] = x; michael@0: nonPositionalArgumentMap['--' + x.longName] = x; michael@0: } michael@0: }); michael@0: var leftoverArguments = []; michael@0: while (args.length) { michael@0: var argString = args.shift(); michael@0: var argument = null, value = argString; michael@0: if (argString == '--') { michael@0: leftoverArguments = leftoverArguments.concat(args); michael@0: break; michael@0: } else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') { michael@0: argument = nonPositionalArgumentMap[argString]; michael@0: true; michael@0: if (!argument) { michael@0: continue; michael@0: } michael@0: if (argument.type !== 'boolean') { michael@0: value = args.shift(); michael@0: true; michael@0: } else { michael@0: value = true; michael@0: } michael@0: } else if (positionalArgumentList.length) { michael@0: argument = positionalArgumentList.shift(); michael@0: } else { michael@0: leftoverArguments.push(value); michael@0: } michael@0: if (argument) { michael@0: argument.parse(value); michael@0: } michael@0: } michael@0: true; michael@0: return leftoverArguments; michael@0: }; michael@0: return ArgumentParser; michael@0: }(); michael@0: Options.ArgumentParser = ArgumentParser; michael@0: var OptionSet = function () { michael@0: function OptionSet(name) { michael@0: this.name = name; michael@0: this.options = []; michael@0: } michael@0: OptionSet.prototype.register = function (option) { michael@0: this.options.push(option); michael@0: return option; michael@0: }; michael@0: OptionSet.prototype.trace = function (writer) { michael@0: writer.enter(this.name + ' {'); michael@0: this.options.forEach(function (option) { michael@0: option.trace(writer); michael@0: }); michael@0: writer.leave('}'); michael@0: }; michael@0: return OptionSet; michael@0: }(); michael@0: Options.OptionSet = OptionSet; michael@0: var Option = function () { michael@0: function Option(shortName, longName, type, defaultValue, description) { michael@0: this.longName = longName; michael@0: this.shortName = shortName; michael@0: this.type = type; michael@0: this.defaultValue = defaultValue; michael@0: this.value = defaultValue; michael@0: this.description = description; michael@0: } michael@0: Option.prototype.parse = function (value) { michael@0: this.value = value; michael@0: }; michael@0: Option.prototype.trace = function (writer) { michael@0: writer.writeLn(('-' + this.shortName + '|--' + this.longName).padRight(' ', 30) + ' = ' + this.type + ' ' + this.value + ' [' + this.defaultValue + ']' + ' (' + this.description + ')'); michael@0: }; michael@0: return Option; michael@0: }(); michael@0: Options.Option = Option; michael@0: }(Shumway.Options || (Shumway.Options = {}))); michael@0: var Options = Shumway.Options; michael@0: }(Shumway || (Shumway = {}))); michael@0: if (typeof exports !== 'undefined') { michael@0: exports['Shumway'] = Shumway; michael@0: } michael@0: var ArgumentParser = Shumway.Options.ArgumentParser; michael@0: var Option = Shumway.Options.Option; michael@0: var OptionSet = Shumway.Options.OptionSet; michael@0: var ArgumentParser = Shumway.Options.ArgumentParser; michael@0: var Option = Shumway.Options.Option; michael@0: var OptionSet = Shumway.Options.OptionSet; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (Metrics) { michael@0: var Timer = function () { michael@0: function Timer(parent, name) { michael@0: this._parent = parent; michael@0: this._timers = Shumway.ObjectUtilities.createMap(); michael@0: this._name = name; michael@0: this._begin = 0; michael@0: this._last = 0; michael@0: this._total = 0; michael@0: this._count = 0; michael@0: } michael@0: Timer.time = function (name, fn) { michael@0: Timer.start(name); michael@0: fn(); michael@0: Timer.stop(); michael@0: }; michael@0: Timer.start = function (name) { michael@0: Timer._top = Timer._top._timers[name] || (Timer._top._timers[name] = new Timer(Timer._top, name)); michael@0: Timer._top.start(); michael@0: var tmp = Timer._flat._timers[name] || (Timer._flat._timers[name] = new Timer(Timer._flat, name)); michael@0: tmp.start(); michael@0: Timer._flatStack.push(tmp); michael@0: }; michael@0: Timer.stop = function () { michael@0: Timer._top.stop(); michael@0: Timer._top = Timer._top._parent; michael@0: Timer._flatStack.pop().stop(); michael@0: }; michael@0: Timer.stopStart = function (name) { michael@0: Timer.stop(); michael@0: Timer.start(name); michael@0: }; michael@0: Timer.prototype.start = function () { michael@0: this._begin = Shumway.getTicks(); michael@0: }; michael@0: Timer.prototype.stop = function () { michael@0: this._last = Shumway.getTicks() - this._begin; michael@0: this._total += this._last; michael@0: this._count += 1; michael@0: }; michael@0: Timer.prototype.toJSON = function () { michael@0: return { michael@0: name: this._name, michael@0: total: this._total, michael@0: timers: this._timers michael@0: }; michael@0: }; michael@0: Timer.prototype.trace = function (writer) { michael@0: writer.enter(this._name + ': ' + this._total.toFixed(2) + ' ms' + ', count: ' + this._count + ', average: ' + (this._total / this._count).toFixed(2) + ' ms'); michael@0: for (var name in this._timers) { michael@0: this._timers[name].trace(writer); michael@0: } michael@0: writer.outdent(); michael@0: }; michael@0: Timer.trace = function (writer) { michael@0: Timer._base.trace(writer); michael@0: Timer._flat.trace(writer); michael@0: }; michael@0: Timer._base = new Timer(null, 'Total'); michael@0: Timer._top = Timer._base; michael@0: Timer._flat = new Timer(null, 'Flat'); michael@0: Timer._flatStack = []; michael@0: return Timer; michael@0: }(); michael@0: Metrics.Timer = Timer; michael@0: var Counter = function () { michael@0: function Counter(enabled) { michael@0: this._enabled = enabled; michael@0: this.clear(); michael@0: } michael@0: Counter.prototype.setEnabled = function (enabled) { michael@0: this._enabled = enabled; michael@0: }; michael@0: Counter.prototype.clear = function () { michael@0: this._counts = Shumway.ObjectUtilities.createMap(); michael@0: }; michael@0: Counter.prototype.toJSON = function () { michael@0: return { michael@0: counts: this._counts michael@0: }; michael@0: }; michael@0: Counter.prototype.count = function (name, increment) { michael@0: if (typeof increment === 'undefined') { michael@0: increment = 1; michael@0: } michael@0: if (!this._enabled) { michael@0: return; michael@0: } michael@0: if (this._counts[name] === undefined) { michael@0: this._counts[name] = 0; michael@0: } michael@0: this._counts[name] += increment; michael@0: return this._counts[name]; michael@0: }; michael@0: Counter.prototype.trace = function (writer) { michael@0: for (var name in this._counts) { michael@0: writer.writeLn(name + ': ' + this._counts[name]); michael@0: } michael@0: }; michael@0: Counter.prototype.traceSorted = function (writer) { michael@0: var pairs = []; michael@0: for (var name in this._counts) { michael@0: pairs.push([ michael@0: name, michael@0: this._counts[name] michael@0: ]); michael@0: } michael@0: pairs.sort(function (a, b) { michael@0: return b[1] - a[1]; michael@0: }); michael@0: pairs.forEach(function (pair) { michael@0: writer.writeLn(pair[0] + ': ' + pair[1]); michael@0: }); michael@0: }; michael@0: return Counter; michael@0: }(); michael@0: Metrics.Counter = Counter; michael@0: var Average = function () { michael@0: function Average(max) { michael@0: this._samples = new Float64Array(max); michael@0: this._count = 0; michael@0: this._index = 0; michael@0: } michael@0: Average.prototype.push = function (sample) { michael@0: if (this._count < this._samples.length) { michael@0: this._count++; michael@0: } michael@0: this._index++; michael@0: this._samples[this._index % this._samples.length] = sample; michael@0: }; michael@0: Average.prototype.average = function () { michael@0: var sum = 0; michael@0: for (var i = 0; i < this._count; i++) { michael@0: sum += this._samples[i]; michael@0: } michael@0: return sum / this._count; michael@0: }; michael@0: return Average; michael@0: }(); michael@0: Metrics.Average = Average; michael@0: }(Shumway.Metrics || (Shumway.Metrics = {}))); michael@0: var Metrics = Shumway.Metrics; michael@0: }(Shumway || (Shumway = {}))); michael@0: var Timer = Shumway.Metrics.Timer; michael@0: var Counter = new Shumway.Metrics.Counter(true); michael@0: var Timer = Shumway.Metrics.Timer; michael@0: var Counter = new Shumway.Metrics.Counter(true); michael@0: var FrameCounter = new Shumway.Metrics.Counter(true); michael@0: var systemOptions = new OptionSet('System Options'); michael@0: var disassemble = systemOptions.register(new Option('d', 'disassemble', 'boolean', false, 'disassemble')); michael@0: var traceLevel = systemOptions.register(new Option('t', 'traceLevel', 'number', 0, 'trace level')); michael@0: window.print = function (s) { michael@0: console.log(s); michael@0: }; michael@0: var CONSTANT_Undefined = 0; michael@0: var CONSTANT_Utf8 = 1; michael@0: var CONSTANT_Float = 2; michael@0: var CONSTANT_Int = 3; michael@0: var CONSTANT_UInt = 4; michael@0: var CONSTANT_PrivateNs = 5; michael@0: var CONSTANT_Double = 6; michael@0: var CONSTANT_QName = 7; michael@0: var CONSTANT_Namespace = 8; michael@0: var CONSTANT_Multiname = 9; michael@0: var CONSTANT_False = 10; michael@0: var CONSTANT_True = 11; michael@0: var CONSTANT_Null = 12; michael@0: var CONSTANT_QNameA = 13; michael@0: var CONSTANT_MultinameA = 14; michael@0: var CONSTANT_RTQName = 15; michael@0: var CONSTANT_RTQNameA = 16; michael@0: var CONSTANT_RTQNameL = 17; michael@0: var CONSTANT_RTQNameLA = 18; michael@0: var CONSTANT_NameL = 19; michael@0: var CONSTANT_NameLA = 20; michael@0: var CONSTANT_NamespaceSet = 21; michael@0: var CONSTANT_PackageNamespace = 22; michael@0: var CONSTANT_PackageInternalNs = 23; michael@0: var CONSTANT_ProtectedNamespace = 24; michael@0: var CONSTANT_ExplicitNamespace = 25; michael@0: var CONSTANT_StaticProtectedNs = 26; michael@0: var CONSTANT_MultinameL = 27; michael@0: var CONSTANT_MultinameLA = 28; michael@0: var CONSTANT_TypeName = 29; michael@0: var CONSTANT_ClassSealed = 1; michael@0: var CONSTANT_ClassFinal = 2; michael@0: var CONSTANT_ClassInterface = 4; michael@0: var CONSTANT_ClassProtectedNs = 8; michael@0: var TRAIT_Slot = 0; michael@0: var TRAIT_Method = 1; michael@0: var TRAIT_Getter = 2; michael@0: var TRAIT_Setter = 3; michael@0: var TRAIT_Class = 4; michael@0: var TRAIT_Function = 5; michael@0: var TRAIT_Const = 6; michael@0: var ATTR_Final = 1; michael@0: var ATTR_Override = 2; michael@0: var ATTR_Metadata = 4; michael@0: var SLOT_var = 0; michael@0: var SLOT_method = 1; michael@0: var SLOT_getter = 2; michael@0: var SLOT_setter = 3; michael@0: var SLOT_class = 4; michael@0: var SLOT_function = 6; michael@0: var METHOD_Arguments = 1; michael@0: var METHOD_Activation = 2; michael@0: var METHOD_Needrest = 4; michael@0: var METHOD_HasOptional = 8; michael@0: var METHOD_IgnoreRest = 16; michael@0: var METHOD_Native = 32; michael@0: var METHOD_Setsdxns = 64; michael@0: var METHOD_HasParamNames = 128; michael@0: var OP_bkpt = 1; michael@0: var OP_nop = 2; michael@0: var OP_throw = 3; michael@0: var OP_getsuper = 4; michael@0: var OP_setsuper = 5; michael@0: var OP_dxns = 6; michael@0: var OP_dxnslate = 7; michael@0: var OP_kill = 8; michael@0: var OP_label = 9; michael@0: var OP_lf32x4 = 10; michael@0: var OP_sf32x4 = 11; michael@0: var OP_ifnlt = 12; michael@0: var OP_ifnle = 13; michael@0: var OP_ifngt = 14; michael@0: var OP_ifnge = 15; michael@0: var OP_jump = 16; michael@0: var OP_iftrue = 17; michael@0: var OP_iffalse = 18; michael@0: var OP_ifeq = 19; michael@0: var OP_ifne = 20; michael@0: var OP_iflt = 21; michael@0: var OP_ifle = 22; michael@0: var OP_ifgt = 23; michael@0: var OP_ifge = 24; michael@0: var OP_ifstricteq = 25; michael@0: var OP_ifstrictne = 26; michael@0: var OP_lookupswitch = 27; michael@0: var OP_pushwith = 28; michael@0: var OP_popscope = 29; michael@0: var OP_nextname = 30; michael@0: var OP_hasnext = 31; michael@0: var OP_pushnull = 32; michael@0: var OP_pushundefined = 33; michael@0: var OP_pushfloat = 34; michael@0: var OP_nextvalue = 35; michael@0: var OP_pushbyte = 36; michael@0: var OP_pushshort = 37; michael@0: var OP_pushtrue = 38; michael@0: var OP_pushfalse = 39; michael@0: var OP_pushnan = 40; michael@0: var OP_pop = 41; michael@0: var OP_dup = 42; michael@0: var OP_swap = 43; michael@0: var OP_pushstring = 44; michael@0: var OP_pushint = 45; michael@0: var OP_pushuint = 46; michael@0: var OP_pushdouble = 47; michael@0: var OP_pushscope = 48; michael@0: var OP_pushnamespace = 49; michael@0: var OP_hasnext2 = 50; michael@0: var OP_li8 = 53; michael@0: var OP_li16 = 54; michael@0: var OP_li32 = 55; michael@0: var OP_lf32 = 56; michael@0: var OP_lf64 = 57; michael@0: var OP_si8 = 58; michael@0: var OP_si16 = 59; michael@0: var OP_si32 = 60; michael@0: var OP_sf32 = 61; michael@0: var OP_sf64 = 62; michael@0: var OP_newfunction = 64; michael@0: var OP_call = 65; michael@0: var OP_construct = 66; michael@0: var OP_callmethod = 67; michael@0: var OP_callstatic = 68; michael@0: var OP_callsuper = 69; michael@0: var OP_callproperty = 70; michael@0: var OP_returnvoid = 71; michael@0: var OP_returnvalue = 72; michael@0: var OP_constructsuper = 73; michael@0: var OP_constructprop = 74; michael@0: var OP_callsuperid = 75; michael@0: var OP_callproplex = 76; michael@0: var OP_callinterface = 77; michael@0: var OP_callsupervoid = 78; michael@0: var OP_callpropvoid = 79; michael@0: var OP_sxi1 = 80; michael@0: var OP_sxi8 = 81; michael@0: var OP_sxi16 = 82; michael@0: var OP_applytype = 83; michael@0: var OP_pushfloat4 = 84; michael@0: var OP_newobject = 85; michael@0: var OP_newarray = 86; michael@0: var OP_newactivation = 87; michael@0: var OP_newclass = 88; michael@0: var OP_getdescendants = 89; michael@0: var OP_newcatch = 90; michael@0: var OP_findpropstrict = 93; michael@0: var OP_findproperty = 94; michael@0: var OP_finddef = 95; michael@0: var OP_getlex = 96; michael@0: var OP_setproperty = 97; michael@0: var OP_getlocal = 98; michael@0: var OP_setlocal = 99; michael@0: var OP_getglobalscope = 100; michael@0: var OP_getscopeobject = 101; michael@0: var OP_getproperty = 102; michael@0: var OP_getouterscope = 103; michael@0: var OP_initproperty = 104; michael@0: var OP_setpropertylate = 105; michael@0: var OP_deleteproperty = 106; michael@0: var OP_deletepropertylate = 107; michael@0: var OP_getslot = 108; michael@0: var OP_setslot = 109; michael@0: var OP_getglobalslot = 110; michael@0: var OP_setglobalslot = 111; michael@0: var OP_convert_s = 112; michael@0: var OP_esc_xelem = 113; michael@0: var OP_esc_xattr = 114; michael@0: var OP_convert_i = 115; michael@0: var OP_convert_u = 116; michael@0: var OP_convert_d = 117; michael@0: var OP_convert_b = 118; michael@0: var OP_convert_o = 119; michael@0: var OP_checkfilter = 120; michael@0: var OP_convert_f = 121; michael@0: var OP_unplus = 122; michael@0: var OP_convert_f4 = 123; michael@0: var OP_coerce = 128; michael@0: var OP_coerce_b = 129; michael@0: var OP_coerce_a = 130; michael@0: var OP_coerce_i = 131; michael@0: var OP_coerce_d = 132; michael@0: var OP_coerce_s = 133; michael@0: var OP_astype = 134; michael@0: var OP_astypelate = 135; michael@0: var OP_coerce_u = 136; michael@0: var OP_coerce_o = 137; michael@0: var OP_negate = 144; michael@0: var OP_increment = 145; michael@0: var OP_inclocal = 146; michael@0: var OP_decrement = 147; michael@0: var OP_declocal = 148; michael@0: var OP_typeof = 149; michael@0: var OP_not = 150; michael@0: var OP_bitnot = 151; michael@0: var OP_add = 160; michael@0: var OP_subtract = 161; michael@0: var OP_multiply = 162; michael@0: var OP_divide = 163; michael@0: var OP_modulo = 164; michael@0: var OP_lshift = 165; michael@0: var OP_rshift = 166; michael@0: var OP_urshift = 167; michael@0: var OP_bitand = 168; michael@0: var OP_bitor = 169; michael@0: var OP_bitxor = 170; michael@0: var OP_equals = 171; michael@0: var OP_strictequals = 172; michael@0: var OP_lessthan = 173; michael@0: var OP_lessequals = 174; michael@0: var OP_greaterthan = 175; michael@0: var OP_greaterequals = 176; michael@0: var OP_instanceof = 177; michael@0: var OP_istype = 178; michael@0: var OP_istypelate = 179; michael@0: var OP_in = 180; michael@0: var OP_increment_i = 192; michael@0: var OP_decrement_i = 193; michael@0: var OP_inclocal_i = 194; michael@0: var OP_declocal_i = 195; michael@0: var OP_negate_i = 196; michael@0: var OP_add_i = 197; michael@0: var OP_subtract_i = 198; michael@0: var OP_multiply_i = 199; michael@0: var OP_getlocal0 = 208; michael@0: var OP_getlocal1 = 209; michael@0: var OP_getlocal2 = 210; michael@0: var OP_getlocal3 = 211; michael@0: var OP_setlocal0 = 212; michael@0: var OP_setlocal1 = 213; michael@0: var OP_setlocal2 = 214; michael@0: var OP_setlocal3 = 215; michael@0: var OP_invalid = 237; michael@0: var OP_debug = 239; michael@0: var OP_debugline = 240; michael@0: var OP_debugfile = 241; michael@0: var OP_bkptline = 242; michael@0: var OP_timestamp = 243; michael@0: var INT_MIN_VALUE = -2147483648; michael@0: var INT_MAX_VALUE = 2147483647; michael@0: var UINT_MIN_VALUE = 0; michael@0: var UINT_MAX_VALUE = 4294967295; michael@0: var SORT_CASEINSENSITIVE = 1; michael@0: var SORT_DESCENDING = 2; michael@0: var SORT_UNIQUESORT = 4; michael@0: var SORT_RETURNINDEXEDARRAY = 8; michael@0: var SORT_NUMERIC = 16; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: AVM2.Errors = { michael@0: CallOfNonFunctionError: { michael@0: code: 1006, michael@0: message: '%1 is not a function.' michael@0: }, michael@0: ConvertNullToObjectError: { michael@0: code: 1009, michael@0: message: 'Cannot access a property or method of a null object reference.' michael@0: }, michael@0: ConvertUndefinedToObjectError: { michael@0: code: 1010, michael@0: message: 'A term is undefined and has no properties.' michael@0: }, michael@0: ClassNotFoundError: { michael@0: code: 1014, michael@0: message: 'Class %1 could not be found.' michael@0: }, michael@0: CheckTypeFailedError: { michael@0: code: 1034, michael@0: message: 'Type Coercion failed: cannot convert %1 to %2.' michael@0: }, michael@0: WrongArgumentCountError: { michael@0: code: 1063, michael@0: message: 'Argument count mismatch on %1. Expected %2, got %3.' michael@0: }, michael@0: XMLMarkupMustBeWellFormed: { michael@0: code: 1088, michael@0: message: 'The markup in the document following the root element must be well-formed.' michael@0: }, michael@0: OutOfRangeError: { michael@0: code: 1125, michael@0: message: 'The index %1 is out of range %2.' michael@0: }, michael@0: VectorFixedError: { michael@0: code: 1126, michael@0: message: 'Cannot change the length of a fixed Vector.' michael@0: }, michael@0: InvalidParamError: { michael@0: code: 2004, michael@0: message: 'One of the parameters is invalid.' michael@0: }, michael@0: ParamRangeError: { michael@0: code: 2006, michael@0: message: 'The supplied index is out of bounds.' michael@0: }, michael@0: NullPointerError: { michael@0: code: 2007, michael@0: message: 'Parameter %1 must be non-null.' michael@0: }, michael@0: InvalidEnumError: { michael@0: code: 2008, michael@0: message: 'Parameter %1 must be one of the accepted values.' michael@0: }, michael@0: ArgumentError: { michael@0: code: 2015, michael@0: message: 'Invalid BitmapData.' michael@0: }, michael@0: CompressedDataError: { michael@0: code: 2058, michael@0: message: 'There was an error decompressing the data.' michael@0: }, michael@0: SocketConnectError: { michael@0: code: 2011, michael@0: message: 'Socket connection failed to %1:%2.' michael@0: }, michael@0: CantAddSelfError: { michael@0: code: 2024, michael@0: message: 'An object cannot be added as a child of itself.' michael@0: }, michael@0: NotAChildError: { michael@0: code: 2025, michael@0: message: 'The supplied DisplayObject must be a child of the caller.' michael@0: }, michael@0: ExternalInterfaceNotAvailableError: { michael@0: code: 2067, michael@0: 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.' michael@0: } michael@0: }; michael@0: function getErrorMessage(index) { michael@0: if (!Shumway.AVM2.Runtime.debuggerMode.value) { michael@0: return 'Error #' + index; michael@0: } michael@0: for (var k in AVM2.Errors) { michael@0: if (AVM2.Errors[k].code == index) { michael@0: return 'Error #' + index + ': ' + AVM2.Errors[k].message; michael@0: } michael@0: } michael@0: return 'Error #' + index + ': (unknown)'; michael@0: } michael@0: AVM2.getErrorMessage = getErrorMessage; michael@0: function formatErrorMessage(error) { michael@0: var args = []; michael@0: for (var _i = 0; _i < arguments.length - 1; _i++) { michael@0: args[_i] = arguments[_i + 1]; michael@0: } michael@0: var message = error.message; michael@0: Array.prototype.slice.call(arguments, 1).forEach(function (x, i) { michael@0: message = message.replace('%' + (i + 1), x); michael@0: }); michael@0: return 'Error #' + error.code + ': ' + message; michael@0: } michael@0: AVM2.formatErrorMessage = formatErrorMessage; michael@0: function translateErrorMessage(error) { michael@0: if (error.type) { michael@0: switch (error.type) { michael@0: case 'undefined_method': michael@0: return formatErrorMessage(AVM2.Errors.CallOfNonFunctionError, 'value'); michael@0: default: michael@0: throw Shumway.Debug.notImplemented(error.type); michael@0: } michael@0: } else { michael@0: if (error.message.indexOf('is not a function') >= 0) { michael@0: return formatErrorMessage(AVM2.Errors.CallOfNonFunctionError, 'value'); michael@0: } michael@0: return error.message; michael@0: } michael@0: } michael@0: AVM2.translateErrorMessage = translateErrorMessage; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var Errors = Shumway.AVM2.Errors; michael@0: var getErrorMessage = Shumway.AVM2.getErrorMessage; michael@0: var formatErrorMessage = Shumway.AVM2.formatErrorMessage; michael@0: var translateErrorMessage = Shumway.AVM2.translateErrorMessage; michael@0: var Errors = Shumway.AVM2.Errors; michael@0: var getErrorMessage = Shumway.AVM2.getErrorMessage; michael@0: var formatErrorMessage = Shumway.AVM2.formatErrorMessage; michael@0: var translateErrorMessage = Shumway.AVM2.translateErrorMessage; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: AVM2.opcodeTable = [ michael@0: null, michael@0: { michael@0: name: 'bkpt', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'nop', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'throw', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'getsuper', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'setsuper', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'dxns', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'dxnslate', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'kill', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'label', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lf32x4', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'sf32x4', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'ifnlt', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifnle', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifngt', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifnge', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'jump', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'iftrue', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'iffalse', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifeq', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifne', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'iflt', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifle', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifgt', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifge', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifstricteq', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'ifstrictne', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'offset', michael@0: size: 's24', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'lookupswitch', michael@0: canThrow: false, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'pushwith', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'popscope', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'nextname', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'hasnext', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushnull', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushundefined', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: { michael@0: name: 'nextvalue', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushbyte', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'value', michael@0: size: 's08', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushshort', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'value', michael@0: size: 's16', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushtrue', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushfalse', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushnan', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pop', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'dup', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'swap', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushstring', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'S' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushint', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'I' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushuint', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'U' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushdouble', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'D' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushscope', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'pushnamespace', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'N' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'hasnext2', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'object', michael@0: size: 'u30', michael@0: type: '' michael@0: }, michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'lix8', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'lix16', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'li8', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'li16', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'li32', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lf32', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lf64', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'si8', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'si16', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'si32', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'sf32', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'sf64', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: { michael@0: name: 'newfunction', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'MI' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'call', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'construct', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callmethod', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callstatic', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'MI' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callsuper', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'returnvoid', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'returnvalue', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'constructsuper', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'constructprop', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callsuperid', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'callproplex', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callinterface', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'callsupervoid', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'callpropvoid', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: }, michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'sxi1', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'sxi8', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'sxi16', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'applytype', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'pushfloat4', michael@0: canThrow: false, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'newobject', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'newarray', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'argCount', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'newactivation', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'newclass', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'CI' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getdescendants', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'newcatch', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'EI' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'findpropglobalstrict', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'findpropglobal', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'findpropstrict', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'findproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'finddef', michael@0: canThrow: true, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'getlex', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'setproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getlocal', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'setlocal', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getglobalscope', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'getscopeobject', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getouterscope', michael@0: canThrow: false, michael@0: operands: null michael@0: }, michael@0: { michael@0: name: 'initproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: null, michael@0: { michael@0: name: 'deleteproperty', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: null, michael@0: { michael@0: name: 'getslot', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'setslot', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'getglobalslot', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'setglobalslot', michael@0: canThrow: false, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'convert_s', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'esc_xelem', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'esc_xattr', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_u', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_d', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_b', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_o', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'checkfilter', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_f', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'unplus', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'convert_f4', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'coerce', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'coerce_b', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_a', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_d', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_s', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'astype', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'astypelate', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_u', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'coerce_o', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'negate', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'increment', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'inclocal', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'decrement', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'declocal', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'typeof', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'not', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'bitnot', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'add', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'subtract', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'multiply', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'divide', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'modulo', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lshift', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'rshift', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'urshift', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'bitand', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'bitor', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'bitxor', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'equals', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'strictequals', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lessthan', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'lessequals', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'greaterthan', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'greaterequals', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'instanceof', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'istype', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'M' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'istypelate', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'in', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'increment_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'decrement_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'inclocal_i', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'declocal_i', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'negate_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'add_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'subtract_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'multiply_i', michael@0: canThrow: true, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'getlocal0', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'getlocal1', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'getlocal2', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'getlocal3', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'setlocal0', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'setlocal1', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'setlocal2', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: { michael@0: name: 'setlocal3', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: { michael@0: name: 'invalid', michael@0: canThrow: false, michael@0: operands: [] michael@0: }, michael@0: null, michael@0: { michael@0: name: 'debug', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'debugType', michael@0: size: 'u08', michael@0: type: '' michael@0: }, michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'S' michael@0: }, michael@0: { michael@0: name: 'reg', michael@0: size: 'u08', michael@0: type: '' michael@0: }, michael@0: { michael@0: name: 'extra', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'debugline', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'lineNumber', michael@0: size: 'u30', michael@0: type: '' michael@0: } michael@0: ] michael@0: }, michael@0: { michael@0: name: 'debugfile', michael@0: canThrow: true, michael@0: operands: [ michael@0: { michael@0: name: 'index', michael@0: size: 'u30', michael@0: type: 'S' michael@0: } michael@0: ] michael@0: }, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null, michael@0: null michael@0: ]; michael@0: function opcodeName(op) { michael@0: return AVM2.opcodeTable[op].name; michael@0: } michael@0: AVM2.opcodeName = opcodeName; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var opcodeTable = Shumway.AVM2.opcodeTable; michael@0: var opcodeName = Shumway.AVM2.opcodeName; michael@0: var opcodeTable = Shumway.AVM2.opcodeTable; michael@0: var opcodeName = Shumway.AVM2.opcodeName; michael@0: var __extends = this.__extends || function (d, b) { michael@0: for (var p in b) michael@0: if (b.hasOwnProperty(p)) michael@0: d[p] = b[p]; michael@0: function __() { michael@0: this.constructor = d; michael@0: } michael@0: __.prototype = b.prototype; michael@0: d.prototype = new __(); michael@0: }; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (ABC) { michael@0: var Timer = Shumway.Metrics.Timer; michael@0: var isString = Shumway.isString; michael@0: var isNumber = Shumway.isNumber; michael@0: var isNumeric = Shumway.isNumeric; michael@0: var isObject = Shumway.isObject; michael@0: var textDecoder = null; michael@0: if (typeof TextDecoder !== 'undefined') { michael@0: textDecoder = new TextDecoder(); michael@0: } michael@0: var AbcStream = function () { michael@0: function AbcStream(bytes) { michael@0: this._bytes = bytes; michael@0: this._view = new DataView(bytes.buffer, bytes.byteOffset); michael@0: this._position = 0; michael@0: } michael@0: AbcStream._getResultBuffer = function (length) { michael@0: if (!AbcStream._resultBuffer || AbcStream._resultBuffer.length < length) { michael@0: AbcStream._resultBuffer = new Int32Array(length * 2); michael@0: } michael@0: return AbcStream._resultBuffer; michael@0: }; michael@0: Object.defineProperty(AbcStream.prototype, 'position', { michael@0: get: function () { michael@0: return this._position; michael@0: }, michael@0: enumerable: true, michael@0: configurable: true michael@0: }); michael@0: AbcStream.prototype.remaining = function () { michael@0: return this._bytes.length - this._position; michael@0: }; michael@0: AbcStream.prototype.seek = function (position) { michael@0: this._position = position; michael@0: }; michael@0: AbcStream.prototype.readU8 = function () { michael@0: return this._bytes[this._position++]; michael@0: }; michael@0: AbcStream.prototype.readU8s = function (count) { michael@0: var b = new Uint8Array(count); michael@0: b.set(this._bytes.subarray(this._position, this._position + count), 0); michael@0: this._position += count; michael@0: return b; michael@0: }; michael@0: AbcStream.prototype.readS8 = function () { michael@0: return this._bytes[this._position++] << 24 >> 24; michael@0: }; michael@0: AbcStream.prototype.readU32 = function () { michael@0: return this.readS32() >>> 0; michael@0: }; michael@0: AbcStream.prototype.readU30 = function () { michael@0: var result = this.readU32(); michael@0: if (result & 3221225472) { michael@0: return result; michael@0: } michael@0: return result; michael@0: }; michael@0: AbcStream.prototype.readU30Unsafe = function () { michael@0: return this.readU32(); michael@0: }; michael@0: AbcStream.prototype.readS16 = function () { michael@0: return this.readU30Unsafe() << 16 >> 16; michael@0: }; michael@0: AbcStream.prototype.readS32 = function () { michael@0: var result = this.readU8(); michael@0: if (result & 128) { michael@0: result = result & 127 | this.readU8() << 7; michael@0: if (result & 16384) { michael@0: result = result & 16383 | this.readU8() << 14; michael@0: if (result & 2097152) { michael@0: result = result & 2097151 | this.readU8() << 21; michael@0: if (result & 268435456) { michael@0: result = result & 268435455 | this.readU8() << 28; michael@0: result = result & 4294967295; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return result; michael@0: }; michael@0: AbcStream.prototype.readWord = function () { michael@0: var result = this._view.getUint32(this._position, true); michael@0: this._position += 4; michael@0: return result; michael@0: }; michael@0: AbcStream.prototype.readS24 = function () { michael@0: var u = this.readU8() | this.readU8() << 8 | this.readU8() << 16; michael@0: return u << 8 >> 8; michael@0: }; michael@0: AbcStream.prototype.readDouble = function () { michael@0: var result = this._view.getFloat64(this._position, true); michael@0: this._position += 8; michael@0: return result; michael@0: }; michael@0: AbcStream.prototype.readUTFString = function (length) { michael@0: if (textDecoder) { michael@0: var position = this._position; michael@0: this._position += length; michael@0: return textDecoder.decode(this._bytes.subarray(position, position + length)); michael@0: } michael@0: var pos = this._position; michael@0: var end = pos + length; michael@0: var bytes = this._bytes; michael@0: var i = 0; michael@0: var result = AbcStream._getResultBuffer(length * 2); michael@0: while (pos < end) { michael@0: var c = bytes[pos++]; michael@0: if (c <= 127) { michael@0: result[i++] = c; michael@0: } else if (c >= 192) { michael@0: var code = 0; michael@0: if (c < 224) { michael@0: code = (c & 31) << 6 | bytes[pos++] & 63; michael@0: } else if (c < 240) { michael@0: code = (c & 15) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63; michael@0: } else { michael@0: code = ((c & 7) << 18 | (bytes[pos++] & 63) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63) - 65536; michael@0: result[i++] = ((code & 1047552) >>> 10) + 55296; michael@0: code = (code & 1023) + 56320; michael@0: } michael@0: result[i++] = code; michael@0: } michael@0: } michael@0: this._position = pos; michael@0: return Shumway.StringUtilities.fromCharCodeArray(result.subarray(0, i)); michael@0: }; michael@0: AbcStream._resultBuffer = new Int32Array(256); michael@0: return AbcStream; michael@0: }(); michael@0: ABC.AbcStream = AbcStream; michael@0: var Parameter = function () { michael@0: function Parameter(name, type, value) { michael@0: this.name = name; michael@0: this.type = type; michael@0: this.value = value; michael@0: } michael@0: return Parameter; michael@0: }(); michael@0: ABC.Parameter = Parameter; michael@0: var Trait = function () { michael@0: function Trait(abc, stream, holder) { michael@0: var constantPool = abc.constantPool; michael@0: var methods = abc.methods; michael@0: var classes = abc.classes; michael@0: var metadata = abc.metadata; michael@0: this.holder = holder; michael@0: this.name = constantPool.multinames[stream.readU30()]; michael@0: var tag = stream.readU8(); michael@0: this.kind = tag & 15; michael@0: this.attributes = tag >> 4 & 15; michael@0: true; michael@0: switch (this.kind) { michael@0: case 0: michael@0: case 6: michael@0: this.slotId = stream.readU30(); michael@0: this.typeName = constantPool.multinames[stream.readU30()]; michael@0: var valueIndex = stream.readU30(); michael@0: this.value = undefined; michael@0: if (valueIndex !== 0) { michael@0: this.hasDefaultValue = true; michael@0: this.value = constantPool.getValue(stream.readU8(), valueIndex); michael@0: } michael@0: break; michael@0: case 1: michael@0: case 3: michael@0: case 2: michael@0: this.dispId = stream.readU30(); michael@0: this.methodInfo = methods[stream.readU30()]; michael@0: this.methodInfo.name = this.name; michael@0: AbcFile.attachHolder(this.methodInfo, this.holder); michael@0: this.methodInfo.abc = abc; michael@0: break; michael@0: case 4: michael@0: this.slotId = stream.readU30(); michael@0: true; michael@0: this.classInfo = classes[stream.readU30()]; michael@0: break; michael@0: case 5: michael@0: true; michael@0: break; michael@0: } michael@0: if (this.attributes & 4) { michael@0: var traitMetadata; michael@0: for (var i = 0, j = stream.readU30(); i < j; i++) { michael@0: var md = metadata[stream.readU30()]; michael@0: if (md.name === '__go_to_definition_help' || md.name === '__go_to_ctor_definition_help') { michael@0: continue; michael@0: } michael@0: if (!traitMetadata) { michael@0: traitMetadata = {}; michael@0: } michael@0: traitMetadata[md.name] = md; michael@0: } michael@0: if (traitMetadata) { michael@0: if (this.isClass()) { michael@0: this.classInfo.metadata = traitMetadata; michael@0: } michael@0: this.metadata = traitMetadata; michael@0: } michael@0: } michael@0: } michael@0: Trait.prototype.isSlot = function () { michael@0: return this.kind === 0; michael@0: }; michael@0: Trait.prototype.isConst = function () { michael@0: return this.kind === 6; michael@0: }; michael@0: Trait.prototype.isMethod = function () { michael@0: return this.kind === 1; michael@0: }; michael@0: Trait.prototype.isClass = function () { michael@0: return this.kind === 4; michael@0: }; michael@0: Trait.prototype.isGetter = function () { michael@0: return this.kind === 2; michael@0: }; michael@0: Trait.prototype.isSetter = function () { michael@0: return this.kind === 3; michael@0: }; michael@0: Trait.prototype.isProtected = function () { michael@0: true; michael@0: return this.name.namespaces[0].isProtected(); michael@0: }; michael@0: Trait.prototype.kindName = function () { michael@0: switch (this.kind) { michael@0: case 0: michael@0: return 'Slot'; michael@0: case 6: michael@0: return 'Const'; michael@0: case 1: michael@0: return 'Method'; michael@0: case 3: michael@0: return 'Setter'; michael@0: case 2: michael@0: return 'Getter'; michael@0: case 4: michael@0: return 'Class'; michael@0: case 5: michael@0: return 'Function'; michael@0: } michael@0: Shumway.Debug.unexpected(); michael@0: }; michael@0: Trait.prototype.isOverride = function () { michael@0: return this.attributes & 2; michael@0: }; michael@0: Trait.prototype.isFinal = function () { michael@0: return this.attributes & 1; michael@0: }; michael@0: Trait.prototype.toString = function () { michael@0: var str = Shumway.IntegerUtilities.getFlags(this.attributes, 'final|override|metadata'.split('|')); michael@0: if (str) { michael@0: str += ' '; michael@0: } michael@0: str += Multiname.getQualifiedName(this.name); michael@0: switch (this.kind) { michael@0: case 0: michael@0: case 6: michael@0: return str + ', typeName: ' + this.typeName + ', slotId: ' + this.slotId + ', value: ' + this.value; michael@0: case 1: michael@0: case 3: michael@0: case 2: michael@0: return str + ', ' + this.kindName() + ': ' + this.methodInfo.name; michael@0: case 4: michael@0: return str + ', slotId: ' + this.slotId + ', class: ' + this.classInfo; michael@0: case 5: michael@0: break; michael@0: } michael@0: }; michael@0: Trait.parseTraits = function (abc, stream, holder) { michael@0: var count = stream.readU30(); michael@0: var traits = []; michael@0: for (var i = 0; i < count; i++) { michael@0: traits.push(new Trait(abc, stream, holder)); michael@0: } michael@0: return traits; michael@0: }; michael@0: return Trait; michael@0: }(); michael@0: ABC.Trait = Trait; michael@0: var Info = function () { michael@0: function Info(abc, index) { michael@0: this.abc = abc; michael@0: this.index = index; michael@0: } michael@0: return Info; michael@0: }(); michael@0: ABC.Info = Info; michael@0: var MethodInfo = function (_super) { michael@0: __extends(MethodInfo, _super); michael@0: function MethodInfo(abc, index, stream) { michael@0: _super.call(this, abc, index); michael@0: var constantPool = abc.constantPool; michael@0: var parameterCount = stream.readU30(); michael@0: this.returnType = constantPool.multinames[stream.readU30()]; michael@0: this.parameters = []; michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: this.parameters.push(new Parameter(undefined, constantPool.multinames[stream.readU30()], undefined)); michael@0: } michael@0: this.debugName = constantPool.strings[stream.readU30()]; michael@0: this.flags = stream.readU8(); michael@0: var optionalCount = 0; michael@0: if (this.flags & 8) { michael@0: optionalCount = stream.readU30(); michael@0: true; michael@0: for (var i = parameterCount - optionalCount; i < parameterCount; i++) { michael@0: var valueIndex = stream.readU30(); michael@0: this.parameters[i].value = constantPool.getValue(stream.readU8(), valueIndex); michael@0: } michael@0: } michael@0: if (this.flags & 128) { michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: if (false) { michael@0: this.parameters[i].name = constantPool.strings[stream.readU30()]; michael@0: } else { michael@0: stream.readU30(); michael@0: this.parameters[i].name = MethodInfo._getParameterName(i); michael@0: } michael@0: } michael@0: } else { michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: this.parameters[i].name = MethodInfo._getParameterName(i); michael@0: } michael@0: } michael@0: } michael@0: MethodInfo._getParameterName = function (i) { michael@0: true; michael@0: return String.fromCharCode('A'.charCodeAt(0) + i); michael@0: }; michael@0: MethodInfo.prototype.toString = function () { michael@0: var flags = Shumway.IntegerUtilities.getFlags(this.flags, 'NEED_ARGUMENTS|NEED_ACTIVATION|NEED_REST|HAS_OPTIONAL|||SET_DXN|HAS_PARAM_NAMES'.split('|')); michael@0: return (flags ? flags + ' ' : '') + this.name; michael@0: }; michael@0: MethodInfo.prototype.hasOptional = function () { michael@0: return !(!(this.flags & 8)); michael@0: }; michael@0: MethodInfo.prototype.needsActivation = function () { michael@0: return !(!(this.flags & 2)); michael@0: }; michael@0: MethodInfo.prototype.needsRest = function () { michael@0: return !(!(this.flags & 4)); michael@0: }; michael@0: MethodInfo.prototype.needsArguments = function () { michael@0: return !(!(this.flags & 1)); michael@0: }; michael@0: MethodInfo.prototype.isNative = function () { michael@0: return !(!(this.flags & 32)); michael@0: }; michael@0: MethodInfo.prototype.isClassMember = function () { michael@0: return this.holder instanceof ClassInfo; michael@0: }; michael@0: MethodInfo.prototype.isInstanceMember = function () { michael@0: return this.holder instanceof InstanceInfo; michael@0: }; michael@0: MethodInfo.prototype.isScriptMember = function () { michael@0: return this.holder instanceof ScriptInfo; michael@0: }; michael@0: MethodInfo.parseException = function (abc, stream) { michael@0: var multinames = abc.constantPool.multinames; michael@0: var ex = { michael@0: start: stream.readU30(), michael@0: end: stream.readU30(), michael@0: target: stream.readU30(), michael@0: typeName: multinames[stream.readU30()], michael@0: varName: multinames[stream.readU30()] michael@0: }; michael@0: true; michael@0: true; michael@0: return ex; michael@0: }; michael@0: MethodInfo.parseBody = function (abc, stream) { michael@0: var constantPool = abc.constantPool; michael@0: var methods = abc.methods; michael@0: var index = stream.readU30(); michael@0: var mi = methods[index]; michael@0: mi.index = index; michael@0: mi.hasBody = true; michael@0: mi.hash = abc.hash + 196608 + index; michael@0: true; michael@0: mi.maxStack = stream.readU30(); michael@0: mi.localCount = stream.readU30(); michael@0: mi.initScopeDepth = stream.readU30(); michael@0: mi.maxScopeDepth = stream.readU30(); michael@0: mi.code = stream.readU8s(stream.readU30()); michael@0: var exceptions = []; michael@0: var exceptionCount = stream.readU30(); michael@0: for (var i = 0; i < exceptionCount; ++i) { michael@0: exceptions.push(MethodInfo.parseException(abc, stream)); michael@0: } michael@0: mi.exceptions = exceptions; michael@0: mi.traits = Trait.parseTraits(abc, stream, mi); michael@0: }; michael@0: MethodInfo.prototype.hasExceptions = function () { michael@0: return this.exceptions.length > 0; michael@0: }; michael@0: return MethodInfo; michael@0: }(Info); michael@0: ABC.MethodInfo = MethodInfo; michael@0: var InstanceInfo = function (_super) { michael@0: __extends(InstanceInfo, _super); michael@0: function InstanceInfo(abc, index, stream) { michael@0: _super.call(this, abc, index); michael@0: this.runtimeId = InstanceInfo.nextID++; michael@0: var constantPool = abc.constantPool; michael@0: var methods = abc.methods; michael@0: this.name = constantPool.multinames[stream.readU30()]; michael@0: true; michael@0: this.superName = constantPool.multinames[stream.readU30()]; michael@0: this.flags = stream.readU8(); michael@0: this.protectedNs = undefined; michael@0: if (this.flags & 8) { michael@0: this.protectedNs = constantPool.namespaces[stream.readU30()]; michael@0: } michael@0: var interfaceCount = stream.readU30(); michael@0: this.interfaces = []; michael@0: for (var i = 0; i < interfaceCount; i++) { michael@0: this.interfaces[i] = constantPool.multinames[stream.readU30()]; michael@0: } michael@0: this.init = methods[stream.readU30()]; michael@0: this.init.isInstanceInitializer = true; michael@0: this.init.name = this.name; michael@0: AbcFile.attachHolder(this.init, this); michael@0: this.traits = Trait.parseTraits(abc, stream, this); michael@0: } michael@0: InstanceInfo.prototype.toString = function () { michael@0: var flags = Shumway.IntegerUtilities.getFlags(this.flags & 8, 'sealed|final|interface|protected'.split('|')); michael@0: var str = (flags ? flags + ' ' : '') + this.name; michael@0: if (this.superName) { michael@0: str += ' extends ' + this.superName; michael@0: } michael@0: return str; michael@0: }; michael@0: InstanceInfo.prototype.isFinal = function () { michael@0: return !(!(this.flags & 2)); michael@0: }; michael@0: InstanceInfo.prototype.isSealed = function () { michael@0: return !(!(this.flags & 1)); michael@0: }; michael@0: InstanceInfo.prototype.isInterface = function () { michael@0: return !(!(this.flags & 4)); michael@0: }; michael@0: InstanceInfo.nextID = 1; michael@0: return InstanceInfo; michael@0: }(Info); michael@0: ABC.InstanceInfo = InstanceInfo; michael@0: var ClassInfo = function (_super) { michael@0: __extends(ClassInfo, _super); michael@0: function ClassInfo(abc, index, stream) { michael@0: _super.call(this, abc, index); michael@0: this.runtimeId = ClassInfo.nextID++; michael@0: this.abc = abc; michael@0: this.hash = abc.hash + 65536 + index; michael@0: this.index = index; michael@0: this.init = abc.methods[stream.readU30()]; michael@0: this.init.isClassInitializer = true; michael@0: AbcFile.attachHolder(this.init, this); michael@0: this.traits = Trait.parseTraits(abc, stream, this); michael@0: this.instanceInfo = abc.instances[index]; michael@0: this.instanceInfo.classInfo = this; michael@0: this.defaultValue = ClassInfo._getDefaultValue(this.instanceInfo.name); michael@0: } michael@0: ClassInfo._getDefaultValue = function (qn) { michael@0: if (Multiname.getQualifiedName(qn) === Multiname.Int || Multiname.getQualifiedName(qn) === Multiname.Uint) { michael@0: return 0; michael@0: } else if (Multiname.getQualifiedName(qn) === Multiname.Number) { michael@0: return NaN; michael@0: } else if (Multiname.getQualifiedName(qn) === Multiname.Boolean) { michael@0: return false; michael@0: } else { michael@0: return null; michael@0: } michael@0: }; michael@0: ClassInfo.prototype.toString = function () { michael@0: return this.instanceInfo.name.toString(); michael@0: }; michael@0: ClassInfo.nextID = 1; michael@0: return ClassInfo; michael@0: }(Info); michael@0: ABC.ClassInfo = ClassInfo; michael@0: var ScriptInfo = function (_super) { michael@0: __extends(ScriptInfo, _super); michael@0: function ScriptInfo(abc, index, stream) { michael@0: _super.call(this, abc, index); michael@0: this.runtimeId = ClassInfo.nextID++; michael@0: this.hash = abc.hash + 131072 + index; michael@0: this.name = abc.name + '$script' + index; michael@0: this.init = abc.methods[stream.readU30()]; michael@0: this.init.isScriptInitializer = true; michael@0: AbcFile.attachHolder(this.init, this); michael@0: this.traits = Trait.parseTraits(abc, stream, this); michael@0: } michael@0: Object.defineProperty(ScriptInfo.prototype, 'entryPoint', { michael@0: get: function () { michael@0: return this.init; michael@0: }, michael@0: enumerable: true, michael@0: configurable: true michael@0: }); michael@0: ScriptInfo.prototype.toString = function () { michael@0: return this.name; michael@0: }; michael@0: ScriptInfo.nextID = 1; michael@0: return ScriptInfo; michael@0: }(Info); michael@0: ABC.ScriptInfo = ScriptInfo; michael@0: var AbcFile = function () { michael@0: function AbcFile(bytes, name, hash) { michael@0: if (typeof hash === 'undefined') { michael@0: hash = 0; michael@0: } michael@0: Timer.start('Parse ABC'); michael@0: this.name = name; michael@0: this.env = {}; michael@0: var computedHash; michael@0: if (!hash || !true) { michael@0: Timer.start('Adler'); michael@0: computedHash = Shumway.HashUtilities.hashBytesTo32BitsAdler(bytes, 0, bytes.length); michael@0: Timer.stop(); michael@0: } michael@0: if (hash) { michael@0: this.hash = hash; michael@0: true; michael@0: } else { michael@0: this.hash = computedHash; michael@0: } michael@0: var n, i; michael@0: var stream = new AbcStream(bytes); michael@0: AbcFile._checkMagic(stream); michael@0: Timer.start('Parse constantPool'); michael@0: this.constantPool = new ConstantPool(stream, this); michael@0: Timer.stop(); michael@0: Timer.start('Parse Method Infos'); michael@0: this.methods = []; michael@0: n = stream.readU30(); michael@0: for (i = 0; i < n; ++i) { michael@0: this.methods.push(new MethodInfo(this, i, stream)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse MetaData Infos'); michael@0: this.metadata = []; michael@0: n = stream.readU30(); michael@0: for (i = 0; i < n; ++i) { michael@0: this.metadata.push(new MetaDataInfo(this, stream)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse Instance Infos'); michael@0: this.instances = []; michael@0: n = stream.readU30(); michael@0: for (i = 0; i < n; ++i) { michael@0: this.instances.push(new InstanceInfo(this, i, stream)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse Class Infos'); michael@0: this.classes = []; michael@0: for (i = 0; i < n; ++i) { michael@0: this.classes.push(new ClassInfo(this, i, stream)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse Script Infos'); michael@0: this.scripts = []; michael@0: n = stream.readU30(); michael@0: for (i = 0; i < n; ++i) { michael@0: this.scripts.push(new ScriptInfo(this, i, stream)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse Method Body Info'); michael@0: n = stream.readU30(); michael@0: for (i = 0; i < n; ++i) { michael@0: MethodInfo.parseBody(this, stream); michael@0: } michael@0: Timer.stop(); michael@0: Timer.stop(); michael@0: } michael@0: AbcFile._checkMagic = function (stream) { michael@0: var magic = stream.readWord(); michael@0: var flashPlayerBrannan = 46 << 16 | 15; michael@0: if (magic < flashPlayerBrannan) { michael@0: throw new Error('Invalid ABC File (magic = ' + Number(magic).toString(16) + ')'); michael@0: } michael@0: }; michael@0: Object.defineProperty(AbcFile.prototype, 'lastScript', { michael@0: get: function () { michael@0: true; michael@0: return this.scripts[this.scripts.length - 1]; michael@0: }, michael@0: enumerable: true, michael@0: configurable: true michael@0: }); michael@0: AbcFile.attachHolder = function (mi, holder) { michael@0: true; michael@0: mi.holder = holder; michael@0: }; michael@0: AbcFile.prototype.toString = function () { michael@0: return this.name; michael@0: }; michael@0: return AbcFile; michael@0: }(); michael@0: ABC.AbcFile = AbcFile; michael@0: var Namespace = function () { michael@0: function Namespace(kind, uri, prefix, uniqueURIHash) { michael@0: if (typeof uri === 'undefined') { michael@0: uri = ''; michael@0: } michael@0: if (uri === undefined) { michael@0: uri = ''; michael@0: } michael@0: if (prefix !== undefined) { michael@0: this.prefix = prefix; michael@0: } michael@0: this.kind = kind; michael@0: this.uri = uri; michael@0: this._buildNamespace(uniqueURIHash); michael@0: } michael@0: Namespace.prototype._buildNamespace = function (uniqueURIHash) { michael@0: if (this.kind === 22) { michael@0: this.kind = 8; michael@0: } michael@0: if (this.isPublic() && this.uri) { michael@0: var n = this.uri.length - 1; michael@0: var mark = this.uri.charCodeAt(n); michael@0: if (mark > Namespace._MIN_API_MARK) { michael@0: this.uri = this.uri.substring(0, n - 1); michael@0: } michael@0: } else if (this.isUnique()) { michael@0: this.uri = 'private ' + uniqueURIHash; michael@0: } michael@0: this.qualifiedName = Namespace._qualifyNamespace(this.kind, this.uri, this.prefix ? this.prefix : ''); michael@0: }; michael@0: Namespace._hashNamespace = function (kind, uri, prefix) { michael@0: var data = new Int32Array(1 + uri.length + prefix.length); michael@0: var j = 0; michael@0: data[j++] = kind; michael@0: var index = Namespace._knownURIs.indexOf(uri); michael@0: if (index >= 0) { michael@0: return kind << 2 | index; michael@0: } else { michael@0: for (var i = 0; i < uri.length; i++) { michael@0: data[j++] = uri.charCodeAt(i); michael@0: } michael@0: } michael@0: for (var i = 0; i < prefix.length; i++) { michael@0: data[j++] = prefix.charCodeAt(i); michael@0: } michael@0: return Shumway.HashUtilities.hashBytesTo32BitsMD5(data, 0, j); michael@0: }; michael@0: Namespace._qualifyNamespace = function (kind, uri, prefix) { michael@0: var key = kind + uri; michael@0: var mangledNamespace = Namespace._mangledNamespaceCache[key]; michael@0: if (mangledNamespace) { michael@0: return mangledNamespace; michael@0: } michael@0: mangledNamespace = Shumway.StringUtilities.variableLengthEncodeInt32(Namespace._hashNamespace(kind, uri, prefix)); michael@0: Namespace._mangledNamespaceMap[mangledNamespace] = { michael@0: kind: kind, michael@0: uri: uri, michael@0: prefix: prefix michael@0: }; michael@0: Namespace._mangledNamespaceCache[key] = mangledNamespace; michael@0: return mangledNamespace; michael@0: }; michael@0: Namespace.fromQualifiedName = function (qn) { michael@0: var length = Shumway.StringUtilities.fromEncoding(qn[0]); michael@0: var mangledNamespace = qn.substring(0, length + 1); michael@0: var ns = Namespace._mangledNamespaceMap[mangledNamespace]; michael@0: return new Namespace(ns.kind, ns.uri, ns.prefix); michael@0: }; michael@0: Namespace.kindFromString = function (str) { michael@0: for (var kind in Namespace._kinds) { michael@0: if (Namespace._kinds[kind] === str) { michael@0: return kind; michael@0: } michael@0: } michael@0: return true; michael@0: }; michael@0: Namespace.createNamespace = function (uri, prefix) { michael@0: return new Namespace(8, uri, prefix); michael@0: }; michael@0: Namespace.parse = function (constantPool, stream, hash) { michael@0: var kind = stream.readU8(); michael@0: var uri = constantPool.strings[stream.readU30()]; michael@0: return new Namespace(kind, uri, undefined, hash); michael@0: }; michael@0: Namespace.prototype.isPublic = function () { michael@0: return this.kind === 8 || this.kind === 22; michael@0: }; michael@0: Namespace.prototype.isProtected = function () { michael@0: return this.kind === 24; michael@0: }; michael@0: Namespace.prototype.isUnique = function () { michael@0: return this.kind === 5 && !this.uri; michael@0: }; michael@0: Namespace.prototype.isDynamic = function () { michael@0: return this.isPublic() && !this.uri; michael@0: }; michael@0: Namespace.prototype.getURI = function () { michael@0: return this.uri; michael@0: }; michael@0: Namespace.prototype.toString = function () { michael@0: return Namespace._kinds[this.kind] + (this.uri ? ' ' + this.uri : ''); michael@0: }; michael@0: Namespace.prototype.clone = function () { michael@0: var ns = Object.create(Namespace.prototype); michael@0: ns.kind = this.kind; michael@0: ns.uri = this.uri; michael@0: ns.prefix = this.prefix; michael@0: ns.qualifiedName = this.qualifiedName; michael@0: return ns; michael@0: }; michael@0: Namespace.prototype.isEqualTo = function (other) { michael@0: return this.qualifiedName === other.qualifiedName; michael@0: }; michael@0: Namespace.prototype.inNamespaceSet = function (set) { michael@0: for (var i = 0; i < set.length; i++) { michael@0: if (set[i].qualifiedName === this.qualifiedName) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: }; michael@0: Namespace.prototype.getAccessModifier = function () { michael@0: return Namespace._kinds[this.kind]; michael@0: }; michael@0: Namespace.prototype.getQualifiedName = function () { michael@0: return this.qualifiedName; michael@0: }; michael@0: Namespace.fromSimpleName = function (simpleName) { michael@0: if (simpleName in Namespace._simpleNameCache) { michael@0: return Namespace._simpleNameCache[simpleName]; michael@0: } michael@0: var namespaceNames; michael@0: if (simpleName.indexOf('[') === 0) { michael@0: true; michael@0: namespaceNames = simpleName.substring(1, simpleName.length - 1).split(','); michael@0: } else { michael@0: namespaceNames = [ michael@0: simpleName michael@0: ]; michael@0: } michael@0: return Namespace._simpleNameCache[simpleName] = namespaceNames.map(function (name) { michael@0: name = name.trim(); michael@0: var kindName, uri; michael@0: if (name.indexOf(' ') > 0) { michael@0: kindName = name.substring(0, name.indexOf(' ')).trim(); michael@0: uri = name.substring(name.indexOf(' ') + 1).trim(); michael@0: } else { michael@0: var kinds = Namespace._kinds; michael@0: if (name === kinds[8] || name === kinds[23] || name === kinds[5] || name === kinds[24] || name === kinds[25] || name === kinds[26]) { michael@0: kindName = name; michael@0: uri = ''; michael@0: } else { michael@0: kindName = Namespace._publicPrefix; michael@0: uri = name; michael@0: } michael@0: } michael@0: return new Namespace(Namespace.kindFromString(kindName), uri); michael@0: }); michael@0: }; michael@0: Namespace._publicPrefix = 'public'; michael@0: Namespace._kinds = function () { michael@0: var map = Shumway.ObjectUtilities.createMap(); michael@0: map[8] = Namespace._publicPrefix; michael@0: map[23] = 'packageInternal'; michael@0: map[5] = 'private'; michael@0: map[24] = 'protected'; michael@0: map[25] = 'explicit'; michael@0: map[26] = 'staticProtected'; michael@0: return map; michael@0: }(); michael@0: Namespace._MIN_API_MARK = 58004; michael@0: Namespace._MAX_API_MARK = 63743; michael@0: Namespace._knownURIs = [ michael@0: '' michael@0: ]; michael@0: Namespace._mangledNamespaceCache = Shumway.ObjectUtilities.createMap(); michael@0: Namespace._mangledNamespaceMap = Shumway.ObjectUtilities.createMap(); michael@0: Namespace.PUBLIC = new Namespace(8); michael@0: Namespace.PROTECTED = new Namespace(24); michael@0: Namespace.PROXY = new Namespace(8, 'http://www.adobe.com/2006/actionscript/flash/proxy'); michael@0: Namespace._simpleNameCache = Shumway.ObjectUtilities.createMap(); michael@0: return Namespace; michael@0: }(); michael@0: ABC.Namespace = Namespace; michael@0: var Multiname = function () { michael@0: function Multiname(namespaces, name, flags) { michael@0: if (typeof flags === 'undefined') { michael@0: flags = 0; michael@0: } michael@0: if (name !== undefined) { michael@0: true; michael@0: } michael@0: this.runtimeId = Multiname._nextID++; michael@0: this.namespaces = namespaces; michael@0: this.name = name; michael@0: this.flags = flags; michael@0: } michael@0: Multiname.parse = function (constantPool, stream, multinames, patchFactoryTypes) { michael@0: var index = 0; michael@0: var kind = stream.readU8(); michael@0: var name, namespaces = [], flags = 0; michael@0: switch (kind) { michael@0: case 7: michael@0: case 13: michael@0: index = stream.readU30(); michael@0: if (index) { michael@0: namespaces = [ michael@0: constantPool.namespaces[index] michael@0: ]; michael@0: } else { michael@0: flags &= ~Multiname.RUNTIME_NAME; michael@0: } michael@0: index = stream.readU30(); michael@0: if (index) { michael@0: name = constantPool.strings[index]; michael@0: } michael@0: break; michael@0: case 15: michael@0: case 16: michael@0: index = stream.readU30(); michael@0: if (index) { michael@0: name = constantPool.strings[index]; michael@0: } else { michael@0: flags &= ~Multiname.RUNTIME_NAME; michael@0: } michael@0: flags |= Multiname.RUNTIME_NAMESPACE; michael@0: break; michael@0: case 17: michael@0: case 18: michael@0: flags |= Multiname.RUNTIME_NAMESPACE; michael@0: flags |= Multiname.RUNTIME_NAME; michael@0: break; michael@0: case 9: michael@0: case 14: michael@0: index = stream.readU30(); michael@0: if (index) { michael@0: name = constantPool.strings[index]; michael@0: } else { michael@0: flags &= ~Multiname.RUNTIME_NAME; michael@0: } michael@0: index = stream.readU30(); michael@0: true; michael@0: namespaces = constantPool.namespaceSets[index]; michael@0: break; michael@0: case 27: michael@0: case 28: michael@0: flags |= Multiname.RUNTIME_NAME; michael@0: index = stream.readU30(); michael@0: true; michael@0: namespaces = constantPool.namespaceSets[index]; michael@0: break; michael@0: case 29: michael@0: var factoryTypeIndex = stream.readU32(); michael@0: if (multinames[factoryTypeIndex]) { michael@0: namespaces = multinames[factoryTypeIndex].namespaces; michael@0: name = multinames[factoryTypeIndex].name; michael@0: } michael@0: var typeParameterCount = stream.readU32(); michael@0: true; michael@0: var typeParameterIndex = stream.readU32(); michael@0: true; michael@0: var mn = new Multiname(namespaces, name, flags); michael@0: mn.typeParameter = multinames[typeParameterIndex]; michael@0: if (!multinames[factoryTypeIndex]) { michael@0: patchFactoryTypes.push({ michael@0: multiname: mn, michael@0: index: factoryTypeIndex michael@0: }); michael@0: } michael@0: return mn; michael@0: default: michael@0: Shumway.Debug.unexpected(); michael@0: break; michael@0: } michael@0: switch (kind) { michael@0: case 13: michael@0: case 16: michael@0: case 18: michael@0: case 14: michael@0: case 28: michael@0: flags |= Multiname.ATTRIBUTE; michael@0: break; michael@0: } michael@0: return new Multiname(namespaces, name, flags); michael@0: }; michael@0: Multiname.isMultiname = function (mn) { michael@0: return typeof mn === 'number' || typeof mn === 'string' || mn instanceof Multiname || mn instanceof Number; michael@0: }; michael@0: Multiname.needsResolution = function (mn) { michael@0: return mn instanceof Multiname && mn.namespaces.length > 1; michael@0: }; michael@0: Multiname.isQName = function (mn) { michael@0: if (mn instanceof Multiname) { michael@0: return mn.namespaces && mn.namespaces.length === 1; michael@0: } michael@0: return true; michael@0: }; michael@0: Multiname.isRuntimeName = function (mn) { michael@0: return mn instanceof Multiname && mn.isRuntimeName(); michael@0: }; michael@0: Multiname.isRuntimeNamespace = function (mn) { michael@0: return mn instanceof Multiname && mn.isRuntimeNamespace(); michael@0: }; michael@0: Multiname.isRuntime = function (mn) { michael@0: return mn instanceof Multiname && mn.isRuntimeName() || mn.isRuntimeNamespace(); michael@0: }; michael@0: Multiname.getQualifiedName = function (mn) { michael@0: true; michael@0: if (mn instanceof Multiname) { michael@0: if (mn.qualifiedName !== undefined) { michael@0: return mn.qualifiedName; michael@0: } michael@0: var name = String(mn.name); michael@0: if (isNumeric(name) && mn.namespaces[0].isPublic()) { michael@0: return mn.qualifiedName = name; michael@0: } michael@0: mn = mn.qualifiedName = Multiname.qualifyName(mn.namespaces[0], name); michael@0: } michael@0: return mn; michael@0: }; michael@0: Multiname.qualifyName = function (namespace, name) { michael@0: return '$' + namespace.qualifiedName + name; michael@0: }; michael@0: Multiname.stripPublicQualifier = function (qn) { michael@0: var publicQualifier = '$' + Namespace.PUBLIC.qualifiedName; michael@0: var index = qn.indexOf(publicQualifier); michael@0: if (index !== 0) { michael@0: return undefined; michael@0: } michael@0: return qn.substring(publicQualifier.length); michael@0: }; michael@0: Multiname.fromQualifiedName = function (qn) { michael@0: if (qn instanceof Multiname) { michael@0: return qn; michael@0: } michael@0: if (isNumeric(qn)) { michael@0: return new Multiname([ michael@0: Namespace.PUBLIC michael@0: ], qn); michael@0: } michael@0: if (qn[0] !== '$') { michael@0: return; michael@0: } michael@0: var ns = Namespace.fromQualifiedName(qn.substring(1)); michael@0: return new Multiname([ michael@0: ns michael@0: ], qn.substring(1 + ns.qualifiedName.length)); michael@0: }; michael@0: Multiname.getNameFromPublicQualifiedName = function (qn) { michael@0: var mn = Multiname.fromQualifiedName(qn); michael@0: true; michael@0: return mn.name; michael@0: }; michael@0: Multiname.getFullQualifiedName = function (mn) { michael@0: var qn = Multiname.getQualifiedName(mn); michael@0: if (mn instanceof Multiname && mn.typeParameter) { michael@0: qn += '$' + Multiname.getFullQualifiedName(mn.typeParameter); michael@0: } michael@0: return qn; michael@0: }; michael@0: Multiname.getPublicQualifiedName = function (name) { michael@0: if (isNumeric(name)) { michael@0: return Shumway.toNumber(name); michael@0: } else if (name !== null && isObject(name)) { michael@0: return name; michael@0: } michael@0: return Multiname.qualifyName(Namespace.PUBLIC, name); michael@0: }; michael@0: Multiname.isPublicQualifiedName = function (qn) { michael@0: return typeof qn === 'number' || isNumeric(qn) || qn.indexOf(Namespace.PUBLIC.qualifiedName) === 1; michael@0: }; michael@0: Multiname.getAccessModifier = function (mn) { michael@0: true; michael@0: if (typeof mn === 'number' || typeof mn === 'string' || mn instanceof Number) { michael@0: return 'public'; michael@0: } michael@0: true; michael@0: return mn.namespaces[0].getAccessModifier(); michael@0: }; michael@0: Multiname.isNumeric = function (mn) { michael@0: if (typeof mn === 'number') { michael@0: return true; michael@0: } else if (typeof mn === 'string') { michael@0: return isNumeric(mn); michael@0: } michael@0: return !isNaN(parseInt(Multiname.getName(mn), 10)); michael@0: }; michael@0: Multiname.getName = function (mn) { michael@0: true; michael@0: true; michael@0: return mn.getName(); michael@0: }; michael@0: Multiname.isAnyName = function (mn) { michael@0: return typeof mn === 'object' && !mn.isRuntimeName() && !mn.name; michael@0: }; michael@0: Multiname.fromSimpleName = function (simpleName) { michael@0: true; michael@0: if (simpleName in Multiname._simpleNameCache) { michael@0: return Multiname._simpleNameCache[simpleName]; michael@0: } michael@0: var nameIndex, namespaceIndex, name, namespace; michael@0: nameIndex = simpleName.lastIndexOf('.'); michael@0: if (nameIndex <= 0) { michael@0: nameIndex = simpleName.lastIndexOf(' '); michael@0: } michael@0: if (nameIndex > 0 && nameIndex < simpleName.length - 1) { michael@0: name = simpleName.substring(nameIndex + 1).trim(); michael@0: namespace = simpleName.substring(0, nameIndex).trim(); michael@0: } else { michael@0: name = simpleName; michael@0: namespace = ''; michael@0: } michael@0: return Multiname._simpleNameCache[simpleName] = new Multiname(Namespace.fromSimpleName(namespace), name); michael@0: }; michael@0: Multiname.prototype.getQName = function (index) { michael@0: true; michael@0: if (!this._qualifiedNameCache) { michael@0: this._qualifiedNameCache = Shumway.ObjectUtilities.createArrayMap(); michael@0: } michael@0: var name = this._qualifiedNameCache[index]; michael@0: if (!name) { michael@0: name = this._qualifiedNameCache[index] = new Multiname([ michael@0: this.namespaces[index] michael@0: ], this.name, this.flags); michael@0: } michael@0: return name; michael@0: }; michael@0: Multiname.prototype.hasQName = function (qn) { michael@0: true; michael@0: if (this.name !== qn.name) { michael@0: return false; michael@0: } michael@0: for (var i = 0; i < this.namespaces.length; i++) { michael@0: if (this.namespaces[i].isEqualTo(qn.namespaces[0])) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: }; michael@0: Multiname.prototype.isAttribute = function () { michael@0: return this.flags & Multiname.ATTRIBUTE; michael@0: }; michael@0: Multiname.prototype.isAnyName = function () { michael@0: return Multiname.isAnyName(this); michael@0: }; michael@0: Multiname.prototype.isAnyNamespace = function () { michael@0: return !this.isRuntimeNamespace() && (this.namespaces.length === 0 || this.isAnyName() && this.namespaces.length !== 1); michael@0: }; michael@0: Multiname.prototype.isRuntimeName = function () { michael@0: return !(!(this.flags & Multiname.RUNTIME_NAME)); michael@0: }; michael@0: Multiname.prototype.isRuntimeNamespace = function () { michael@0: return !(!(this.flags & Multiname.RUNTIME_NAMESPACE)); michael@0: }; michael@0: Multiname.prototype.isRuntime = function () { michael@0: return !(!(this.flags & (Multiname.RUNTIME_NAME | Multiname.RUNTIME_NAMESPACE))); michael@0: }; michael@0: Multiname.prototype.isQName = function () { michael@0: return this.namespaces.length === 1 && !this.isAnyName(); michael@0: }; michael@0: Multiname.prototype.hasTypeParameter = function () { michael@0: return !(!this.typeParameter); michael@0: }; michael@0: Multiname.prototype.getName = function () { michael@0: return this.name; michael@0: }; michael@0: Multiname.prototype.getOriginalName = function () { michael@0: true; michael@0: var name = this.namespaces[0].uri; michael@0: if (name) { michael@0: name += '.'; michael@0: } michael@0: return name + this.name; michael@0: }; michael@0: Multiname.prototype.getNamespace = function () { michael@0: true; michael@0: true; michael@0: return this.namespaces[0]; michael@0: }; michael@0: Multiname.prototype.nameToString = function () { michael@0: if (this.isAnyName()) { michael@0: return '*'; michael@0: } else { michael@0: var name = this.getName(); michael@0: return this.isRuntimeName() ? '[]' : name; michael@0: } michael@0: }; michael@0: Multiname.prototype.hasObjectName = function () { michael@0: return typeof this.name === 'object'; michael@0: }; michael@0: Multiname.prototype.toString = function () { michael@0: var str = this.isAttribute() ? '@' : ''; michael@0: if (this.isAnyNamespace()) { michael@0: str += '*::' + this.nameToString(); michael@0: } else if (this.isRuntimeNamespace()) { michael@0: str += '[]::' + this.nameToString(); michael@0: } else if (this.namespaces.length === 1 && this.isQName()) { michael@0: str += this.namespaces[0].toString() + '::'; michael@0: str += this.nameToString(); michael@0: } else { michael@0: str += '{'; michael@0: for (var i = 0, count = this.namespaces.length; i < count; i++) { michael@0: str += this.namespaces[i].toString(); michael@0: if (i + 1 < count) { michael@0: str += ','; michael@0: } michael@0: } michael@0: str += '}::' + this.nameToString(); michael@0: } michael@0: if (this.hasTypeParameter()) { michael@0: str += '<' + this.typeParameter.toString() + '>'; michael@0: } michael@0: return str; michael@0: }; michael@0: Multiname.ATTRIBUTE = 1; michael@0: Multiname.RUNTIME_NAMESPACE = 2; michael@0: Multiname.RUNTIME_NAME = 4; michael@0: Multiname._nextID = 0; michael@0: Multiname._simpleNameCache = Shumway.ObjectUtilities.createMap(); michael@0: Multiname.Int = Multiname.getPublicQualifiedName('int'); michael@0: Multiname.Uint = Multiname.getPublicQualifiedName('uint'); michael@0: Multiname.Class = Multiname.getPublicQualifiedName('Class'); michael@0: Multiname.Array = Multiname.getPublicQualifiedName('Array'); michael@0: Multiname.Object = Multiname.getPublicQualifiedName('Object'); michael@0: Multiname.String = Multiname.getPublicQualifiedName('String'); michael@0: Multiname.Number = Multiname.getPublicQualifiedName('Number'); michael@0: Multiname.Boolean = Multiname.getPublicQualifiedName('Boolean'); michael@0: Multiname.Function = Multiname.getPublicQualifiedName('Function'); michael@0: Multiname.XML = Multiname.getPublicQualifiedName('XML'); michael@0: Multiname.XMLList = Multiname.getPublicQualifiedName('XMLList'); michael@0: Multiname.TEMPORARY = new Multiname([], ''); michael@0: return Multiname; michael@0: }(); michael@0: ABC.Multiname = Multiname; michael@0: var MetaDataInfo = function () { michael@0: function MetaDataInfo(abc, stream) { michael@0: var strings = abc.constantPool.strings; michael@0: var name = this.name = strings[stream.readU30()]; michael@0: var itemCount = stream.readU30(); michael@0: var keys = []; michael@0: var items = []; michael@0: for (var i = 0; i < itemCount; i++) { michael@0: keys[i] = strings[stream.readU30()]; michael@0: } michael@0: for (var i = 0; i < itemCount; i++) { michael@0: var key = keys[i]; michael@0: items[i] = { michael@0: key: key, michael@0: value: strings[stream.readU30()] michael@0: }; michael@0: if (key && name === 'native') { michael@0: true; michael@0: this[key] = items[i].value; michael@0: } michael@0: } michael@0: this.value = items; michael@0: } michael@0: MetaDataInfo.prototype.toString = function () { michael@0: return '[' + this.name + ']'; michael@0: }; michael@0: return MetaDataInfo; michael@0: }(); michael@0: ABC.MetaDataInfo = MetaDataInfo; michael@0: (function (CONSTANT) { michael@0: CONSTANT[CONSTANT['Undefined'] = 0] = 'Undefined'; michael@0: CONSTANT[CONSTANT['Utf8'] = 1] = 'Utf8'; michael@0: CONSTANT[CONSTANT['Float'] = 2] = 'Float'; michael@0: CONSTANT[CONSTANT['Int'] = 3] = 'Int'; michael@0: CONSTANT[CONSTANT['UInt'] = 4] = 'UInt'; michael@0: CONSTANT[CONSTANT['PrivateNs'] = 5] = 'PrivateNs'; michael@0: CONSTANT[CONSTANT['Double'] = 6] = 'Double'; michael@0: CONSTANT[CONSTANT['QName'] = 7] = 'QName'; michael@0: CONSTANT[CONSTANT['Namespace'] = 8] = 'Namespace'; michael@0: CONSTANT[CONSTANT['Multiname'] = 9] = 'Multiname'; michael@0: CONSTANT[CONSTANT['False'] = 10] = 'False'; michael@0: CONSTANT[CONSTANT['True'] = 11] = 'True'; michael@0: CONSTANT[CONSTANT['Null'] = 12] = 'Null'; michael@0: CONSTANT[CONSTANT['QNameA'] = 13] = 'QNameA'; michael@0: CONSTANT[CONSTANT['MultinameA'] = 14] = 'MultinameA'; michael@0: CONSTANT[CONSTANT['RTQName'] = 15] = 'RTQName'; michael@0: CONSTANT[CONSTANT['RTQNameA'] = 16] = 'RTQNameA'; michael@0: CONSTANT[CONSTANT['RTQNameL'] = 17] = 'RTQNameL'; michael@0: CONSTANT[CONSTANT['RTQNameLA'] = 18] = 'RTQNameLA'; michael@0: CONSTANT[CONSTANT['NameL'] = 19] = 'NameL'; michael@0: CONSTANT[CONSTANT['NameLA'] = 20] = 'NameLA'; michael@0: CONSTANT[CONSTANT['NamespaceSet'] = 21] = 'NamespaceSet'; michael@0: CONSTANT[CONSTANT['PackageNamespace'] = 22] = 'PackageNamespace'; michael@0: CONSTANT[CONSTANT['PackageInternalNs'] = 23] = 'PackageInternalNs'; michael@0: CONSTANT[CONSTANT['ProtectedNamespace'] = 24] = 'ProtectedNamespace'; michael@0: CONSTANT[CONSTANT['ExplicitNamespace'] = 25] = 'ExplicitNamespace'; michael@0: CONSTANT[CONSTANT['StaticProtectedNs'] = 26] = 'StaticProtectedNs'; michael@0: CONSTANT[CONSTANT['MultinameL'] = 27] = 'MultinameL'; michael@0: CONSTANT[CONSTANT['MultinameLA'] = 28] = 'MultinameLA'; michael@0: CONSTANT[CONSTANT['TypeName'] = 29] = 'TypeName'; michael@0: CONSTANT[CONSTANT['ClassSealed'] = 1] = 'ClassSealed'; michael@0: CONSTANT[CONSTANT['ClassFinal'] = 2] = 'ClassFinal'; michael@0: CONSTANT[CONSTANT['ClassInterface'] = 4] = 'ClassInterface'; michael@0: CONSTANT[CONSTANT['ClassProtectedNs'] = 8] = 'ClassProtectedNs'; michael@0: }(ABC.CONSTANT || (ABC.CONSTANT = {}))); michael@0: var CONSTANT = ABC.CONSTANT; michael@0: (function (METHOD) { michael@0: METHOD[METHOD['Arguments'] = 1] = 'Arguments'; michael@0: METHOD[METHOD['Activation'] = 2] = 'Activation'; michael@0: METHOD[METHOD['Needrest'] = 4] = 'Needrest'; michael@0: METHOD[METHOD['HasOptional'] = 8] = 'HasOptional'; michael@0: METHOD[METHOD['IgnoreRest'] = 16] = 'IgnoreRest'; michael@0: METHOD[METHOD['Native'] = 32] = 'Native'; michael@0: METHOD[METHOD['Setsdxns'] = 64] = 'Setsdxns'; michael@0: METHOD[METHOD['HasParamNames'] = 128] = 'HasParamNames'; michael@0: }(ABC.METHOD || (ABC.METHOD = {}))); michael@0: var METHOD = ABC.METHOD; michael@0: (function (TRAIT) { michael@0: TRAIT[TRAIT['Slot'] = 0] = 'Slot'; michael@0: TRAIT[TRAIT['Method'] = 1] = 'Method'; michael@0: TRAIT[TRAIT['Getter'] = 2] = 'Getter'; michael@0: TRAIT[TRAIT['Setter'] = 3] = 'Setter'; michael@0: TRAIT[TRAIT['Class'] = 4] = 'Class'; michael@0: TRAIT[TRAIT['Function'] = 5] = 'Function'; michael@0: TRAIT[TRAIT['Const'] = 6] = 'Const'; michael@0: }(ABC.TRAIT || (ABC.TRAIT = {}))); michael@0: var TRAIT = ABC.TRAIT; michael@0: (function (ATTR) { michael@0: ATTR[ATTR['Final'] = 1] = 'Final'; michael@0: ATTR[ATTR['Override'] = 2] = 'Override'; michael@0: ATTR[ATTR['Metadata'] = 4] = 'Metadata'; michael@0: }(ABC.ATTR || (ABC.ATTR = {}))); michael@0: var ATTR = ABC.ATTR; michael@0: (function (SORT) { michael@0: SORT[SORT['CASEINSENSITIVE'] = 1] = 'CASEINSENSITIVE'; michael@0: SORT[SORT['DESCENDING'] = 2] = 'DESCENDING'; michael@0: SORT[SORT['UNIQUESORT'] = 4] = 'UNIQUESORT'; michael@0: SORT[SORT['RETURNINDEXEDARRAY'] = 8] = 'RETURNINDEXEDARRAY'; michael@0: SORT[SORT['NUMERIC'] = 16] = 'NUMERIC'; michael@0: }(ABC.SORT || (ABC.SORT = {}))); michael@0: var SORT = ABC.SORT; michael@0: (function (OP) { michael@0: OP[OP['bkpt'] = 1] = 'bkpt'; michael@0: OP[OP['nop'] = 2] = 'nop'; michael@0: OP[OP['throw'] = 3] = 'throw'; michael@0: OP[OP['getsuper'] = 4] = 'getsuper'; michael@0: OP[OP['setsuper'] = 5] = 'setsuper'; michael@0: OP[OP['dxns'] = 6] = 'dxns'; michael@0: OP[OP['dxnslate'] = 7] = 'dxnslate'; michael@0: OP[OP['kill'] = 8] = 'kill'; michael@0: OP[OP['label'] = 9] = 'label'; michael@0: OP[OP['lf32x4'] = 10] = 'lf32x4'; michael@0: OP[OP['sf32x4'] = 11] = 'sf32x4'; michael@0: OP[OP['ifnlt'] = 12] = 'ifnlt'; michael@0: OP[OP['ifnle'] = 13] = 'ifnle'; michael@0: OP[OP['ifngt'] = 14] = 'ifngt'; michael@0: OP[OP['ifnge'] = 15] = 'ifnge'; michael@0: OP[OP['jump'] = 16] = 'jump'; michael@0: OP[OP['iftrue'] = 17] = 'iftrue'; michael@0: OP[OP['iffalse'] = 18] = 'iffalse'; michael@0: OP[OP['ifeq'] = 19] = 'ifeq'; michael@0: OP[OP['ifne'] = 20] = 'ifne'; michael@0: OP[OP['iflt'] = 21] = 'iflt'; michael@0: OP[OP['ifle'] = 22] = 'ifle'; michael@0: OP[OP['ifgt'] = 23] = 'ifgt'; michael@0: OP[OP['ifge'] = 24] = 'ifge'; michael@0: OP[OP['ifstricteq'] = 25] = 'ifstricteq'; michael@0: OP[OP['ifstrictne'] = 26] = 'ifstrictne'; michael@0: OP[OP['lookupswitch'] = 27] = 'lookupswitch'; michael@0: OP[OP['pushwith'] = 28] = 'pushwith'; michael@0: OP[OP['popscope'] = 29] = 'popscope'; michael@0: OP[OP['nextname'] = 30] = 'nextname'; michael@0: OP[OP['hasnext'] = 31] = 'hasnext'; michael@0: OP[OP['pushnull'] = 32] = 'pushnull'; michael@0: OP[OP['c'] = 33] = 'c'; michael@0: OP[OP['pushundefined'] = 33] = 'pushundefined'; michael@0: OP[OP['pushfloat'] = 34] = 'pushfloat'; michael@0: OP[OP['nextvalue'] = 35] = 'nextvalue'; michael@0: OP[OP['pushbyte'] = 36] = 'pushbyte'; michael@0: OP[OP['pushshort'] = 37] = 'pushshort'; michael@0: OP[OP['pushtrue'] = 38] = 'pushtrue'; michael@0: OP[OP['pushfalse'] = 39] = 'pushfalse'; michael@0: OP[OP['pushnan'] = 40] = 'pushnan'; michael@0: OP[OP['pop'] = 41] = 'pop'; michael@0: OP[OP['dup'] = 42] = 'dup'; michael@0: OP[OP['swap'] = 43] = 'swap'; michael@0: OP[OP['pushstring'] = 44] = 'pushstring'; michael@0: OP[OP['pushint'] = 45] = 'pushint'; michael@0: OP[OP['pushuint'] = 46] = 'pushuint'; michael@0: OP[OP['pushdouble'] = 47] = 'pushdouble'; michael@0: OP[OP['pushscope'] = 48] = 'pushscope'; michael@0: OP[OP['pushnamespace'] = 49] = 'pushnamespace'; michael@0: OP[OP['hasnext2'] = 50] = 'hasnext2'; michael@0: OP[OP['li8'] = 53] = 'li8'; michael@0: OP[OP['li16'] = 54] = 'li16'; michael@0: OP[OP['li32'] = 55] = 'li32'; michael@0: OP[OP['lf32'] = 56] = 'lf32'; michael@0: OP[OP['lf64'] = 57] = 'lf64'; michael@0: OP[OP['si8'] = 58] = 'si8'; michael@0: OP[OP['si16'] = 59] = 'si16'; michael@0: OP[OP['si32'] = 60] = 'si32'; michael@0: OP[OP['sf32'] = 61] = 'sf32'; michael@0: OP[OP['sf64'] = 62] = 'sf64'; michael@0: OP[OP['newfunction'] = 64] = 'newfunction'; michael@0: OP[OP['call'] = 65] = 'call'; michael@0: OP[OP['construct'] = 66] = 'construct'; michael@0: OP[OP['callmethod'] = 67] = 'callmethod'; michael@0: OP[OP['callstatic'] = 68] = 'callstatic'; michael@0: OP[OP['callsuper'] = 69] = 'callsuper'; michael@0: OP[OP['callproperty'] = 70] = 'callproperty'; michael@0: OP[OP['returnvoid'] = 71] = 'returnvoid'; michael@0: OP[OP['returnvalue'] = 72] = 'returnvalue'; michael@0: OP[OP['constructsuper'] = 73] = 'constructsuper'; michael@0: OP[OP['constructprop'] = 74] = 'constructprop'; michael@0: OP[OP['callsuperid'] = 75] = 'callsuperid'; michael@0: OP[OP['callproplex'] = 76] = 'callproplex'; michael@0: OP[OP['callinterface'] = 77] = 'callinterface'; michael@0: OP[OP['callsupervoid'] = 78] = 'callsupervoid'; michael@0: OP[OP['callpropvoid'] = 79] = 'callpropvoid'; michael@0: OP[OP['sxi1'] = 80] = 'sxi1'; michael@0: OP[OP['sxi8'] = 81] = 'sxi8'; michael@0: OP[OP['sxi16'] = 82] = 'sxi16'; michael@0: OP[OP['applytype'] = 83] = 'applytype'; michael@0: OP[OP['pushfloat4'] = 84] = 'pushfloat4'; michael@0: OP[OP['newobject'] = 85] = 'newobject'; michael@0: OP[OP['newarray'] = 86] = 'newarray'; michael@0: OP[OP['newactivation'] = 87] = 'newactivation'; michael@0: OP[OP['newclass'] = 88] = 'newclass'; michael@0: OP[OP['getdescendants'] = 89] = 'getdescendants'; michael@0: OP[OP['newcatch'] = 90] = 'newcatch'; michael@0: OP[OP['findpropstrict'] = 93] = 'findpropstrict'; michael@0: OP[OP['findproperty'] = 94] = 'findproperty'; michael@0: OP[OP['finddef'] = 95] = 'finddef'; michael@0: OP[OP['getlex'] = 96] = 'getlex'; michael@0: OP[OP['setproperty'] = 97] = 'setproperty'; michael@0: OP[OP['getlocal'] = 98] = 'getlocal'; michael@0: OP[OP['setlocal'] = 99] = 'setlocal'; michael@0: OP[OP['getglobalscope'] = 100] = 'getglobalscope'; michael@0: OP[OP['getscopeobject'] = 101] = 'getscopeobject'; michael@0: OP[OP['getproperty'] = 102] = 'getproperty'; michael@0: OP[OP['getouterscope'] = 103] = 'getouterscope'; michael@0: OP[OP['initproperty'] = 104] = 'initproperty'; michael@0: OP[OP['setpropertylate'] = 105] = 'setpropertylate'; michael@0: OP[OP['deleteproperty'] = 106] = 'deleteproperty'; michael@0: OP[OP['deletepropertylate'] = 107] = 'deletepropertylate'; michael@0: OP[OP['getslot'] = 108] = 'getslot'; michael@0: OP[OP['setslot'] = 109] = 'setslot'; michael@0: OP[OP['getglobalslot'] = 110] = 'getglobalslot'; michael@0: OP[OP['setglobalslot'] = 111] = 'setglobalslot'; michael@0: OP[OP['convert_s'] = 112] = 'convert_s'; michael@0: OP[OP['esc_xelem'] = 113] = 'esc_xelem'; michael@0: OP[OP['esc_xattr'] = 114] = 'esc_xattr'; michael@0: OP[OP['convert_i'] = 115] = 'convert_i'; michael@0: OP[OP['convert_u'] = 116] = 'convert_u'; michael@0: OP[OP['convert_d'] = 117] = 'convert_d'; michael@0: OP[OP['convert_b'] = 118] = 'convert_b'; michael@0: OP[OP['convert_o'] = 119] = 'convert_o'; michael@0: OP[OP['checkfilter'] = 120] = 'checkfilter'; michael@0: OP[OP['convert_f'] = 121] = 'convert_f'; michael@0: OP[OP['unplus'] = 122] = 'unplus'; michael@0: OP[OP['convert_f4'] = 123] = 'convert_f4'; michael@0: OP[OP['coerce'] = 128] = 'coerce'; michael@0: OP[OP['coerce_b'] = 129] = 'coerce_b'; michael@0: OP[OP['coerce_a'] = 130] = 'coerce_a'; michael@0: OP[OP['coerce_i'] = 131] = 'coerce_i'; michael@0: OP[OP['coerce_d'] = 132] = 'coerce_d'; michael@0: OP[OP['coerce_s'] = 133] = 'coerce_s'; michael@0: OP[OP['astype'] = 134] = 'astype'; michael@0: OP[OP['astypelate'] = 135] = 'astypelate'; michael@0: OP[OP['coerce_u'] = 136] = 'coerce_u'; michael@0: OP[OP['coerce_o'] = 137] = 'coerce_o'; michael@0: OP[OP['negate'] = 144] = 'negate'; michael@0: OP[OP['increment'] = 145] = 'increment'; michael@0: OP[OP['inclocal'] = 146] = 'inclocal'; michael@0: OP[OP['decrement'] = 147] = 'decrement'; michael@0: OP[OP['declocal'] = 148] = 'declocal'; michael@0: OP[OP['typeof'] = 149] = 'typeof'; michael@0: OP[OP['not'] = 150] = 'not'; michael@0: OP[OP['bitnot'] = 151] = 'bitnot'; michael@0: OP[OP['add'] = 160] = 'add'; michael@0: OP[OP['subtract'] = 161] = 'subtract'; michael@0: OP[OP['multiply'] = 162] = 'multiply'; michael@0: OP[OP['divide'] = 163] = 'divide'; michael@0: OP[OP['modulo'] = 164] = 'modulo'; michael@0: OP[OP['lshift'] = 165] = 'lshift'; michael@0: OP[OP['rshift'] = 166] = 'rshift'; michael@0: OP[OP['urshift'] = 167] = 'urshift'; michael@0: OP[OP['bitand'] = 168] = 'bitand'; michael@0: OP[OP['bitor'] = 169] = 'bitor'; michael@0: OP[OP['bitxor'] = 170] = 'bitxor'; michael@0: OP[OP['equals'] = 171] = 'equals'; michael@0: OP[OP['strictequals'] = 172] = 'strictequals'; michael@0: OP[OP['lessthan'] = 173] = 'lessthan'; michael@0: OP[OP['lessequals'] = 174] = 'lessequals'; michael@0: OP[OP['greaterthan'] = 175] = 'greaterthan'; michael@0: OP[OP['greaterequals'] = 176] = 'greaterequals'; michael@0: OP[OP['instanceof'] = 177] = 'instanceof'; michael@0: OP[OP['istype'] = 178] = 'istype'; michael@0: OP[OP['istypelate'] = 179] = 'istypelate'; michael@0: OP[OP['in'] = 180] = 'in'; michael@0: OP[OP['increment_i'] = 192] = 'increment_i'; michael@0: OP[OP['decrement_i'] = 193] = 'decrement_i'; michael@0: OP[OP['inclocal_i'] = 194] = 'inclocal_i'; michael@0: OP[OP['declocal_i'] = 195] = 'declocal_i'; michael@0: OP[OP['negate_i'] = 196] = 'negate_i'; michael@0: OP[OP['add_i'] = 197] = 'add_i'; michael@0: OP[OP['subtract_i'] = 198] = 'subtract_i'; michael@0: OP[OP['multiply_i'] = 199] = 'multiply_i'; michael@0: OP[OP['getlocal0'] = 208] = 'getlocal0'; michael@0: OP[OP['getlocal1'] = 209] = 'getlocal1'; michael@0: OP[OP['getlocal2'] = 210] = 'getlocal2'; michael@0: OP[OP['getlocal3'] = 211] = 'getlocal3'; michael@0: OP[OP['setlocal0'] = 212] = 'setlocal0'; michael@0: OP[OP['setlocal1'] = 213] = 'setlocal1'; michael@0: OP[OP['setlocal2'] = 214] = 'setlocal2'; michael@0: OP[OP['setlocal3'] = 215] = 'setlocal3'; michael@0: OP[OP['invalid'] = 237] = 'invalid'; michael@0: OP[OP['debug'] = 239] = 'debug'; michael@0: OP[OP['debugline'] = 240] = 'debugline'; michael@0: OP[OP['debugfile'] = 241] = 'debugfile'; michael@0: OP[OP['bkptline'] = 242] = 'bkptline'; michael@0: OP[OP['timestamp'] = 243] = 'timestamp'; michael@0: }(ABC.OP || (ABC.OP = {}))); michael@0: var OP = ABC.OP; michael@0: var ConstantPool = function () { michael@0: function ConstantPool(stream, abc) { michael@0: var n; michael@0: var ints = [ michael@0: 0 michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: ints.push(stream.readS32()); michael@0: } michael@0: var uints = [ michael@0: 0 michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: uints.push(stream.readU32()); michael@0: } michael@0: var doubles = [ michael@0: NaN michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: doubles.push(stream.readDouble()); michael@0: } michael@0: Timer.start('Parse Strings'); michael@0: var strings = [ michael@0: '' michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: strings.push(stream.readUTFString(stream.readU30())); michael@0: } michael@0: this.positionAfterUTFStrings = stream.position; michael@0: Timer.stop(); michael@0: this.ints = ints; michael@0: this.uints = uints; michael@0: this.doubles = doubles; michael@0: this.strings = strings; michael@0: Timer.start('Parse Namespaces'); michael@0: var namespaces = [ michael@0: undefined michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: namespaces.push(Namespace.parse(this, stream, abc.hash + i)); michael@0: } michael@0: Timer.stop(); michael@0: Timer.start('Parse Namespace Sets'); michael@0: var namespaceSets = [ michael@0: undefined michael@0: ]; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: var count = stream.readU30(); michael@0: var set = []; michael@0: set.runtimeId = ConstantPool._nextNamespaceSetID++; michael@0: for (var j = 0; j < count; ++j) { michael@0: set.push(namespaces[stream.readU30()]); michael@0: } michael@0: namespaceSets.push(set); michael@0: } michael@0: Timer.stop(); michael@0: this.namespaces = namespaces; michael@0: this.namespaceSets = namespaceSets; michael@0: Timer.start('Parse Multinames'); michael@0: var multinames = [ michael@0: undefined michael@0: ]; michael@0: var patchFactoryTypes = []; michael@0: n = stream.readU30(); michael@0: for (var i = 1; i < n; ++i) { michael@0: multinames.push(Multiname.parse(this, stream, multinames, patchFactoryTypes)); michael@0: } michael@0: Timer.stop(); michael@0: this.multinames = multinames; michael@0: } michael@0: ConstantPool.prototype.getValue = function (kind, index) { michael@0: switch (kind) { michael@0: case 3: michael@0: return this.ints[index]; michael@0: case 4: michael@0: return this.uints[index]; michael@0: case 6: michael@0: return this.doubles[index]; michael@0: case 1: michael@0: return this.strings[index]; michael@0: case 11: michael@0: return true; michael@0: case 10: michael@0: return false; michael@0: case 12: michael@0: return null; michael@0: case 0: michael@0: return undefined; michael@0: case 8: michael@0: case 23: michael@0: return this.namespaces[index]; michael@0: case 7: michael@0: case 14: michael@0: case 15: michael@0: case 16: michael@0: case 17: michael@0: case 18: michael@0: case 19: michael@0: case 20: michael@0: return this.multinames[index]; michael@0: case 2: michael@0: Shumway.Debug.warning('TODO: CONSTANT.Float may be deprecated?'); michael@0: break; michael@0: default: michael@0: true; michael@0: } michael@0: }; michael@0: ConstantPool._nextNamespaceSetID = 1; michael@0: return ConstantPool; michael@0: }(); michael@0: ABC.ConstantPool = ConstantPool; michael@0: }(AVM2.ABC || (AVM2.ABC = {}))); michael@0: var ABC = AVM2.ABC; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var AbcFile = Shumway.AVM2.ABC.AbcFile; michael@0: var AbcStream = Shumway.AVM2.ABC.AbcStream; michael@0: var ConstantPool = Shumway.AVM2.ABC.ConstantPool; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var MetaDataInfo = Shumway.AVM2.ABC.MetaDataInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo; michael@0: var Trait = Shumway.AVM2.ABC.Trait; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var ASNamespace = Shumway.AVM2.ABC.Namespace; michael@0: var AbcFile = Shumway.AVM2.ABC.AbcFile; michael@0: var AbcStream = Shumway.AVM2.ABC.AbcStream; michael@0: var ConstantPool = Shumway.AVM2.ABC.ConstantPool; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var MetaDataInfo = Shumway.AVM2.ABC.MetaDataInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo; michael@0: var Trait = Shumway.AVM2.ABC.Trait; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var ASNamespace = Shumway.AVM2.ABC.Namespace; michael@0: var Bytecode = function () { michael@0: function Bytecode(code) { michael@0: var op = code.readU8(); michael@0: this.op = op; michael@0: this.originalPosition = code.position; michael@0: var opdesc = Shumway.AVM2.opcodeTable[op]; michael@0: if (!opdesc) { michael@0: unexpected('Unknown Op ' + op); michael@0: } michael@0: this.canThrow = opdesc.canThrow; michael@0: var i, n; michael@0: switch (op) { michael@0: case OP_lookupswitch: michael@0: var defaultOffset = code.readS24(); michael@0: this.offsets = []; michael@0: var n = code.readU30() + 1; michael@0: for (i = 0; i < n; i++) { michael@0: this.offsets.push(code.readS24()); michael@0: } michael@0: this.offsets.push(defaultOffset); michael@0: break; michael@0: default: michael@0: for (i = 0, n = opdesc.operands.length; i < n; i++) { michael@0: var operand = opdesc.operands[i]; michael@0: switch (operand.size) { michael@0: case 'u08': michael@0: this[operand.name] = code.readU8(); michael@0: break; michael@0: case 's08': michael@0: this[operand.name] = code.readS8(); michael@0: break; michael@0: case 's16': michael@0: this[operand.name] = code.readS16(); michael@0: break; michael@0: case 's24': michael@0: this[operand.name] = code.readS24(); michael@0: break; michael@0: case 'u30': michael@0: this[operand.name] = code.readU30(); michael@0: break; michael@0: case 'u32': michael@0: this[operand.name] = code.readU32(); michael@0: break; michael@0: default: michael@0: unexpected(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: Bytecode.prototype = { michael@0: makeBlockHead: function makeBlockHead(id) { michael@0: if (this.succs) { michael@0: return id; michael@0: } michael@0: this.bid = id; michael@0: this.succs = []; michael@0: this.preds = []; michael@0: this.dominatees = []; michael@0: return id + 1; michael@0: }, michael@0: trace: function trace(writer) { michael@0: if (!this.succs) { michael@0: return; michael@0: } michael@0: writer.writeLn('#' + this.bid); michael@0: }, michael@0: toString: function toString(abc) { michael@0: var opDescription = Shumway.AVM2.opcodeTable[this.op]; michael@0: var str = opDescription.name.padRight(' ', 20); michael@0: var i, j; michael@0: if (this.op === OP_lookupswitch) { michael@0: str += 'targets:'; michael@0: for (i = 0, j = this.targets.length; i < j; i++) { michael@0: str += (i > 0 ? ',' : '') + this.targets[i].position; michael@0: } michael@0: } else { michael@0: for (i = 0, j = opDescription.operands.length; i < j; i++) { michael@0: var operand = opDescription.operands[i]; michael@0: if (operand.name === 'offset') { michael@0: str += 'target:' + this.target.position; michael@0: } else { michael@0: str += operand.name + ': '; michael@0: var value = this[operand.name]; michael@0: if (abc) { michael@0: switch (operand.type) { michael@0: case '': michael@0: str += value; michael@0: break; michael@0: case 'I': michael@0: str += abc.constantPool.ints[value]; michael@0: break; michael@0: case 'U': michael@0: str += abc.constantPool.uints[value]; michael@0: break; michael@0: case 'D': michael@0: str += abc.constantPool.doubles[value]; michael@0: break; michael@0: case 'S': michael@0: str += abc.constantPool.strings[value]; michael@0: break; michael@0: case 'N': michael@0: str += abc.constantPool.namespaces[value]; michael@0: break; michael@0: case 'CI': michael@0: str += abc.classes[value]; michael@0: break; michael@0: case 'M': michael@0: str += abc.constantPool.multinames[value]; michael@0: break; michael@0: default: michael@0: str += '?'; michael@0: break; michael@0: } michael@0: } else { michael@0: str += value; michael@0: } michael@0: } michael@0: if (i < j - 1) { michael@0: str += ', '; michael@0: } michael@0: } michael@0: } michael@0: return str; michael@0: } michael@0: }; michael@0: return Bytecode; michael@0: }(); michael@0: var Analysis = function () { michael@0: function blockSetClass(length, blockById) { michael@0: var BlockSet = BitSetFunctor(length); michael@0: var ADDRESS_BITS_PER_WORD = BlockSet.ADDRESS_BITS_PER_WORD; michael@0: var BITS_PER_WORD = BlockSet.BITS_PER_WORD; michael@0: var BIT_INDEX_MASK = BlockSet.BIT_INDEX_MASK; michael@0: BlockSet.singleton = function singleton(b) { michael@0: var bs = new BlockSet(); michael@0: bs.set(b.bid); michael@0: bs.count = 1; michael@0: bs.dirty = 0; michael@0: return bs; michael@0: }; michael@0: BlockSet.fromBlocks = function fromArray(other) { michael@0: var bs = new BlockSet(); michael@0: bs.setBlocks(other); michael@0: return bs; michael@0: }; michael@0: var Bsp = BlockSet.prototype; michael@0: if (BlockSet.singleword) { michael@0: Bsp.forEachBlock = function forEach(fn) { michael@0: true; michael@0: var byId = blockById; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(byId[k]); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.choose = function choose() { michael@0: var byId = blockById; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: return byId[k]; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.members = function members() { michael@0: var byId = blockById; michael@0: var set = []; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(byId[k]); michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }; michael@0: Bsp.setBlocks = function setBlocks(bs) { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bs.length; i < j; i++) { michael@0: var id = bs[i].bid; michael@0: bits |= 1 << (id & BIT_INDEX_MASK); michael@0: } michael@0: this.bits = bits; michael@0: }; michael@0: } else { michael@0: Bsp.forEachBlock = function forEach(fn) { michael@0: true; michael@0: var byId = blockById; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(byId[i * BITS_PER_WORD + k]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.choose = function choose() { michael@0: var byId = blockById; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: return byId[i * BITS_PER_WORD + k]; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.members = function members() { michael@0: var byId = blockById; michael@0: var set = []; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(byId[i * BITS_PER_WORD + k]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }; michael@0: Bsp.setBlocks = function setBlocks(bs) { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bs.length; i < j; i++) { michael@0: var id = bs[i].bid; michael@0: bits[id >> ADDRESS_BITS_PER_WORD] |= 1 << (id & BIT_INDEX_MASK); michael@0: } michael@0: }; michael@0: } michael@0: return BlockSet; michael@0: } michael@0: function Analysis(method) { michael@0: Counter.count('Analysis'); michael@0: this.method = method; michael@0: if (this.method.code) { michael@0: Timer.start('Normalize'); michael@0: this.normalizeBytecode(); michael@0: Timer.stop(); michael@0: } michael@0: } michael@0: Analysis.prototype = { michael@0: normalizeBytecode: function normalizeBytecode() { michael@0: function getInvalidTarget(cache, offset) { michael@0: if (cache && cache[offset]) { michael@0: return cache[offset]; michael@0: } michael@0: var code = Object.create(Bytecode.prototype); michael@0: code.op = OP_invalid; michael@0: code.position = offset; michael@0: cache && (cache[offset] = code); michael@0: return code; michael@0: } michael@0: var method = this.method; michael@0: function accessLocal(index) { michael@0: if (index-- === 0) michael@0: return; michael@0: if (index < method.parameters.length) { michael@0: method.parameters[index].isUsed = true; michael@0: } michael@0: } michael@0: var bytecodesOffset = []; michael@0: var bytecodes = []; michael@0: var codeStream = new AbcStream(this.method.code); michael@0: var code; michael@0: while (codeStream.remaining() > 0) { michael@0: var pos = codeStream.position; michael@0: code = new Bytecode(codeStream); michael@0: switch (code.op) { michael@0: case OP_nop: michael@0: case OP_label: michael@0: bytecodesOffset[pos] = bytecodes.length; michael@0: continue; michael@0: case OP_lookupswitch: michael@0: this.method.hasLookupSwitches = true; michael@0: code.targets = []; michael@0: var offsets = code.offsets; michael@0: for (var i = 0, j = offsets.length; i < j; i++) { michael@0: offsets[i] += pos; michael@0: } michael@0: break; michael@0: case OP_jump: michael@0: case OP_iflt: michael@0: case OP_ifnlt: michael@0: case OP_ifle: michael@0: case OP_ifnle: michael@0: case OP_ifgt: michael@0: case OP_ifngt: michael@0: case OP_ifge: michael@0: case OP_ifnge: michael@0: case OP_ifeq: michael@0: case OP_ifne: michael@0: case OP_ifstricteq: michael@0: case OP_ifstrictne: michael@0: case OP_iftrue: michael@0: case OP_iffalse: michael@0: code.offset += codeStream.position; michael@0: break; michael@0: case OP_getlocal0: michael@0: case OP_getlocal1: michael@0: case OP_getlocal2: michael@0: case OP_getlocal3: michael@0: accessLocal(code.op - OP_getlocal0); michael@0: break; michael@0: case OP_getlocal: michael@0: accessLocal(code.index); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: code.position = bytecodes.length; michael@0: bytecodesOffset[pos] = bytecodes.length; michael@0: bytecodes.push(code); michael@0: } michael@0: var invalidJumps = {}; michael@0: var newOffset; michael@0: for (var pc = 0, end = bytecodes.length; pc < end; pc++) { michael@0: code = bytecodes[pc]; michael@0: switch (code.op) { michael@0: case OP_lookupswitch: michael@0: var offsets = code.offsets; michael@0: for (var i = 0, j = offsets.length; i < j; i++) { michael@0: newOffset = bytecodesOffset[offsets[i]]; michael@0: code.targets.push(bytecodes[newOffset] || getInvalidTarget(invalidJumps, offsets[i])); michael@0: offsets[i] = newOffset; michael@0: } michael@0: break; michael@0: case OP_jump: michael@0: case OP_iflt: michael@0: case OP_ifnlt: michael@0: case OP_ifle: michael@0: case OP_ifnle: michael@0: case OP_ifgt: michael@0: case OP_ifngt: michael@0: case OP_ifge: michael@0: case OP_ifnge: michael@0: case OP_ifeq: michael@0: case OP_ifne: michael@0: case OP_ifstricteq: michael@0: case OP_ifstrictne: michael@0: case OP_iftrue: michael@0: case OP_iffalse: michael@0: newOffset = bytecodesOffset[code.offset]; michael@0: code.target = bytecodes[newOffset] || getInvalidTarget(invalidJumps, code.offset); michael@0: code.offset = newOffset; michael@0: break; michael@0: default: michael@0: } michael@0: } michael@0: this.bytecodes = bytecodes; michael@0: var exceptions = this.method.exceptions; michael@0: for (var i = 0, j = exceptions.length; i < j; i++) { michael@0: var ex = exceptions[i]; michael@0: ex.start = bytecodesOffset[ex.start]; michael@0: ex.end = bytecodesOffset[ex.end]; michael@0: ex.offset = bytecodesOffset[ex.target]; michael@0: ex.target = bytecodes[ex.offset]; michael@0: ex.target.exception = ex; michael@0: } michael@0: }, michael@0: detectBasicBlocks: function detectBasicBlocks() { michael@0: var bytecodes = this.bytecodes; michael@0: var exceptions = this.method.exceptions; michael@0: var hasExceptions = exceptions.length > 0; michael@0: var blockById = {}; michael@0: var code; michael@0: var pc, end; michael@0: var id = 0; michael@0: function tryTargets(block) { michael@0: var targets = []; michael@0: for (var i = 0, j = exceptions.length; i < j; i++) { michael@0: var ex = exceptions[i]; michael@0: if (block.position >= ex.start && block.end.position <= ex.end) { michael@0: targets.push(ex.target); michael@0: } michael@0: } michael@0: return targets; michael@0: } michael@0: id = bytecodes[0].makeBlockHead(id); michael@0: for (pc = 0, end = bytecodes.length - 1; pc < end; pc++) { michael@0: code = bytecodes[pc]; michael@0: switch (code.op) { michael@0: case OP_returnvoid: michael@0: case OP_returnvalue: michael@0: case OP_throw: michael@0: id = bytecodes[pc + 1].makeBlockHead(id); michael@0: break; michael@0: case OP_lookupswitch: michael@0: var targets = code.targets; michael@0: for (var i = 0, j = targets.length; i < j; i++) { michael@0: id = targets[i].makeBlockHead(id); michael@0: } michael@0: id = bytecodes[pc + 1].makeBlockHead(id); michael@0: break; michael@0: case OP_jump: michael@0: case OP_iflt: michael@0: case OP_ifnlt: michael@0: case OP_ifle: michael@0: case OP_ifnle: michael@0: case OP_ifgt: michael@0: case OP_ifngt: michael@0: case OP_ifge: michael@0: case OP_ifnge: michael@0: case OP_ifeq: michael@0: case OP_ifne: michael@0: case OP_ifstricteq: michael@0: case OP_ifstrictne: michael@0: case OP_iftrue: michael@0: case OP_iffalse: michael@0: id = code.target.makeBlockHead(id); michael@0: id = bytecodes[pc + 1].makeBlockHead(id); michael@0: break; michael@0: default: michael@0: } michael@0: } michael@0: code = bytecodes[end]; michael@0: switch (code.op) { michael@0: case OP_returnvoid: michael@0: case OP_returnvalue: michael@0: case OP_throw: michael@0: break; michael@0: case OP_lookupswitch: michael@0: var targets = code.targets; michael@0: for (var i = 0, j = targets.length; i < j; i++) { michael@0: id = targets[i].makeBlockHead(id); michael@0: } michael@0: break; michael@0: case OP_jump: michael@0: id = code.target.makeBlockHead(id); michael@0: break; michael@0: case OP_iflt: michael@0: case OP_ifnlt: michael@0: case OP_ifle: michael@0: case OP_ifnle: michael@0: case OP_ifgt: michael@0: case OP_ifngt: michael@0: case OP_ifge: michael@0: case OP_ifnge: michael@0: case OP_ifeq: michael@0: case OP_ifne: michael@0: case OP_ifstricteq: michael@0: case OP_ifstrictne: michael@0: case OP_iftrue: michael@0: case OP_iffalse: michael@0: id = code.target.makeBlockHead(id); michael@0: bytecodes[pc + 1] = getInvalidTarget(null, pc + 1); michael@0: id = bytecodes[pc + 1].makeBlockHead(id); michael@0: break; michael@0: default: michael@0: } michael@0: if (hasExceptions) { michael@0: for (var i = 0, j = exceptions.length; i < j; i++) { michael@0: var ex = exceptions[i]; michael@0: var tryStart = bytecodes[ex.start]; michael@0: var afterTry = bytecodes[ex.end + 1]; michael@0: id = tryStart.makeBlockHead(id); michael@0: if (afterTry) { michael@0: id = afterTry.makeBlockHead(id); michael@0: } michael@0: id = ex.target.makeBlockHead(id); michael@0: } michael@0: } michael@0: var currentBlock = bytecodes[0]; michael@0: for (pc = 1, end = bytecodes.length; pc < end; pc++) { michael@0: if (!bytecodes[pc].succs) { michael@0: continue; michael@0: } michael@0: true; michael@0: blockById[currentBlock.bid] = currentBlock; michael@0: code = bytecodes[pc - 1]; michael@0: currentBlock.end = code; michael@0: var nextBlock = bytecodes[pc]; michael@0: switch (code.op) { michael@0: case OP_returnvoid: michael@0: case OP_returnvalue: michael@0: case OP_throw: michael@0: break; michael@0: case OP_lookupswitch: michael@0: for (var i = 0, j = code.targets.length; i < j; i++) { michael@0: currentBlock.succs.push(code.targets[i]); michael@0: } michael@0: break; michael@0: case OP_jump: michael@0: currentBlock.succs.push(code.target); michael@0: break; michael@0: case OP_iflt: michael@0: case OP_ifnlt: michael@0: case OP_ifle: michael@0: case OP_ifnle: michael@0: case OP_ifgt: michael@0: case OP_ifngt: michael@0: case OP_ifge: michael@0: case OP_ifnge: michael@0: case OP_ifeq: michael@0: case OP_ifne: michael@0: case OP_ifstricteq: michael@0: case OP_ifstrictne: michael@0: case OP_iftrue: michael@0: case OP_iffalse: michael@0: currentBlock.succs.push(code.target); michael@0: if (code.target !== nextBlock) { michael@0: currentBlock.succs.push(nextBlock); michael@0: } michael@0: break; michael@0: default: michael@0: currentBlock.succs.push(nextBlock); michael@0: } michael@0: if (hasExceptions) { michael@0: var targets = tryTargets(currentBlock); michael@0: currentBlock.hasCatches = targets.length > 0; michael@0: currentBlock.succs.push.apply(currentBlock.succs, targets); michael@0: } michael@0: currentBlock = nextBlock; michael@0: } michael@0: blockById[currentBlock.bid] = currentBlock; michael@0: code = bytecodes[end - 1]; michael@0: switch (code.op) { michael@0: case OP_lookupswitch: michael@0: for (var i = 0, j = code.targets.length; i < j; i++) { michael@0: currentBlock.succs.push(code.targets[i]); michael@0: } michael@0: break; michael@0: case OP_jump: michael@0: currentBlock.succs.push(code.target); michael@0: break; michael@0: default: michael@0: } michael@0: currentBlock.end = code; michael@0: this.BlockSet = blockSetClass(id, blockById); michael@0: }, michael@0: normalizeReachableBlocks: function normalizeReachableBlocks() { michael@0: var root = this.bytecodes[0]; michael@0: true; michael@0: var ONCE = 1; michael@0: var BUNCH_OF_TIMES = 2; michael@0: var BlockSet = this.BlockSet; michael@0: var blocks = []; michael@0: var visited = {}; michael@0: var ancestors = {}; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var node; michael@0: ancestors[root.bid] = true; michael@0: while (node = worklist.top()) { michael@0: if (visited[node.bid]) { michael@0: if (visited[node.bid] === ONCE) { michael@0: visited[node.bid] = BUNCH_OF_TIMES; michael@0: blocks.push(node); michael@0: var succs = node.succs; michael@0: for (var i = 0, j = succs.length; i < j; i++) { michael@0: succs[i].preds.push(node); michael@0: } michael@0: } michael@0: ancestors[node.bid] = false; michael@0: worklist.pop(); michael@0: continue; michael@0: } michael@0: visited[node.bid] = ONCE; michael@0: ancestors[node.bid] = true; michael@0: var succs = node.succs; michael@0: for (var i = 0, j = succs.length; i < j; i++) { michael@0: var s = succs[i]; michael@0: if (ancestors[s.bid]) { michael@0: if (!node.spbacks) { michael@0: node.spbacks = new BlockSet(); michael@0: } michael@0: node.spbacks.set(s.bid); michael@0: } michael@0: !visited[s.bid] && worklist.push(s); michael@0: } michael@0: } michael@0: this.blocks = blocks.reverse(); michael@0: }, michael@0: computeDominance: function computeDominance() { michael@0: function intersectDominators(doms, b1, b2) { michael@0: var finger1 = b1; michael@0: var finger2 = b2; michael@0: while (finger1 !== finger2) { michael@0: while (finger1 > finger2) { michael@0: finger1 = doms[finger1]; michael@0: } michael@0: while (finger2 > finger1) { michael@0: finger2 = doms[finger2]; michael@0: } michael@0: } michael@0: return finger1; michael@0: } michael@0: var blocks = this.blocks; michael@0: var n = blocks.length; michael@0: var doms = new Array(n); michael@0: doms[0] = 0; michael@0: var rpo = {}; michael@0: for (var b = 0; b < n; b++) { michael@0: rpo[blocks[b].bid] = b; michael@0: } michael@0: var changed = true; michael@0: while (changed) { michael@0: changed = false; michael@0: for (var b = 1; b < n; b++) { michael@0: var preds = blocks[b].preds; michael@0: var j = preds.length; michael@0: var newIdom = rpo[preds[0].bid]; michael@0: if (!(newIdom in doms)) { michael@0: for (var i = 1; i < j; i++) { michael@0: newIdom = rpo[preds[i].bid]; michael@0: if (newIdom in doms) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: true; michael@0: for (var i = 0; i < j; i++) { michael@0: var p = rpo[preds[i].bid]; michael@0: if (p === newIdom) { michael@0: continue; michael@0: } michael@0: if (p in doms) { michael@0: newIdom = intersectDominators(doms, p, newIdom); michael@0: } michael@0: } michael@0: if (doms[b] !== newIdom) { michael@0: doms[b] = newIdom; michael@0: changed = true; michael@0: } michael@0: } michael@0: } michael@0: blocks[0].dominator = blocks[0]; michael@0: var block; michael@0: for (var b = 1; b < n; b++) { michael@0: block = blocks[b]; michael@0: var idom = blocks[doms[b]]; michael@0: block.dominator = idom; michael@0: idom.dominatees.push(block); michael@0: block.npreds = block.preds.length; michael@0: } michael@0: var worklist = [ michael@0: blocks[0] michael@0: ]; michael@0: blocks[0].level || (blocks[0].level = 0); michael@0: while (block = worklist.shift()) { michael@0: var dominatees = block.dominatees; michael@0: for (var i = 0, j = dominatees.length; i < j; i++) { michael@0: dominatees[i].level = block.level + 1; michael@0: } michael@0: worklist.push.apply(worklist, dominatees); michael@0: } michael@0: }, michael@0: analyzeControlFlow: function analyzeControlFlow() { michael@0: true; michael@0: this.detectBasicBlocks(); michael@0: this.normalizeReachableBlocks(); michael@0: this.computeDominance(); michael@0: this.analyzedControlFlow = true; michael@0: return true; michael@0: }, michael@0: markLoops: function markLoops() { michael@0: if (!this.analyzedControlFlow && !this.analyzeControlFlow()) { michael@0: return false; michael@0: } michael@0: var BlockSet = this.BlockSet; michael@0: function findSCCs(root) { michael@0: var preorderId = 1; michael@0: var preorder = {}; michael@0: var assigned = {}; michael@0: var unconnectedNodes = []; michael@0: var pendingNodes = []; michael@0: var sccs = []; michael@0: var level = root.level + 1; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var node; michael@0: var u, s; michael@0: while (node = worklist.top()) { michael@0: if (preorder[node.bid]) { michael@0: if (pendingNodes.peek() === node) { michael@0: pendingNodes.pop(); michael@0: var scc = []; michael@0: do { michael@0: u = unconnectedNodes.pop(); michael@0: assigned[u.bid] = true; michael@0: scc.push(u); michael@0: } while (u !== node); michael@0: if (scc.length > 1 || u.spbacks && u.spbacks.get(u.bid)) { michael@0: sccs.push(scc); michael@0: } michael@0: } michael@0: worklist.pop(); michael@0: continue; michael@0: } michael@0: preorder[node.bid] = preorderId++; michael@0: unconnectedNodes.push(node); michael@0: pendingNodes.push(node); michael@0: var succs = node.succs; michael@0: for (var i = 0, j = succs.length; i < j; i++) { michael@0: s = succs[i]; michael@0: if (s.level < level) { michael@0: continue; michael@0: } michael@0: var sid = s.bid; michael@0: if (!preorder[sid]) { michael@0: worklist.push(s); michael@0: } else if (!assigned[sid]) { michael@0: while (preorder[pendingNodes.peek().bid] > preorder[sid]) { michael@0: pendingNodes.pop(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return sccs; michael@0: } michael@0: function findLoopHeads(blocks) { michael@0: var heads = new BlockSet(); michael@0: for (var i = 0, j = blocks.length; i < j; i++) { michael@0: var block = blocks[i]; michael@0: var spbacks = block.spbacks; michael@0: if (!spbacks) { michael@0: continue; michael@0: } michael@0: var succs = block.succs; michael@0: for (var k = 0, l = succs.length; k < l; k++) { michael@0: var s = succs[k]; michael@0: if (spbacks.get(s.bid)) { michael@0: heads.set(s.dominator.bid); michael@0: } michael@0: } michael@0: } michael@0: return heads.members(); michael@0: } michael@0: function LoopInfo(scc, loopId) { michael@0: var body = new BlockSet(); michael@0: body.setBlocks(scc); michael@0: body.recount(); michael@0: this.id = loopId; michael@0: this.body = body; michael@0: this.exit = new BlockSet(); michael@0: this.save = {}; michael@0: this.head = new BlockSet(); michael@0: this.npreds = 0; michael@0: } michael@0: var heads = findLoopHeads(this.blocks); michael@0: if (heads.length <= 0) { michael@0: this.markedLoops = true; michael@0: return true; michael@0: } michael@0: var worklist = heads.sort(function (a, b) { michael@0: return a.level - b.level; michael@0: }); michael@0: var loopId = 0; michael@0: for (var n = worklist.length - 1; n >= 0; n--) { michael@0: var top = worklist[n]; michael@0: var sccs = findSCCs(top); michael@0: if (sccs.length === 0) { michael@0: continue; michael@0: } michael@0: for (var i = 0, j = sccs.length; i < j; i++) { michael@0: var scc = sccs[i]; michael@0: var loop = new LoopInfo(scc, loopId++); michael@0: for (var k = 0, l = scc.length; k < l; k++) { michael@0: var h = scc[k]; michael@0: if (h.level === top.level + 1 && !h.loop) { michael@0: h.loop = loop; michael@0: loop.head.set(h.bid); michael@0: var preds = h.preds; michael@0: for (var pi = 0, pj = preds.length; pi < pj; pi++) { michael@0: loop.body.get(preds[pi].bid) && h.npreds--; michael@0: } michael@0: loop.npreds += h.npreds; michael@0: } michael@0: } michael@0: for (var k = 0, l = scc.length; k < l; k++) { michael@0: var h = scc[k]; michael@0: if (h.level === top.level + 1) { michael@0: h.npreds = loop.npreds; michael@0: } michael@0: } michael@0: loop.head.recount(); michael@0: } michael@0: } michael@0: this.markedLoops = true; michael@0: return true; michael@0: } michael@0: }; michael@0: return Analysis; michael@0: }(); michael@0: (function (exports) { michael@0: var lang = exports.lang = { michael@0: Node: {}, michael@0: Program: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@body' michael@0: ] michael@0: }, michael@0: Statement: { michael@0: extends: 'Node' michael@0: }, michael@0: EmptyStatement: { michael@0: extends: 'Statement' michael@0: }, michael@0: BlockStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@body' michael@0: ] michael@0: }, michael@0: ExpressionStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@expression' michael@0: ] michael@0: }, michael@0: IfStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@test', michael@0: '@consequent', michael@0: '@alternate' michael@0: ] michael@0: }, michael@0: LabeledStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@label', michael@0: '@body' michael@0: ] michael@0: }, michael@0: BreakStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@label' michael@0: ] michael@0: }, michael@0: ContinueStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@label' michael@0: ] michael@0: }, michael@0: WithStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@object', michael@0: '@body' michael@0: ] michael@0: }, michael@0: SwitchStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@discriminant', michael@0: '@cases', michael@0: 'lexical' michael@0: ] michael@0: }, michael@0: ReturnStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@argument' michael@0: ] michael@0: }, michael@0: ThrowStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@argument' michael@0: ] michael@0: }, michael@0: TryStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@block', michael@0: '@handlers', michael@0: '@finalizer' michael@0: ] michael@0: }, michael@0: WhileStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@test', michael@0: '@body' michael@0: ] michael@0: }, michael@0: DoWhileStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@body', michael@0: '@test' michael@0: ] michael@0: }, michael@0: ForStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@init', michael@0: '@test', michael@0: '@update', michael@0: '@body' michael@0: ] michael@0: }, michael@0: ForInStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@left', michael@0: '@right', michael@0: '@body', michael@0: 'each' michael@0: ] michael@0: }, michael@0: LetStatement: { michael@0: extends: 'Statement', michael@0: fields: [ michael@0: '@head', michael@0: '@body' michael@0: ] michael@0: }, michael@0: DebuggerStatement: { michael@0: extends: 'Statement' michael@0: }, michael@0: Declaration: { michael@0: extends: 'Statement' michael@0: }, michael@0: FunctionDeclaration: { michael@0: extends: 'Declaration', michael@0: fields: [ michael@0: '@id', michael@0: '@params', michael@0: '@body', michael@0: '@decltype', michael@0: 'generator', michael@0: 'expression', michael@0: '@modifiers' michael@0: ] michael@0: }, michael@0: VariableDeclaration: { michael@0: extends: 'Declaration', michael@0: fields: [ michael@0: 'kind', michael@0: '@declarations' michael@0: ] michael@0: }, michael@0: VariableDeclarator: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@id', michael@0: '@init', michael@0: '@decltype', michael@0: '@arguments' michael@0: ] michael@0: }, michael@0: Expression: { michael@0: extends: 'Pattern' michael@0: }, michael@0: ThisExpression: { michael@0: extends: 'Expression' michael@0: }, michael@0: ArrayExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@elements' michael@0: ] michael@0: }, michael@0: ObjectExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@properties' michael@0: ] michael@0: }, michael@0: Property: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@key', michael@0: '@value', michael@0: 'kind' michael@0: ] michael@0: }, michael@0: FunctionExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@id', michael@0: '@params', michael@0: '@body', michael@0: '@decltype', michael@0: 'generator', michael@0: 'expression' michael@0: ] michael@0: }, michael@0: SequenceExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@expressions' michael@0: ] michael@0: }, michael@0: UnaryExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'operator', michael@0: '@argument', michael@0: 'prefix' michael@0: ] michael@0: }, michael@0: BinaryExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'operator', michael@0: '@left', michael@0: '@right' michael@0: ] michael@0: }, michael@0: AssignmentExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@left', michael@0: 'operator', michael@0: '@right' michael@0: ] michael@0: }, michael@0: UpdateExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'operator', michael@0: '@argument', michael@0: 'prefix' michael@0: ] michael@0: }, michael@0: LogicalExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'operator', michael@0: '@left', michael@0: '@right' michael@0: ] michael@0: }, michael@0: ConditionalExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@test', michael@0: '@consequent', michael@0: '@alternate' michael@0: ] michael@0: }, michael@0: NewExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@callee', michael@0: '@arguments' michael@0: ] michael@0: }, michael@0: CallExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@callee', michael@0: '@arguments' michael@0: ] michael@0: }, michael@0: MemberExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@object', michael@0: '@property', michael@0: 'computed', michael@0: 'kind' michael@0: ] michael@0: }, michael@0: YieldExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@argument' michael@0: ] michael@0: }, michael@0: ComprehensionExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@blocks', michael@0: '@filter' michael@0: ] michael@0: }, michael@0: GeneratorExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@blocks', michael@0: '@filter' michael@0: ] michael@0: }, michael@0: LetExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@head', michael@0: '@body' michael@0: ] michael@0: }, michael@0: Pattern: { michael@0: extends: 'Node' michael@0: }, michael@0: ObjectPattern: { michael@0: extends: 'Pattern', michael@0: fields: [ michael@0: '@properties' michael@0: ] michael@0: }, michael@0: ArrayPattern: { michael@0: extends: 'Pattern', michael@0: fields: [ michael@0: '@elements' michael@0: ] michael@0: }, michael@0: SwitchCase: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@test', michael@0: '@consequent' michael@0: ] michael@0: }, michael@0: CatchClause: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@param', michael@0: '@guard', michael@0: '@body' michael@0: ] michael@0: }, michael@0: Identifier: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'name', michael@0: 'kind' michael@0: ] michael@0: }, michael@0: Literal: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: 'value' michael@0: ] michael@0: }, michael@0: Type: { michael@0: extends: 'Node' michael@0: }, michael@0: PointerType: { michael@0: extends: 'Type', michael@0: fields: [ michael@0: '@base' michael@0: ] michael@0: }, michael@0: ArrayType: { michael@0: extends: 'PointerType', michael@0: fields: [ michael@0: 'length' michael@0: ] michael@0: }, michael@0: StructType: { michael@0: extends: 'Type', michael@0: fields: [ michael@0: '@id', michael@0: '@members', michael@0: 'isUnion' michael@0: ] michael@0: }, michael@0: MemberDeclarator: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: 'modifiers', michael@0: '@declarator' michael@0: ] michael@0: }, michael@0: ArrowType: { michael@0: extends: 'Type', michael@0: fields: [ michael@0: '@params', michael@0: '@return' michael@0: ] michael@0: }, michael@0: TypeIdentifier: { michael@0: extends: 'Type', michael@0: fields: [ michael@0: 'name' michael@0: ] michael@0: }, michael@0: TypeAliasDirective: { michael@0: extends: 'Node', michael@0: fields: [ michael@0: '@original', michael@0: '@alias' michael@0: ] michael@0: }, michael@0: CastExpression: { michael@0: extends: 'Expression', michael@0: fields: [ michael@0: '@as', michael@0: '@argument' michael@0: ] michael@0: } michael@0: }; michael@0: function allFields(spec) { michael@0: var fields = [ michael@0: 'leadingComments', michael@0: 'loc' michael@0: ]; michael@0: while (spec) { michael@0: if (spec.fields) { michael@0: fields = spec.fields.concat(fields); michael@0: } michael@0: spec = spec.extends ? lang[spec.extends] : null; michael@0: } michael@0: return fields; michael@0: } michael@0: ; michael@0: exports.allFields = allFields; michael@0: function prefixUnderscore(s) { michael@0: return '_' + s; michael@0: } michael@0: function ensureConstructor(name, spec) { michael@0: if (!exports[name]) { michael@0: var fields = allFields(spec); michael@0: var children = []; michael@0: var body = [ michael@0: 'this.type = "' + name + '";' michael@0: ]; michael@0: for (var i = 0, j = fields.length; i < j; i++) { michael@0: var fname = fields[i]; michael@0: if (fname.charAt(0) === '@') { michael@0: fields[i] = fname = fname.substr(1); michael@0: children.push(fname); michael@0: } michael@0: body.push('this.' + fname + ' = _' + fname + ';'); michael@0: } michael@0: var node = new Function(fields.map(prefixUnderscore), body.join('\n')); michael@0: if (spec.extends) { michael@0: var pnode = ensureConstructor(spec.extends, lang[spec.extends]); michael@0: node.prototype = Object.create(pnode.prototype); michael@0: } michael@0: Object.defineProperty(node.prototype, '_children', { michael@0: value: children, michael@0: writable: true, michael@0: configurable: true, michael@0: enumerable: false michael@0: }); michael@0: exports[name] = node; michael@0: } michael@0: return exports[name]; michael@0: } michael@0: for (var name in lang) { michael@0: ensureConstructor(name, lang[name]); michael@0: } michael@0: exports.makePass = function makePass(name, prop) { michael@0: return function (o) { michael@0: var trans, arr; michael@0: var child, children = this._children; michael@0: for (var i = 0, j = children.length; i < j; i++) { michael@0: if (!(child = this[children[i]])) { michael@0: continue; michael@0: } michael@0: if (child instanceof Array) { michael@0: arr = this[children[i]] = []; michael@0: for (var k = 0, l = child.length; k < l; k++) { michael@0: if (!child[k]) { michael@0: arr.push(child[k]); michael@0: } else if (typeof child[k][name] === 'function') { michael@0: trans = child[k][name](o); michael@0: if (trans !== null) { michael@0: arr.push(trans); michael@0: } michael@0: } michael@0: } michael@0: } else if (typeof child[name] === 'function') { michael@0: trans = child[name](o); michael@0: if (trans === null) { michael@0: this[children[i]] = undefined; michael@0: } else { michael@0: this[children[i]] = trans; michael@0: } michael@0: } michael@0: } michael@0: if (typeof this[prop] === 'function') { michael@0: if (o.logger && typeof this.loc !== 'undefined') { michael@0: o.logger.push(this); michael@0: trans = this[prop](o); michael@0: o.logger.pop(); michael@0: } else { michael@0: trans = this[prop](o); michael@0: } michael@0: if (trans === null) { michael@0: return null; michael@0: } michael@0: return trans ? trans : this; michael@0: } michael@0: return this; michael@0: }; michael@0: }; michael@0: exports.makePass = function makePass(name, prop, backward) { michael@0: return function (o) { michael@0: var trans, arr; michael@0: var child, children = this._children; michael@0: var i, k; michael@0: for (var x = 0, j = children.length; x < j; x++) { michael@0: i = backward ? children.length - 1 - x : x; michael@0: if (!(child = this[children[i]])) { michael@0: continue; michael@0: } michael@0: if (child instanceof Array) { michael@0: arr = this[children[i]] = []; michael@0: var y; michael@0: for (var y = 0, l = child.length; y < l; y++) { michael@0: k = backward ? child.length - 1 - y : y; michael@0: if (!child[k]) { michael@0: if (backward) { michael@0: arr.unshift(child[k]); michael@0: } else { michael@0: arr.push(child[k]); michael@0: } michael@0: } else if (typeof child[k][name] === 'function') { michael@0: trans = child[k][name](o); michael@0: if (trans !== null) { michael@0: if (backward) { michael@0: arr.unshift(trans); michael@0: } else { michael@0: arr.push(trans); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } else if (typeof child[name] === 'function') { michael@0: trans = child[name](o); michael@0: if (trans === null) { michael@0: this[children[i]] = undefined; michael@0: } else { michael@0: this[children[i]] = trans; michael@0: } michael@0: } michael@0: } michael@0: if (typeof this[prop] === 'function') { michael@0: if (o.logger && typeof this.loc !== 'undefined') { michael@0: o.logger.push(this); michael@0: trans = this[prop](o); michael@0: o.logger.pop(); michael@0: } else { michael@0: trans = this[prop](o); michael@0: } michael@0: if (trans === null) { michael@0: return null; michael@0: } michael@0: return trans ? trans : this; michael@0: } michael@0: return this; michael@0: }; michael@0: }; michael@0: exports.lift = function lift(raw) { michael@0: if (!raw) { michael@0: return raw; michael@0: } michael@0: if (raw instanceof Array) { michael@0: return raw.map(function (r) { michael@0: return r ? lift(r) : r; michael@0: }); michael@0: } michael@0: var type = raw.type; michael@0: var Node = exports[type]; michael@0: if (!Node) { michael@0: throw new Error('unknown node type `' + type + '\''); michael@0: } michael@0: var node = new Node(); michael@0: node.loc = raw.loc; michael@0: var fields = allFields(lang[type]); michael@0: for (var i = 0, j = fields.length; i < j; i++) { michael@0: var field; michael@0: if (fields[i].charAt(0) === '@') { michael@0: field = fields[i].substr(1); michael@0: if (raw[field]) { michael@0: node[field] = lift(raw[field]); michael@0: } michael@0: } else { michael@0: field = fields[i]; michael@0: node[field] = raw[field]; michael@0: } michael@0: } michael@0: return node; michael@0: }; michael@0: exports.flatten = function flatten(node) { michael@0: if (!node) { michael@0: return node; michael@0: } michael@0: if (node instanceof Array) { michael@0: return node.map(function (n) { michael@0: return flatten(n); michael@0: }); michael@0: } michael@0: var type = node.type; michael@0: var raw = { michael@0: type: type michael@0: }; michael@0: var fields = allFields(lang[type]); michael@0: for (var i = 0, j = fields.length; i < j; i++) { michael@0: var field; michael@0: if (fields[i].charAt(0) === '@') { michael@0: field = fields[i].substr(1); michael@0: if (node[field]) { michael@0: raw[field] = flatten(node[field]); michael@0: } else { michael@0: raw[field] = null; michael@0: } michael@0: } else { michael@0: field = fields[i]; michael@0: raw[field] = node[field]; michael@0: } michael@0: } michael@0: return raw; michael@0: }; michael@0: }(typeof exports === 'undefined' ? estransform = {} : exports)); michael@0: (function (exports) { michael@0: var Syntax, Precedence, BinaryPrecedence, Regex, VisitorKeys, VisitorOption, isArray, base, indent, json, renumber, hexadecimal, quotes, escapeless, newline, space, parentheses, semicolons, extra, parse; michael@0: Syntax = { michael@0: AssignmentExpression: 'AssignmentExpression', michael@0: ArrayExpression: 'ArrayExpression', michael@0: BlockStatement: 'BlockStatement', michael@0: BinaryExpression: 'BinaryExpression', michael@0: BreakStatement: 'BreakStatement', michael@0: CallExpression: 'CallExpression', michael@0: CatchClause: 'CatchClause', michael@0: ConditionalExpression: 'ConditionalExpression', michael@0: ContinueStatement: 'ContinueStatement', michael@0: DoWhileStatement: 'DoWhileStatement', michael@0: DebuggerStatement: 'DebuggerStatement', michael@0: EmptyStatement: 'EmptyStatement', michael@0: ExpressionStatement: 'ExpressionStatement', michael@0: ForStatement: 'ForStatement', michael@0: ForInStatement: 'ForInStatement', michael@0: FunctionDeclaration: 'FunctionDeclaration', michael@0: FunctionExpression: 'FunctionExpression', michael@0: Identifier: 'Identifier', michael@0: IfStatement: 'IfStatement', michael@0: Literal: 'Literal', michael@0: LabeledStatement: 'LabeledStatement', michael@0: LogicalExpression: 'LogicalExpression', michael@0: MemberExpression: 'MemberExpression', michael@0: NewExpression: 'NewExpression', michael@0: ObjectExpression: 'ObjectExpression', michael@0: Program: 'Program', michael@0: Property: 'Property', michael@0: ReturnStatement: 'ReturnStatement', michael@0: SequenceExpression: 'SequenceExpression', michael@0: SwitchStatement: 'SwitchStatement', michael@0: SwitchCase: 'SwitchCase', michael@0: ThisExpression: 'ThisExpression', michael@0: ThrowStatement: 'ThrowStatement', michael@0: TryStatement: 'TryStatement', michael@0: UnaryExpression: 'UnaryExpression', michael@0: UpdateExpression: 'UpdateExpression', michael@0: VariableDeclaration: 'VariableDeclaration', michael@0: VariableDeclarator: 'VariableDeclarator', michael@0: WhileStatement: 'WhileStatement', michael@0: WithStatement: 'WithStatement' michael@0: }; michael@0: Precedence = { michael@0: Sequence: 0, michael@0: Assignment: 1, michael@0: Conditional: 2, michael@0: LogicalOR: 3, michael@0: LogicalAND: 4, michael@0: BitwiseOR: 5, michael@0: BitwiseXOR: 6, michael@0: BitwiseAND: 7, michael@0: Equality: 8, michael@0: Relational: 9, michael@0: BitwiseSHIFT: 10, michael@0: Additive: 11, michael@0: Multiplicative: 12, michael@0: Unary: 13, michael@0: Postfix: 14, michael@0: Call: 15, michael@0: New: 16, michael@0: Member: 17, michael@0: Primary: 18 michael@0: }; michael@0: BinaryPrecedence = { michael@0: '||': Precedence.LogicalOR, michael@0: '&&': Precedence.LogicalAND, michael@0: '|': Precedence.BitwiseOR, michael@0: '^': Precedence.BitwiseXOR, michael@0: '&': Precedence.BitwiseAND, michael@0: '==': Precedence.Equality, michael@0: '!=': Precedence.Equality, michael@0: '===': Precedence.Equality, michael@0: '!==': Precedence.Equality, michael@0: '<': Precedence.Relational, michael@0: '>': Precedence.Relational, michael@0: '<=': Precedence.Relational, michael@0: '>=': Precedence.Relational, michael@0: 'in': Precedence.Relational, michael@0: 'instanceof': Precedence.Relational, michael@0: '<<': Precedence.BitwiseSHIFT, michael@0: '>>': Precedence.BitwiseSHIFT, michael@0: '>>>': Precedence.BitwiseSHIFT, michael@0: '+': Precedence.Additive, michael@0: '-': Precedence.Additive, michael@0: '*': Precedence.Multiplicative, michael@0: '%': Precedence.Multiplicative, michael@0: '/': Precedence.Multiplicative michael@0: }; michael@0: Regex = { michael@0: NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') michael@0: }; michael@0: function getDefaultOptions() { michael@0: return { michael@0: indent: null, michael@0: base: null, michael@0: parse: null, michael@0: comment: false, michael@0: format: { michael@0: indent: { michael@0: style: ' ', michael@0: base: 0, michael@0: adjustMultilineComment: false michael@0: }, michael@0: json: false, michael@0: renumber: false, michael@0: hexadecimal: false, michael@0: quotes: 'single', michael@0: escapeless: false, michael@0: compact: false, michael@0: parentheses: true, michael@0: semicolons: true michael@0: } michael@0: }; michael@0: } michael@0: function stringToArray(str) { michael@0: var length = str.length, result = [], i; michael@0: for (i = 0; i < length; i += 1) { michael@0: result[i] = str.charAt(i); michael@0: } michael@0: return result; michael@0: } michael@0: function stringRepeat(str, num) { michael@0: var result = ''; michael@0: for (num |= 0; num > 0; num >>>= 1, str += str) { michael@0: if (num & 1) { michael@0: result += str; michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: isArray = Array.isArray; michael@0: if (!isArray) { michael@0: isArray = function isArray(array) { michael@0: return Object.prototype.toString.call(array) === '[object Array]'; michael@0: }; michael@0: } michael@0: function endsWithLineTerminator(str) { michael@0: var len, ch; michael@0: len = str.length; michael@0: ch = str.charAt(len - 1); michael@0: return ch === '\r' || ch === '\n'; michael@0: } michael@0: function shallowCopy(obj) { michael@0: var ret = {}, key; michael@0: for (key in obj) { michael@0: if (obj.hasOwnProperty(key)) { michael@0: ret[key] = obj[key]; michael@0: } michael@0: } michael@0: return ret; michael@0: } michael@0: function deepCopy(obj) { michael@0: var ret = {}, key, val; michael@0: for (key in obj) { michael@0: if (obj.hasOwnProperty(key)) { michael@0: val = obj[key]; michael@0: if (typeof val === 'object' && val !== null) { michael@0: ret[key] = deepCopy(val); michael@0: } else { michael@0: ret[key] = val; michael@0: } michael@0: } michael@0: } michael@0: return ret; michael@0: } michael@0: function updateDeeply(target, override) { michael@0: var key, val; michael@0: function isHashObject(target) { michael@0: return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); michael@0: } michael@0: for (key in override) { michael@0: if (override.hasOwnProperty(key)) { michael@0: val = override[key]; michael@0: if (isHashObject(val)) { michael@0: if (isHashObject(target[key])) { michael@0: updateDeeply(target[key], val); michael@0: } else { michael@0: target[key] = updateDeeply({}, val); michael@0: } michael@0: } else { michael@0: target[key] = val; michael@0: } michael@0: } michael@0: } michael@0: return target; michael@0: } michael@0: function generateNumber(value) { michael@0: var result, point, temp, exponent, pos; michael@0: if (value !== value) { michael@0: throw new Error('Numeric literal whose value is NaN'); michael@0: } michael@0: if (1 / value < 0) { michael@0: throw new Error('Numeric literal whose value is negative'); michael@0: } michael@0: if (value === 1 / 0) { michael@0: return json ? 'null' : renumber ? '1e400' : '1e+400'; michael@0: } michael@0: result = '' + value; michael@0: if (!renumber || result.length < 3) { michael@0: return result; michael@0: } michael@0: point = result.indexOf('.'); michael@0: if (!json && result.charAt(0) === '0' && point === 1) { michael@0: point = 0; michael@0: result = result.slice(1); michael@0: } michael@0: temp = result; michael@0: result = result.replace('e+', 'e'); michael@0: exponent = 0; michael@0: if ((pos = temp.indexOf('e')) > 0) { michael@0: exponent = +temp.slice(pos + 1); michael@0: temp = temp.slice(0, pos); michael@0: } michael@0: if (point >= 0) { michael@0: exponent -= temp.length - point - 1; michael@0: temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; michael@0: } michael@0: pos = 0; michael@0: while (temp.charAt(temp.length + pos - 1) === '0') { michael@0: pos -= 1; michael@0: } michael@0: if (pos !== 0) { michael@0: exponent -= pos; michael@0: temp = temp.slice(0, pos); michael@0: } michael@0: if (exponent !== 0) { michael@0: temp += 'e' + exponent; michael@0: } michael@0: if ((temp.length < result.length || hexadecimal && value > 1000000000000 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length) && +temp === value) { michael@0: result = temp; michael@0: } michael@0: return result; michael@0: } michael@0: function escapeAllowedCharacter(ch, next) { michael@0: var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; michael@0: switch (ch) { michael@0: case '\b': michael@0: result += 'b'; michael@0: break; michael@0: case '\f': michael@0: result += 'f'; michael@0: break; michael@0: case '\t': michael@0: result += 't'; michael@0: break; michael@0: default: michael@0: if (json || code > 255) { michael@0: result += 'u' + '0000'.slice(hex.length) + hex; michael@0: } else if (ch === '\0' && '0123456789'.indexOf(next) < 0) { michael@0: result += '0'; michael@0: } else if (ch === '\v') { michael@0: result += 'v'; michael@0: } else { michael@0: result += 'x' + '00'.slice(hex.length) + hex; michael@0: } michael@0: break; michael@0: } michael@0: return result; michael@0: } michael@0: function escapeDisallowedCharacter(ch) { michael@0: var result = '\\'; michael@0: switch (ch) { michael@0: case '\\': michael@0: result += '\\'; michael@0: break; michael@0: case '\n': michael@0: result += 'n'; michael@0: break; michael@0: case '\r': michael@0: result += 'r'; michael@0: break; michael@0: case '\u2028': michael@0: result += 'u2028'; michael@0: break; michael@0: case '\u2029': michael@0: result += 'u2029'; michael@0: break; michael@0: default: michael@0: throw new Error('Incorrectly classified character'); michael@0: } michael@0: return result; michael@0: } michael@0: function escapeString(str) { michael@0: var result = '', i, len, ch, next, singleQuotes = 0, doubleQuotes = 0, single; michael@0: if (typeof str[0] === 'undefined') { michael@0: str = stringToArray(str); michael@0: } michael@0: for (i = 0, len = str.length; i < len; i += 1) { michael@0: ch = str[i]; michael@0: if (ch === '\'') { michael@0: singleQuotes += 1; michael@0: } else if (ch === '"') { michael@0: doubleQuotes += 1; michael@0: } else if (ch === '/' && json) { michael@0: result += '\\'; michael@0: } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { michael@0: result += escapeDisallowedCharacter(ch); michael@0: continue; michael@0: } else if (json && ch < ' ' || !(json || escapeless || ch >= ' ' && ch <= '~')) { michael@0: result += escapeAllowedCharacter(ch, str[i + 1]); michael@0: continue; michael@0: } michael@0: result += ch; michael@0: } michael@0: single = !(quotes === 'double' || quotes === 'auto' && doubleQuotes < singleQuotes); michael@0: str = result; michael@0: result = single ? '\'' : '"'; michael@0: if (typeof str[0] === 'undefined') { michael@0: str = stringToArray(str); michael@0: } michael@0: for (i = 0, len = str.length; i < len; i += 1) { michael@0: ch = str[i]; michael@0: if (ch === '\'' && single || ch === '"' && !single) { michael@0: result += '\\'; michael@0: } michael@0: result += ch; michael@0: } michael@0: return result + (single ? '\'' : '"'); michael@0: } michael@0: function isWhiteSpace(ch) { michael@0: return '\t\v\f \xa0'.indexOf(ch) >= 0 || ch.charCodeAt(0) >= 5760 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0; michael@0: } michael@0: function isLineTerminator(ch) { michael@0: return '\n\r\u2028\u2029'.indexOf(ch) >= 0; michael@0: } michael@0: function isIdentifierPart(ch) { michael@0: return ch === '$' || ch === '_' || ch === '\\' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch.charCodeAt(0) >= 128 && Regex.NonAsciiIdentifierPart.test(ch); michael@0: } michael@0: function join(left, right) { michael@0: var leftChar = left.charAt(left.length - 1), rightChar = right.charAt(0); michael@0: if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar)) { michael@0: return left + ' ' + right; michael@0: } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { michael@0: return left + right; michael@0: } michael@0: return left + space + right; michael@0: } michael@0: function addIndent(stmt) { michael@0: return base + stmt; michael@0: } michael@0: function calculateSpaces(str) { michael@0: var i; michael@0: for (i = str.length - 1; i >= 0; i -= 1) { michael@0: if (isLineTerminator(str.charAt(i))) { michael@0: break; michael@0: } michael@0: } michael@0: return str.length - 1 - i; michael@0: } michael@0: function adjustMultilineComment(value, specialBase) { michael@0: var array, i, len, line, j, ch, spaces, previousBase; michael@0: array = value.split(/\r\n|[\r\n]/); michael@0: spaces = Number.MAX_VALUE; michael@0: for (i = 1, len = array.length; i < len; i += 1) { michael@0: line = array[i]; michael@0: j = 0; michael@0: while (j < line.length && isWhiteSpace(line[j])) { michael@0: j += 1; michael@0: } michael@0: if (spaces > j) { michael@0: spaces = j; michael@0: } michael@0: } michael@0: if (typeof specialBase !== 'undefined') { michael@0: previousBase = base; michael@0: if (array[1][spaces] === '*') { michael@0: specialBase += ' '; michael@0: } michael@0: base = specialBase; michael@0: } else { michael@0: if (spaces % 2 === 1) { michael@0: spaces -= 1; michael@0: } michael@0: previousBase = base; michael@0: } michael@0: for (i = 1, len = array.length; i < len; i += 1) { michael@0: array[i] = addIndent(array[i].slice(spaces)); michael@0: } michael@0: base = previousBase; michael@0: return array.join('\n'); michael@0: } michael@0: function generateComment(comment, specialBase) { michael@0: if (comment.type === 'Line') { michael@0: if (endsWithLineTerminator(comment.value)) { michael@0: return '//' + comment.value; michael@0: } else { michael@0: return '//' + comment.value + '\n'; michael@0: } michael@0: } michael@0: if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { michael@0: return adjustMultilineComment('/*' + comment.value + '*/', specialBase); michael@0: } michael@0: return '/*' + comment.value + '*/'; michael@0: } michael@0: function addCommentsToStatement(stmt, result) { michael@0: var i, len, comment, save, node, tailingToStatement, specialBase, fragment; michael@0: if (stmt.leadingComments) { michael@0: save = result; michael@0: comment = stmt.leadingComments[0]; michael@0: result = generateComment(comment); michael@0: if (!endsWithLineTerminator(result)) { michael@0: result += '\n'; michael@0: } michael@0: for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { michael@0: comment = stmt.leadingComments[i]; michael@0: fragment = generateComment(comment); michael@0: if (!endsWithLineTerminator(fragment)) { michael@0: fragment += '\n'; michael@0: } michael@0: result += addIndent(fragment); michael@0: } michael@0: result += addIndent(save); michael@0: } michael@0: if (stmt.trailingComments) { michael@0: tailingToStatement = !endsWithLineTerminator(result); michael@0: specialBase = stringRepeat(' ', calculateSpaces(base + result + indent)); michael@0: for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { michael@0: comment = stmt.trailingComments[i]; michael@0: if (tailingToStatement) { michael@0: if (i === 0) { michael@0: result += indent; michael@0: } else { michael@0: result += specialBase; michael@0: } michael@0: result += generateComment(comment, specialBase); michael@0: } else { michael@0: result += addIndent(generateComment(comment)); michael@0: } michael@0: if (i !== len - 1 && !endsWithLineTerminator(result)) { michael@0: result += '\n'; michael@0: } michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: function parenthesize(text, current, should) { michael@0: if (current < should) { michael@0: return '(' + text + ')'; michael@0: } michael@0: return text; michael@0: } michael@0: function maybeBlock(stmt, semicolonOptional) { michael@0: var previousBase, result, noLeadingComment; michael@0: noLeadingComment = !extra.comment || !stmt.leadingComments; michael@0: if (stmt.type === Syntax.BlockStatement && noLeadingComment) { michael@0: return space + generateStatement(stmt); michael@0: } michael@0: if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { michael@0: return ';'; michael@0: } michael@0: previousBase = base; michael@0: base += indent; michael@0: result = newline + addIndent(generateStatement(stmt, { michael@0: semicolonOptional: semicolonOptional michael@0: })); michael@0: base = previousBase; michael@0: return result; michael@0: } michael@0: function maybeBlockSuffix(stmt, result) { michael@0: if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !endsWithLineTerminator(result)) { michael@0: return space; michael@0: } michael@0: if (endsWithLineTerminator(result)) { michael@0: return addIndent(''); michael@0: } michael@0: return (newline === '' ? ' ' : newline) + addIndent(''); michael@0: } michael@0: function generateFunctionBody(node) { michael@0: var result, i, len; michael@0: result = '('; michael@0: for (i = 0, len = node.params.length; i < len; i += 1) { michael@0: result += node.params[i].name; michael@0: if (i + 1 < len) { michael@0: result += ',' + space; michael@0: } michael@0: } michael@0: return result + ')' + maybeBlock(node.body); michael@0: } michael@0: function generateExpression(expr, option) { michael@0: var result, precedence, currentPrecedence, previousBase, i, len, raw, fragment, allowIn, allowCall, allowUnparenthesizedNew; michael@0: precedence = option.precedence; michael@0: allowIn = option.allowIn; michael@0: allowCall = option.allowCall; michael@0: switch (expr.type) { michael@0: case Syntax.SequenceExpression: michael@0: result = ''; michael@0: allowIn |= Precedence.Sequence < precedence; michael@0: for (i = 0, len = expr.expressions.length; i < len; i += 1) { michael@0: result += generateExpression(expr.expressions[i], { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }); michael@0: if (i + 1 < len) { michael@0: result += ',' + space; michael@0: } michael@0: } michael@0: result = parenthesize(result, Precedence.Sequence, precedence); michael@0: break; michael@0: case Syntax.AssignmentExpression: michael@0: allowIn |= Precedence.Assignment < precedence; michael@0: result = parenthesize(generateExpression(expr.left, { michael@0: precedence: Precedence.Call, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }) + space + expr.operator + space + generateExpression(expr.right, { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }), Precedence.Assignment, precedence); michael@0: break; michael@0: case Syntax.ConditionalExpression: michael@0: allowIn |= Precedence.Conditional < precedence; michael@0: result = parenthesize(generateExpression(expr.test, { michael@0: precedence: Precedence.LogicalOR, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }) + space + '?' + space + generateExpression(expr.consequent, { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }) + space + ':' + space + generateExpression(expr.alternate, { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }), Precedence.Conditional, precedence); michael@0: break; michael@0: case Syntax.LogicalExpression: michael@0: case Syntax.BinaryExpression: michael@0: currentPrecedence = BinaryPrecedence[expr.operator]; michael@0: allowIn |= currentPrecedence < precedence; michael@0: result = join(generateExpression(expr.left, { michael@0: precedence: currentPrecedence, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }), expr.operator); michael@0: fragment = generateExpression(expr.right, { michael@0: precedence: currentPrecedence + 1, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }); michael@0: if (expr.operator === '/' && result.charAt(result.length - 1) === '/') { michael@0: result += ' ' + fragment; michael@0: } else { michael@0: result = join(result, fragment); michael@0: } michael@0: if (expr.operator === 'in' && !allowIn) { michael@0: result = '(' + result + ')'; michael@0: } else { michael@0: result = parenthesize(result, currentPrecedence, precedence); michael@0: } michael@0: break; michael@0: case Syntax.CallExpression: michael@0: result = generateExpression(expr.callee, { michael@0: precedence: Precedence.Call, michael@0: allowIn: true, michael@0: allowCall: true, michael@0: allowUnparenthesizedNew: false michael@0: }); michael@0: result += '('; michael@0: for (i = 0, len = expr['arguments'].length; i < len; i += 1) { michael@0: result += generateExpression(expr['arguments'][i], { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: if (i + 1 < len) { michael@0: result += ',' + space; michael@0: } michael@0: } michael@0: result += ')'; michael@0: if (!allowCall) { michael@0: result = '(' + result + ')'; michael@0: } else { michael@0: result = parenthesize(result, Precedence.Call, precedence); michael@0: } michael@0: break; michael@0: case Syntax.NewExpression: michael@0: len = expr['arguments'].length; michael@0: allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; michael@0: result = join('new', generateExpression(expr.callee, { michael@0: precedence: Precedence.New, michael@0: allowIn: true, michael@0: allowCall: false, michael@0: allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 michael@0: })); michael@0: if (!allowUnparenthesizedNew || parentheses || len > 0) { michael@0: result += '('; michael@0: for (i = 0; i < len; i += 1) { michael@0: result += generateExpression(expr['arguments'][i], { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: if (i + 1 < len) { michael@0: result += ',' + space; michael@0: } michael@0: } michael@0: result += ')'; michael@0: } michael@0: result = parenthesize(result, Precedence.New, precedence); michael@0: break; michael@0: case Syntax.MemberExpression: michael@0: result = generateExpression(expr.object, { michael@0: precedence: Precedence.Call, michael@0: allowIn: true, michael@0: allowCall: allowCall, michael@0: allowUnparenthesizedNew: false michael@0: }); michael@0: if (expr.computed) { michael@0: result += '[' + generateExpression(expr.property, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: allowCall michael@0: }) + ']'; michael@0: } else { michael@0: if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { michael@0: if (result.indexOf('.') < 0) { michael@0: if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) { michael@0: result += '.'; michael@0: } michael@0: } michael@0: } michael@0: result += '.' + expr.property.name; michael@0: } michael@0: result = parenthesize(result, Precedence.Member, precedence); michael@0: break; michael@0: case Syntax.UnaryExpression: michael@0: fragment = generateExpression(expr.argument, { michael@0: precedence: Precedence.Unary + (expr.argument.type === Syntax.UnaryExpression && expr.operator.length < 3 && expr.argument.operator === expr.operator ? 1 : 0), michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: if (space === '') { michael@0: result = join(expr.operator, fragment); michael@0: } else { michael@0: result = expr.operator; michael@0: if (result.length > 2) { michael@0: result += ' '; michael@0: } michael@0: result += fragment; michael@0: } michael@0: result = parenthesize(result, Precedence.Unary, precedence); michael@0: break; michael@0: case Syntax.UpdateExpression: michael@0: if (expr.prefix) { michael@0: result = parenthesize(expr.operator + generateExpression(expr.argument, { michael@0: precedence: Precedence.Unary, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }), Precedence.Unary, precedence); michael@0: } else { michael@0: result = parenthesize(generateExpression(expr.argument, { michael@0: precedence: Precedence.Postfix, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + expr.operator, Precedence.Postfix, precedence); michael@0: } michael@0: break; michael@0: case Syntax.FunctionExpression: michael@0: result = 'function'; michael@0: if (expr.id) { michael@0: result += ' ' + expr.id.name; michael@0: } else { michael@0: result += space; michael@0: } michael@0: result += generateFunctionBody(expr); michael@0: break; michael@0: case Syntax.ArrayExpression: michael@0: if (!expr.elements.length) { michael@0: result = '[]'; michael@0: break; michael@0: } michael@0: result = '[' + newline; michael@0: previousBase = base; michael@0: base += indent; michael@0: for (i = 0, len = expr.elements.length; i < len; i += 1) { michael@0: if (!expr.elements[i]) { michael@0: result += addIndent(''); michael@0: if (i + 1 === len) { michael@0: result += ','; michael@0: } michael@0: } else { michael@0: result += addIndent(generateExpression(expr.elements[i], { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })); michael@0: } michael@0: if (i + 1 < len) { michael@0: result += ',' + newline; michael@0: } michael@0: } michael@0: base = previousBase; michael@0: if (!endsWithLineTerminator(result)) { michael@0: result += newline; michael@0: } michael@0: result += addIndent(']'); michael@0: break; michael@0: case Syntax.Property: michael@0: if (expr.kind === 'get' || expr.kind === 'set') { michael@0: result = expr.kind + ' ' + generateExpression(expr.key, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + generateFunctionBody(expr.value); michael@0: } else { michael@0: result = generateExpression(expr.key, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ':' + space + generateExpression(expr.value, { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: } michael@0: break; michael@0: case Syntax.ObjectExpression: michael@0: if (!expr.properties.length) { michael@0: result = '{}'; michael@0: break; michael@0: } michael@0: result = '{' + newline; michael@0: previousBase = base; michael@0: base += indent; michael@0: for (i = 0, len = expr.properties.length; i < len; i += 1) { michael@0: result += addIndent(generateExpression(expr.properties[i], { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })); michael@0: if (i + 1 < len) { michael@0: result += ',' + newline; michael@0: } michael@0: } michael@0: base = previousBase; michael@0: if (!endsWithLineTerminator(result)) { michael@0: result += newline; michael@0: } michael@0: result += addIndent('}'); michael@0: break; michael@0: case Syntax.ThisExpression: michael@0: result = 'this'; michael@0: break; michael@0: case Syntax.Identifier: michael@0: result = expr.name; michael@0: break; michael@0: case Syntax.Literal: michael@0: if (expr.hasOwnProperty('raw') && parse) { michael@0: try { michael@0: raw = parse(expr.raw).body[0].expression; michael@0: if (raw.type === Syntax.Literal) { michael@0: if (raw.value === expr.value) { michael@0: result = expr.raw; michael@0: break; michael@0: } michael@0: } michael@0: } catch (e) { michael@0: } michael@0: } michael@0: if (expr.value === null) { michael@0: result = 'null'; michael@0: break; michael@0: } michael@0: if (typeof expr.value === 'string') { michael@0: result = escapeString(expr.value); michael@0: break; michael@0: } michael@0: if (typeof expr.value === 'number') { michael@0: result = generateNumber(expr.value); michael@0: break; michael@0: } michael@0: result = expr.value.toString(); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: if (result === undefined) { michael@0: throw new Error('Unknown expression type: ' + expr.type); michael@0: } michael@0: return result; michael@0: } michael@0: function generateStatement(stmt, option) { michael@0: var i, len, result, previousBase, node, allowIn, fragment, semicolon; michael@0: allowIn = true; michael@0: semicolon = ';'; michael@0: if (option) { michael@0: allowIn = option.allowIn === undefined || option.allowIn; michael@0: if (!semicolons && option.semicolonOptional === true) { michael@0: semicolon = ''; michael@0: } michael@0: } michael@0: switch (stmt.type) { michael@0: case Syntax.BlockStatement: michael@0: result = '{' + newline; michael@0: previousBase = base; michael@0: base += indent; michael@0: for (i = 0, len = stmt.body.length; i < len; i += 1) { michael@0: fragment = addIndent(generateStatement(stmt.body[i], { michael@0: semicolonOptional: i === len - 1 michael@0: })); michael@0: result += fragment; michael@0: if (!endsWithLineTerminator(fragment)) { michael@0: result += newline; michael@0: } michael@0: } michael@0: base = previousBase; michael@0: result += addIndent('}'); michael@0: break; michael@0: case Syntax.BreakStatement: michael@0: if (stmt.label) { michael@0: result = 'break ' + stmt.label.name + semicolon; michael@0: } else { michael@0: result = 'break' + semicolon; michael@0: } michael@0: break; michael@0: case Syntax.ContinueStatement: michael@0: if (stmt.label) { michael@0: result = 'continue ' + stmt.label.name + semicolon; michael@0: } else { michael@0: result = 'continue' + semicolon; michael@0: } michael@0: break; michael@0: case Syntax.DoWhileStatement: michael@0: result = join('do', maybeBlock(stmt.body)); michael@0: result += maybeBlockSuffix(stmt.body, result); michael@0: result += 'while' + space + '(' + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')' + semicolon; michael@0: break; michael@0: case Syntax.CatchClause: michael@0: previousBase = base; michael@0: base += indent; michael@0: result = 'catch' + space + '(' + generateExpression(stmt.param, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.body); michael@0: break; michael@0: case Syntax.DebuggerStatement: michael@0: result = 'debugger' + semicolon; michael@0: break; michael@0: case Syntax.EmptyStatement: michael@0: result = ';'; michael@0: break; michael@0: case Syntax.ExpressionStatement: michael@0: result = generateExpression(stmt.expression, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: if (result.charAt(0) === '{' || result.slice(0, 8) === 'function' && ' ('.indexOf(result.charAt(8)) >= 0) { michael@0: result = '(' + result + ')' + semicolon; michael@0: } else { michael@0: result += semicolon; michael@0: } michael@0: break; michael@0: case Syntax.VariableDeclarator: michael@0: if (stmt.init) { michael@0: result = stmt.id.name + space + '=' + space + generateExpression(stmt.init, { michael@0: precedence: Precedence.Assignment, michael@0: allowIn: allowIn, michael@0: allowCall: true michael@0: }); michael@0: } else { michael@0: result = stmt.id.name; michael@0: } michael@0: break; michael@0: case Syntax.VariableDeclaration: michael@0: result = stmt.kind; michael@0: if (stmt.declarations.length === 1 && stmt.declarations[0].init && stmt.declarations[0].init.type === Syntax.FunctionExpression) { michael@0: result += ' ' + generateStatement(stmt.declarations[0], { michael@0: allowIn: allowIn michael@0: }); michael@0: } else { michael@0: previousBase = base; michael@0: base += indent; michael@0: node = stmt.declarations[0]; michael@0: if (extra.comment && node.leadingComments) { michael@0: result += '\n' + addIndent(generateStatement(node, { michael@0: allowIn: allowIn michael@0: })); michael@0: } else { michael@0: result += ' ' + generateStatement(node, { michael@0: allowIn: allowIn michael@0: }); michael@0: } michael@0: for (i = 1, len = stmt.declarations.length; i < len; i += 1) { michael@0: node = stmt.declarations[i]; michael@0: if (extra.comment && node.leadingComments) { michael@0: result += ',' + newline + addIndent(generateStatement(node, { michael@0: allowIn: allowIn michael@0: })); michael@0: } else { michael@0: result += ',' + space + generateStatement(node, { michael@0: allowIn: allowIn michael@0: }); michael@0: } michael@0: } michael@0: base = previousBase; michael@0: } michael@0: result += semicolon; michael@0: break; michael@0: case Syntax.ThrowStatement: michael@0: result = join('throw', generateExpression(stmt.argument, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })) + semicolon; michael@0: break; michael@0: case Syntax.TryStatement: michael@0: result = 'try' + maybeBlock(stmt.block); michael@0: result += maybeBlockSuffix(stmt.block, result); michael@0: for (i = 0, len = stmt.handlers.length; i < len; i += 1) { michael@0: result += generateStatement(stmt.handlers[i]); michael@0: if (stmt.finalizer || i + 1 !== len) { michael@0: result += maybeBlockSuffix(stmt.handlers[i].body, result); michael@0: } michael@0: } michael@0: if (stmt.finalizer) { michael@0: result += 'finally' + maybeBlock(stmt.finalizer); michael@0: } michael@0: break; michael@0: case Syntax.SwitchStatement: michael@0: previousBase = base; michael@0: base += indent; michael@0: result = 'switch' + space + '(' + generateExpression(stmt.discriminant, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')' + space + '{' + newline; michael@0: base = previousBase; michael@0: if (stmt.cases) { michael@0: for (i = 0, len = stmt.cases.length; i < len; i += 1) { michael@0: fragment = addIndent(generateStatement(stmt.cases[i], { michael@0: semicolonOptional: i === len - 1 michael@0: })); michael@0: result += fragment; michael@0: if (!endsWithLineTerminator(fragment)) { michael@0: result += newline; michael@0: } michael@0: } michael@0: } michael@0: result += addIndent('}'); michael@0: break; michael@0: case Syntax.SwitchCase: michael@0: previousBase = base; michael@0: base += indent; michael@0: if (stmt.test) { michael@0: result = join('case', generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })) + ':'; michael@0: } else { michael@0: result = 'default:'; michael@0: } michael@0: i = 0; michael@0: len = stmt.consequent.length; michael@0: if (len && stmt.consequent[0].type === Syntax.BlockStatement) { michael@0: fragment = maybeBlock(stmt.consequent[0]); michael@0: result += fragment; michael@0: i = 1; michael@0: } michael@0: if (i !== len && !endsWithLineTerminator(result)) { michael@0: result += newline; michael@0: } michael@0: for (; i < len; i += 1) { michael@0: fragment = addIndent(generateStatement(stmt.consequent[i], { michael@0: semicolonOptional: i === len - 1 && semicolon === '' michael@0: })); michael@0: result += fragment; michael@0: if (i + 1 !== len && !endsWithLineTerminator(fragment)) { michael@0: result += newline; michael@0: } michael@0: } michael@0: base = previousBase; michael@0: break; michael@0: case Syntax.IfStatement: michael@0: previousBase = base; michael@0: base += indent; michael@0: if (stmt.alternate) { michael@0: if (stmt.alternate.type === Syntax.IfStatement) { michael@0: result = 'if' + space + '(' + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.consequent); michael@0: result += maybeBlockSuffix(stmt.consequent, result); michael@0: result += 'else ' + generateStatement(stmt.alternate); michael@0: } else { michael@0: result = 'if' + space + '(' + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.consequent); michael@0: result += maybeBlockSuffix(stmt.consequent, result); michael@0: result += 'else'; michael@0: result = join(result, maybeBlock(stmt.alternate, semicolon === '')); michael@0: } michael@0: } else { michael@0: result = 'if' + space + '(' + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.consequent, semicolon === ''); michael@0: } michael@0: break; michael@0: case Syntax.ForStatement: michael@0: previousBase = base; michael@0: base += indent; michael@0: result = 'for' + space + '('; michael@0: if (stmt.init) { michael@0: if (stmt.init.type === Syntax.VariableDeclaration) { michael@0: result += generateStatement(stmt.init, { michael@0: allowIn: false michael@0: }); michael@0: } else { michael@0: result += generateExpression(stmt.init, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: false, michael@0: allowCall: true michael@0: }) + ';'; michael@0: } michael@0: } else { michael@0: result += ';'; michael@0: } michael@0: if (stmt.test) { michael@0: result += space + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ';'; michael@0: } else { michael@0: result += ';'; michael@0: } michael@0: if (stmt.update) { michael@0: result += space + generateExpression(stmt.update, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: } else { michael@0: result += ')'; michael@0: } michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.body, semicolon === ''); michael@0: break; michael@0: case Syntax.ForInStatement: michael@0: result = 'for' + space + '('; michael@0: if (stmt.left.type === Syntax.VariableDeclaration) { michael@0: previousBase = base; michael@0: base += indent + indent; michael@0: result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], { michael@0: allowIn: false michael@0: }); michael@0: base = previousBase; michael@0: } else { michael@0: previousBase = base; michael@0: base += indent; michael@0: result += generateExpression(stmt.left, { michael@0: precedence: Precedence.Call, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: base = previousBase; michael@0: } michael@0: previousBase = base; michael@0: base += indent; michael@0: result = join(result, 'in'); michael@0: result = join(result, generateExpression(stmt.right, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.body, semicolon === ''); michael@0: break; michael@0: case Syntax.LabeledStatement: michael@0: result = stmt.label.name + ':' + maybeBlock(stmt.body, semicolon === ''); michael@0: break; michael@0: case Syntax.Program: michael@0: result = ''; michael@0: for (i = 0, len = stmt.body.length; i < len; i += 1) { michael@0: fragment = addIndent(generateStatement(stmt.body[i], { michael@0: semicolonOptional: i === len - 1 michael@0: })); michael@0: result += fragment; michael@0: if (i + 1 < len && !endsWithLineTerminator(fragment)) { michael@0: result += newline; michael@0: } michael@0: } michael@0: break; michael@0: case Syntax.FunctionDeclaration: michael@0: result = 'function' + space; michael@0: if (stmt.id) { michael@0: result += (space === '' ? ' ' : '') + stmt.id.name; michael@0: } michael@0: result += generateFunctionBody(stmt); michael@0: break; michael@0: case Syntax.ReturnStatement: michael@0: if (stmt.argument) { michael@0: result = join('return', generateExpression(stmt.argument, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: })) + semicolon; michael@0: } else { michael@0: result = 'return' + semicolon; michael@0: } michael@0: break; michael@0: case Syntax.WhileStatement: michael@0: previousBase = base; michael@0: base += indent; michael@0: result = 'while' + space + '(' + generateExpression(stmt.test, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.body, semicolon === ''); michael@0: break; michael@0: case Syntax.WithStatement: michael@0: previousBase = base; michael@0: base += indent; michael@0: result = 'with' + space + '(' + generateExpression(stmt.object, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }) + ')'; michael@0: base = previousBase; michael@0: result += maybeBlock(stmt.body, semicolon === ''); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: if (result === undefined) { michael@0: throw new Error('Unknown statement type: ' + stmt.type); michael@0: } michael@0: if (extra.comment) { michael@0: return addCommentsToStatement(stmt, result); michael@0: } michael@0: return result; michael@0: } michael@0: function generate(node, options) { michael@0: var defaultOptions = getDefaultOptions(); michael@0: if (typeof options !== 'undefined') { michael@0: if (typeof options.indent === 'string') { michael@0: defaultOptions.format.indent.style = options.indent; michael@0: } michael@0: if (typeof options.base === 'number') { michael@0: defaultOptions.format.indent.base = options.base; michael@0: } michael@0: options = updateDeeply(defaultOptions, options); michael@0: indent = options.format.indent.style; michael@0: if (typeof options.base === 'string') { michael@0: base = options.base; michael@0: } else { michael@0: base = stringRepeat(indent, options.format.indent.base); michael@0: } michael@0: } else { michael@0: options = defaultOptions; michael@0: indent = options.format.indent.style; michael@0: base = stringRepeat(indent, options.format.indent.base); michael@0: } michael@0: json = options.format.json; michael@0: renumber = options.format.renumber; michael@0: hexadecimal = json ? false : options.format.hexadecimal; michael@0: quotes = json ? 'double' : options.format.quotes; michael@0: escapeless = options.format.escapeless; michael@0: if (options.format.compact) { michael@0: newline = space = indent = base = ''; michael@0: } else { michael@0: newline = '\n'; michael@0: space = ' '; michael@0: } michael@0: parentheses = options.format.parentheses; michael@0: semicolons = options.format.semicolons; michael@0: parse = json ? null : options.parse; michael@0: extra = options; michael@0: switch (node.type) { michael@0: case Syntax.BlockStatement: michael@0: case Syntax.BreakStatement: michael@0: case Syntax.CatchClause: michael@0: case Syntax.ContinueStatement: michael@0: case Syntax.DoWhileStatement: michael@0: case Syntax.DebuggerStatement: michael@0: case Syntax.EmptyStatement: michael@0: case Syntax.ExpressionStatement: michael@0: case Syntax.ForStatement: michael@0: case Syntax.ForInStatement: michael@0: case Syntax.FunctionDeclaration: michael@0: case Syntax.IfStatement: michael@0: case Syntax.LabeledStatement: michael@0: case Syntax.Program: michael@0: case Syntax.ReturnStatement: michael@0: case Syntax.SwitchStatement: michael@0: case Syntax.SwitchCase: michael@0: case Syntax.ThrowStatement: michael@0: case Syntax.TryStatement: michael@0: case Syntax.VariableDeclaration: michael@0: case Syntax.VariableDeclarator: michael@0: case Syntax.WhileStatement: michael@0: case Syntax.WithStatement: michael@0: return generateStatement(node); michael@0: case Syntax.AssignmentExpression: michael@0: case Syntax.ArrayExpression: michael@0: case Syntax.BinaryExpression: michael@0: case Syntax.CallExpression: michael@0: case Syntax.ConditionalExpression: michael@0: case Syntax.FunctionExpression: michael@0: case Syntax.Identifier: michael@0: case Syntax.Literal: michael@0: case Syntax.LogicalExpression: michael@0: case Syntax.MemberExpression: michael@0: case Syntax.NewExpression: michael@0: case Syntax.ObjectExpression: michael@0: case Syntax.Property: michael@0: case Syntax.SequenceExpression: michael@0: case Syntax.ThisExpression: michael@0: case Syntax.UnaryExpression: michael@0: case Syntax.UpdateExpression: michael@0: return generateExpression(node, { michael@0: precedence: Precedence.Sequence, michael@0: allowIn: true, michael@0: allowCall: true michael@0: }); michael@0: default: michael@0: break; michael@0: } michael@0: throw new Error('Unknown node type: ' + node.type); michael@0: } michael@0: VisitorKeys = { michael@0: AssignmentExpression: [ michael@0: 'left', michael@0: 'right' michael@0: ], michael@0: ArrayExpression: [ michael@0: 'elements' michael@0: ], michael@0: BlockStatement: [ michael@0: 'body' michael@0: ], michael@0: BinaryExpression: [ michael@0: 'left', michael@0: 'right' michael@0: ], michael@0: BreakStatement: [ michael@0: 'label' michael@0: ], michael@0: CallExpression: [ michael@0: 'callee', michael@0: 'arguments' michael@0: ], michael@0: CatchClause: [ michael@0: 'param', michael@0: 'body' michael@0: ], michael@0: ConditionalExpression: [ michael@0: 'test', michael@0: 'consequent', michael@0: 'alternate' michael@0: ], michael@0: ContinueStatement: [ michael@0: 'label' michael@0: ], michael@0: DoWhileStatement: [ michael@0: 'body', michael@0: 'test' michael@0: ], michael@0: DebuggerStatement: [], michael@0: EmptyStatement: [], michael@0: ExpressionStatement: [ michael@0: 'expression' michael@0: ], michael@0: ForStatement: [ michael@0: 'init', michael@0: 'test', michael@0: 'update', michael@0: 'body' michael@0: ], michael@0: ForInStatement: [ michael@0: 'left', michael@0: 'right', michael@0: 'body' michael@0: ], michael@0: FunctionDeclaration: [ michael@0: 'id', michael@0: 'params', michael@0: 'body' michael@0: ], michael@0: FunctionExpression: [ michael@0: 'id', michael@0: 'params', michael@0: 'body' michael@0: ], michael@0: Identifier: [], michael@0: IfStatement: [ michael@0: 'test', michael@0: 'consequent', michael@0: 'alternate' michael@0: ], michael@0: Literal: [], michael@0: LabeledStatement: [ michael@0: 'label', michael@0: 'body' michael@0: ], michael@0: LogicalExpression: [ michael@0: 'left', michael@0: 'right' michael@0: ], michael@0: MemberExpression: [ michael@0: 'object', michael@0: 'property' michael@0: ], michael@0: NewExpression: [ michael@0: 'callee', michael@0: 'arguments' michael@0: ], michael@0: ObjectExpression: [ michael@0: 'properties' michael@0: ], michael@0: Program: [ michael@0: 'body' michael@0: ], michael@0: Property: [ michael@0: 'key', michael@0: 'value' michael@0: ], michael@0: ReturnStatement: [ michael@0: 'argument' michael@0: ], michael@0: SequenceExpression: [ michael@0: 'expressions' michael@0: ], michael@0: SwitchStatement: [ michael@0: 'descriminant', michael@0: 'cases' michael@0: ], michael@0: SwitchCase: [ michael@0: 'test', michael@0: 'consequent' michael@0: ], michael@0: ThisExpression: [], michael@0: ThrowStatement: [ michael@0: 'argument' michael@0: ], michael@0: TryStatement: [ michael@0: 'block', michael@0: 'handlers', michael@0: 'finalizer' michael@0: ], michael@0: UnaryExpression: [ michael@0: 'argument' michael@0: ], michael@0: UpdateExpression: [ michael@0: 'argument' michael@0: ], michael@0: VariableDeclaration: [ michael@0: 'declarations' michael@0: ], michael@0: VariableDeclarator: [ michael@0: 'id', michael@0: 'init' michael@0: ], michael@0: WhileStatement: [ michael@0: 'test', michael@0: 'body' michael@0: ], michael@0: WithStatement: [ michael@0: 'object', michael@0: 'body' michael@0: ], michael@0: PointerType: [ michael@0: 'base' michael@0: ], michael@0: StructType: [ michael@0: 'id', michael@0: 'fields' michael@0: ], michael@0: FieldDeclarator: [ michael@0: 'id', michael@0: 'decltype' michael@0: ], michael@0: ArrowType: [ michael@0: 'params', michael@0: 'return' michael@0: ], michael@0: TypeIdentifier: [], michael@0: TypeAliasDirective: [ michael@0: 'original', michael@0: 'alias' michael@0: ], michael@0: CastExpression: [ michael@0: 'as', michael@0: 'argument' michael@0: ] michael@0: }; michael@0: VisitorOption = { michael@0: Break: 1, michael@0: Skip: 2 michael@0: }; michael@0: function traverse(top, visitor) { michael@0: var worklist, leavelist, node, ret, current, current2, candidates, candidate; michael@0: worklist = [ michael@0: top michael@0: ]; michael@0: leavelist = []; michael@0: while (worklist.length) { michael@0: node = worklist.pop(); michael@0: if (node) { michael@0: if (visitor.enter) { michael@0: ret = visitor.enter(node); michael@0: } else { michael@0: ret = undefined; michael@0: } michael@0: if (ret === VisitorOption.Break) { michael@0: return; michael@0: } michael@0: worklist.push(null); michael@0: leavelist.push(node); michael@0: if (ret !== VisitorOption.Skip) { michael@0: candidates = VisitorKeys[node.type]; michael@0: current = candidates.length; michael@0: while ((current -= 1) >= 0) { michael@0: candidate = node[candidates[current]]; michael@0: if (candidate) { michael@0: if (isArray(candidate)) { michael@0: current2 = candidate.length; michael@0: while ((current2 -= 1) >= 0) { michael@0: if (candidate[current2]) { michael@0: worklist.push(candidate[current2]); michael@0: } michael@0: } michael@0: } else { michael@0: worklist.push(candidate); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: node = leavelist.pop(); michael@0: if (visitor.leave) { michael@0: ret = visitor.leave(node); michael@0: } else { michael@0: ret = undefined; michael@0: } michael@0: if (ret === VisitorOption.Break) { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: function upperBound(array, func) { michael@0: var diff, len, i, current; michael@0: len = array.length; michael@0: i = 0; michael@0: while (len) { michael@0: diff = len >>> 1; michael@0: current = i + diff; michael@0: if (func(array[current])) { michael@0: len = diff; michael@0: } else { michael@0: i = current + 1; michael@0: len -= diff + 1; michael@0: } michael@0: } michael@0: return i; michael@0: } michael@0: function lowerBound(array, func) { michael@0: var diff, len, i, current; michael@0: len = array.length; michael@0: i = 0; michael@0: while (len) { michael@0: diff = len >>> 1; michael@0: current = i + diff; michael@0: if (func(array[current])) { michael@0: i = current + 1; michael@0: len -= diff + 1; michael@0: } else { michael@0: len = diff; michael@0: } michael@0: } michael@0: return i; michael@0: } michael@0: function extendCommentRange(comment, tokens) { michael@0: var target, token; michael@0: target = upperBound(tokens, function search(token) { michael@0: return token.range[0] > comment.range[0]; michael@0: }); michael@0: comment.extendedRange = [ michael@0: comment.range[0], michael@0: comment.range[1] michael@0: ]; michael@0: if (target !== tokens.length) { michael@0: comment.extendedRange[1] = tokens[target].range[0]; michael@0: } michael@0: target -= 1; michael@0: if (target >= 0) { michael@0: if (target < tokens.length) { michael@0: comment.extendedRange[0] = tokens[target].range[1]; michael@0: } else if (token.length) { michael@0: comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; michael@0: } michael@0: } michael@0: return comment; michael@0: } michael@0: function attachComments(tree, providedComments, tokens) { michael@0: var comments = [], comment, len, i; michael@0: if (!tree.range) { michael@0: throw new Error('attachComments needs range information'); michael@0: } michael@0: if (!tokens.length) { michael@0: if (providedComments.length) { michael@0: for (i = 0, len = providedComments.length; i < len; i += 1) { michael@0: comment = deepCopy(providedComments[i]); michael@0: comment.extendedRange = [ michael@0: 0, michael@0: tree.range[0] michael@0: ]; michael@0: comments.push(comment); michael@0: } michael@0: tree.leadingComments = comments; michael@0: } michael@0: return tree; michael@0: } michael@0: for (i = 0, len = providedComments.length; i < len; i += 1) { michael@0: comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); michael@0: } michael@0: traverse(tree, { michael@0: cursor: 0, michael@0: enter: function (node) { michael@0: var comment; michael@0: while (this.cursor < comments.length) { michael@0: comment = comments[this.cursor]; michael@0: if (comment.extendedRange[1] > node.range[0]) { michael@0: break; michael@0: } michael@0: if (comment.extendedRange[1] === node.range[0]) { michael@0: if (!node.leadingComments) { michael@0: node.leadingComments = []; michael@0: } michael@0: node.leadingComments.push(comment); michael@0: comments.splice(this.cursor, 1); michael@0: } else { michael@0: this.cursor += 1; michael@0: } michael@0: } michael@0: if (this.cursor === comments.length) { michael@0: return VisitorOption.Break; michael@0: } michael@0: if (comments[this.cursor].extendedRange[0] > node.range[1]) { michael@0: return VisitorOption.Skip; michael@0: } michael@0: } michael@0: }); michael@0: traverse(tree, { michael@0: cursor: 0, michael@0: leave: function (node) { michael@0: var comment; michael@0: while (this.cursor < comments.length) { michael@0: comment = comments[this.cursor]; michael@0: if (node.range[1] < comment.extendedRange[0]) { michael@0: break; michael@0: } michael@0: if (node.range[1] === comment.extendedRange[0]) { michael@0: if (!node.trailingComments) { michael@0: node.trailingComments = []; michael@0: } michael@0: node.trailingComments.push(comment); michael@0: comments.splice(this.cursor, 1); michael@0: } else { michael@0: this.cursor += 1; michael@0: } michael@0: } michael@0: if (this.cursor === comments.length) { michael@0: return VisitorOption.Break; michael@0: } michael@0: if (comments[this.cursor].extendedRange[0] > node.range[1]) { michael@0: return VisitorOption.Skip; michael@0: } michael@0: } michael@0: }); michael@0: return tree; michael@0: } michael@0: exports.version = '0.0.6-dev'; michael@0: exports.generate = generate; michael@0: exports.traverse = traverse; michael@0: exports.attachComments = attachComments; michael@0: }(typeof exports === 'undefined' ? escodegen = {} : exports)); michael@0: var verifierOptions = systemOptions.register(new OptionSet('Verifier Options')); michael@0: var verifierTraceLevel = verifierOptions.register(new Option('tv', 'tv', 'number', 0, 'Verifier Trace Level')); michael@0: var Type = function () { michael@0: function type() { michael@0: unexpected('Type is Abstract'); michael@0: } michael@0: type.prototype.equals = function (other) { michael@0: return this === other; michael@0: }; michael@0: type.prototype.merge = function (other) { michael@0: unexpected('Merging ' + this + ' with ' + other); michael@0: }; michael@0: type.cache = { michael@0: name: {}, michael@0: classInfo: [], michael@0: instanceInfo: [], michael@0: scriptInfo: [], michael@0: methodInfo: [] michael@0: }; michael@0: type.from = function from(x, domain) { michael@0: var traitsTypeCache = null; michael@0: if (x instanceof ClassInfo) { michael@0: traitsTypeCache = type.cache.classInfo; michael@0: } else if (x instanceof InstanceInfo) { michael@0: traitsTypeCache = type.cache.instanceInfo; michael@0: } else if (x instanceof ScriptInfo) { michael@0: traitsTypeCache = type.cache.scriptInfo; michael@0: } michael@0: if (traitsTypeCache) { michael@0: return traitsTypeCache[x.runtimeId] || (traitsTypeCache[x.runtimeId] = new TraitsType(x, domain)); michael@0: } michael@0: if (x instanceof ActivationInfo) { michael@0: return new TraitsType(x.methodInfo); michael@0: } else if (x instanceof Global) { michael@0: return new TraitsType(x.scriptInfo); michael@0: } else if (x instanceof Interface) { michael@0: return new TraitsType(x.classInfo, domain); michael@0: } else if (x instanceof MethodInfo) { michael@0: return new MethodType(x); michael@0: } else if (domain && x instanceof Class) { michael@0: return type.from(x.classInfo, domain); michael@0: } michael@0: return Type.Any; michael@0: }; michael@0: type.fromSimpleName = function (name, domain) { michael@0: return Type.fromName(Multiname.fromSimpleName(name), domain); michael@0: }; michael@0: type.fromName = function fromName(mn, domain) { michael@0: if (mn === undefined) { michael@0: return Type.Undefined; michael@0: } else { michael@0: var qn = Multiname.isQName(mn) ? Multiname.getFullQualifiedName(mn) : undefined; michael@0: if (qn) { michael@0: var ty = type.cache.name[qn]; michael@0: if (ty) { michael@0: return ty; michael@0: } michael@0: } michael@0: if (qn === Multiname.getPublicQualifiedName('void')) { michael@0: return Type.Void; michael@0: } michael@0: true; michael@0: ty = domain.findClassInfo(mn); michael@0: ty = ty ? type.from(ty, domain) : Type.Any; michael@0: if (mn.hasTypeParameter()) { michael@0: ty = new ParameterizedType(ty, type.fromName(mn.typeParameter, domain)); michael@0: } michael@0: return type.cache.name[qn] = ty; michael@0: } michael@0: }; michael@0: type.prototype.applyType = function (parameter) { michael@0: return new ParameterizedType(this, parameter); michael@0: }; michael@0: type.prototype.toString = function () { michael@0: return '[type]'; michael@0: }; michael@0: type.prototype.isNumeric = function () { michael@0: return this === Type.Int || this === Type.Uint || this === Type.Number; michael@0: }; michael@0: type.prototype.isString = function () { michael@0: return this === Type.String; michael@0: }; michael@0: type.prototype.isDirectlyReadable = function () { michael@0: return this === Type.Array; michael@0: }; michael@0: type.prototype.isIndexedReadable = function () { michael@0: return this.isParameterizedType(); michael@0: }; michael@0: type.prototype.isDirectlyWriteable = function () { michael@0: return this === Type.Array; michael@0: }; michael@0: type.prototype.isIndexedWriteable = function () { michael@0: return this.isParameterizedType(); michael@0: }; michael@0: type.prototype.isVector = function () { michael@0: return this.isParameterizedType(); michael@0: }; michael@0: type.prototype.isNotDirectlyIndexable = function () { michael@0: return this === Type.Any || this === Type.XML || this === Type.XMLList || this === Type.Dictionary; michael@0: }; michael@0: type.prototype.isParameterizedType = function () { michael@0: return this instanceof ParameterizedType; michael@0: }; michael@0: type.prototype.instanceType = function () { michael@0: return this; michael@0: }; michael@0: type.prototype.getTrait = function () { michael@0: return null; michael@0: }; michael@0: type.prototype.super = function () { michael@0: unexpected('Can\'t call super on ' + this); michael@0: }; michael@0: type.prototype.isSubtypeOf = function (other) { michael@0: if (this === other || this.equals(other)) { michael@0: return true; michael@0: } michael@0: return this.merge(other) === this; michael@0: }; michael@0: var typesInitialized = false; michael@0: type.initializeTypes = function (domain) { michael@0: if (typesInitialized) { michael@0: return; michael@0: } michael@0: type.Any = new AtomType('Any'); michael@0: type.Null = new AtomType('Null'); michael@0: type.Undefined = new AtomType('Undefined'); michael@0: type.Void = new AtomType('Void'); michael@0: type.Int = Type.fromSimpleName('int', domain).instanceType(); michael@0: type.Uint = Type.fromSimpleName('uint', domain).instanceType(); michael@0: type.Class = Type.fromSimpleName('Class', domain).instanceType(); michael@0: type.Array = Type.fromSimpleName('Array', domain).instanceType(); michael@0: type.Object = Type.fromSimpleName('Object', domain).instanceType(); michael@0: type.String = Type.fromSimpleName('String', domain).instanceType(); michael@0: type.Number = Type.fromSimpleName('Number', domain).instanceType(); michael@0: type.Boolean = Type.fromSimpleName('Boolean', domain).instanceType(); michael@0: type.Function = Type.fromSimpleName('Function', domain).instanceType(); michael@0: type.XML = Type.fromSimpleName('XML', domain).instanceType(); michael@0: type.XMLList = Type.fromSimpleName('XMLList', domain).instanceType(); michael@0: type.Dictionary = Type.fromSimpleName('flash.utils.Dictionary', domain).instanceType(); michael@0: typesInitialized = true; michael@0: }; michael@0: return type; michael@0: }(); michael@0: var AtomType = function () { michael@0: function atomType(name) { michael@0: this.name = name; michael@0: } michael@0: atomType.prototype = Object.create(Type.prototype); michael@0: atomType.prototype.toString = function () { michael@0: if (this === Type.Any) { michael@0: return '?'; michael@0: } else if (this === Type.Undefined) { michael@0: return '_'; michael@0: } else if (this === Type.Null) { michael@0: return 'X'; michael@0: } else if (this === Type.Void) { michael@0: return 'V'; michael@0: } michael@0: unexpected(); michael@0: }; michael@0: atomType.prototype.merge = function merge(other) { michael@0: if (other instanceof TraitsType) { michael@0: return Type.Any; michael@0: } michael@0: if (this === other) { michael@0: return this; michael@0: } michael@0: if (this === Type.Any || other === Type.Any) { michael@0: return Type.Any; michael@0: } michael@0: return Type.Any; michael@0: }; michael@0: return atomType; michael@0: }(); michael@0: var MethodType = function () { michael@0: function methodType(methodInfo) { michael@0: this.methodInfo = methodInfo; michael@0: } michael@0: methodType.prototype = Object.create(Type.prototype); michael@0: methodType.prototype.toString = function () { michael@0: return 'MT ' + this.methodInfo; michael@0: }; michael@0: return methodType; michael@0: }(); michael@0: var TraitsType = function () { michael@0: function traitsType(object, domain) { michael@0: true; michael@0: this.object = object; michael@0: this.traits = object.traits; michael@0: this.domain = domain; michael@0: if (this.object instanceof InstanceInfo) { michael@0: true; michael@0: } michael@0: } michael@0: traitsType.prototype = Object.create(Type.prototype); michael@0: function nameOf(x) { michael@0: if (x instanceof ScriptInfo) { michael@0: return 'SI'; michael@0: } else if (x instanceof ClassInfo) { michael@0: return 'CI:' + x.instanceInfo.name.name; michael@0: } else if (x instanceof InstanceInfo) { michael@0: return 'II:' + x.name.name; michael@0: } else if (x instanceof MethodInfo) { michael@0: return 'MI'; michael@0: } else if (x instanceof ActivationInfo) { michael@0: return 'AC'; michael@0: } michael@0: true; michael@0: } michael@0: function findTraitBySlotId(traits, slotId) { michael@0: for (var i = traits.length - 1; i >= 0; i--) { michael@0: if (traits[i].slotId === slotId) { michael@0: return traits[i]; michael@0: } michael@0: } michael@0: unexpected('Cannot find trait with slotId: ' + slotId + ' in ' + traits); michael@0: } michael@0: function findTraitByName(traits, mn, isSetter) { michael@0: var isGetter = !isSetter; michael@0: var trait; michael@0: if (!Multiname.isQName(mn)) { michael@0: if (mn instanceof MultinameType) { michael@0: return; michael@0: } michael@0: true; michael@0: var dy; michael@0: for (var i = 0, j = mn.namespaces.length; i < j; i++) { michael@0: var qn = mn.getQName(i); michael@0: if (mn.namespaces[i].isDynamic()) { michael@0: dy = qn; michael@0: } else { michael@0: if (trait = findTraitByName(traits, qn, isSetter)) { michael@0: return trait; michael@0: } michael@0: } michael@0: } michael@0: if (dy) { michael@0: return findTraitByName(traits, dy, isSetter); michael@0: } michael@0: } else { michael@0: var qn = Multiname.getQualifiedName(mn); michael@0: for (var i = 0, j = traits.length; i < j; i++) { michael@0: trait = traits[i]; michael@0: if (Multiname.getQualifiedName(trait.name) === qn) { michael@0: if (isSetter && trait.isGetter() || isGetter && trait.isSetter()) { michael@0: continue; michael@0: } michael@0: return trait; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: traitsType.prototype.getTrait = function (mn, isSetter, followSuperType) { michael@0: if (mn instanceof MultinameType) { michael@0: return null; michael@0: } michael@0: if (mn.isAttribute()) { michael@0: return null; michael@0: } michael@0: if (followSuperType && (this.isInstanceInfo() || this.isClassInfo())) { michael@0: var that = this; michael@0: do { michael@0: var trait = that.getTrait(mn, isSetter, false); michael@0: if (!trait) { michael@0: that = that.super(); michael@0: } michael@0: } while (!trait && that); michael@0: return trait; michael@0: } else { michael@0: return findTraitByName(this.traits, mn, isSetter); michael@0: } michael@0: }; michael@0: traitsType.prototype.getTraitAt = function (i) { michael@0: if (this.object instanceof ScriptInfo || this.object instanceof MethodInfo) { michael@0: return findTraitBySlotId(this.traits, i); michael@0: } michael@0: }; michael@0: traitsType.prototype.toString = function () { michael@0: switch (this) { michael@0: case Type.Int: michael@0: return 'I'; michael@0: case Type.Uint: michael@0: return 'U'; michael@0: case Type.Array: michael@0: return 'A'; michael@0: case Type.Object: michael@0: return 'O'; michael@0: case Type.String: michael@0: return 'S'; michael@0: case Type.Number: michael@0: return 'N'; michael@0: case Type.Boolean: michael@0: return 'B'; michael@0: case Type.Function: michael@0: return 'F'; michael@0: } michael@0: return nameOf(this.object); michael@0: }; michael@0: traitsType.prototype.instanceType = function () { michael@0: true; michael@0: return this.instanceCache || (this.instanceCache = Type.from(this.object.instanceInfo, this.domain)); michael@0: }; michael@0: traitsType.prototype.classType = function () { michael@0: true; michael@0: return this.instanceCache || (this.instanceCache = Type.from(this.object.classInfo, this.domain)); michael@0: }; michael@0: traitsType.prototype.super = function () { michael@0: if (this.object instanceof ClassInfo) { michael@0: return Type.Class; michael@0: } michael@0: true; michael@0: if (this.object.superName) { michael@0: var result = Type.fromName(this.object.superName, this.domain).instanceType(); michael@0: true; michael@0: return result; michael@0: } michael@0: return null; michael@0: }; michael@0: traitsType.prototype.isScriptInfo = function () { michael@0: return this.object instanceof ScriptInfo; michael@0: }; michael@0: traitsType.prototype.isClassInfo = function () { michael@0: return this.object instanceof ClassInfo; michael@0: }; michael@0: traitsType.prototype.isInstanceInfo = function () { michael@0: return this.object instanceof InstanceInfo; michael@0: }; michael@0: traitsType.prototype.isInstanceOrClassInfo = function () { michael@0: return this.isInstanceInfo() || this.isClassInfo(); michael@0: }; michael@0: traitsType.prototype.equals = function (other) { michael@0: return this.traits === other.traits; michael@0: }; michael@0: traitsType.prototype.merge = function (other) { michael@0: if (other instanceof TraitsType) { michael@0: if (this.equals(other)) { michael@0: return this; michael@0: } michael@0: if (this.isNumeric() && other.isNumeric()) { michael@0: return Type.Number; michael@0: } michael@0: if (this.isInstanceInfo() && other.isInstanceInfo()) { michael@0: var path = []; michael@0: for (var curr = this; curr; curr = curr.super()) { michael@0: path.push(curr); michael@0: } michael@0: for (var curr = other; curr; curr = curr.super()) { michael@0: for (var i = 0; i < path.length; i++) { michael@0: if (path[i].equals(curr)) { michael@0: return curr; michael@0: } michael@0: } michael@0: } michael@0: return Type.Object; michael@0: } michael@0: } michael@0: return Type.Any; michael@0: }; michael@0: return traitsType; michael@0: }(); michael@0: var MultinameType = function () { michael@0: function multinameType(namespaces, name, flags) { michael@0: this.namespaces = namespaces; michael@0: this.name = name; michael@0: this.flags = flags; michael@0: } michael@0: multinameType.prototype = Object.create(Type.prototype); michael@0: multinameType.prototype.toString = function () { michael@0: return 'MN'; michael@0: }; michael@0: return multinameType; michael@0: }(); michael@0: var ParameterizedType = function () { michael@0: function parameterizedType(type, parameter) { michael@0: this.type = type; michael@0: this.parameter = parameter; michael@0: } michael@0: parameterizedType.prototype = Object.create(Type.prototype); michael@0: parameterizedType.prototype.toString = function () { michael@0: return this.type + '<' + this.parameter + '>'; michael@0: }; michael@0: parameterizedType.prototype.instanceType = function () { michael@0: true; michael@0: return new ParameterizedType(this.type.instanceType(), this.parameter.instanceType()); michael@0: }; michael@0: parameterizedType.prototype.equals = function (other) { michael@0: if (other instanceof ParameterizedType) { michael@0: return this.type.equals(other.type) && this.parameter.equals(other.parameter); michael@0: } michael@0: return false; michael@0: }; michael@0: parameterizedType.prototype.merge = function (other) { michael@0: if (other instanceof TraitsType) { michael@0: if (this.equals(other)) { michael@0: return this; michael@0: } michael@0: } michael@0: return Type.Any; michael@0: }; michael@0: return parameterizedType; michael@0: }(); michael@0: var TypeInformation = function () { michael@0: function typeInformation() { michael@0: } michael@0: typeInformation.prototype.toString = function () { michael@0: return toKeyValueArray(this).map(function (x) { michael@0: return x[0] + ': ' + x[1]; michael@0: }).join(' | '); michael@0: }; michael@0: return typeInformation; michael@0: }(); michael@0: var Verifier = function () { michael@0: function VerifierError(message) { michael@0: this.name = 'VerifierError'; michael@0: this.message = message || ''; michael@0: } michael@0: var State = function () { michael@0: var id = 0; michael@0: function state() { michael@0: this.id = id += 1; michael@0: this.stack = []; michael@0: this.scope = []; michael@0: this.local = []; michael@0: } michael@0: state.prototype.clone = function clone() { michael@0: var s = new State(); michael@0: s.originalId = this.id; michael@0: s.stack = this.stack.slice(0); michael@0: s.scope = this.scope.slice(0); michael@0: s.local = this.local.slice(0); michael@0: return s; michael@0: }; michael@0: state.prototype.trace = function trace(writer) { michael@0: writer.writeLn(this.toString()); michael@0: }; michael@0: state.prototype.toString = function () { michael@0: return '<' + this.id + (this.originalId ? ':' + this.originalId : '') + ', L[' + this.local.join(', ') + ']' + ', S[' + this.stack.join(', ') + ']' + ', $[' + this.scope.join(', ') + ']>'; michael@0: }; michael@0: state.prototype.equals = function (other) { michael@0: return arrayEquals(this.stack, other.stack) && arrayEquals(this.scope, other.scope) && arrayEquals(this.local, other.local); michael@0: }; michael@0: function arrayEquals(a, b) { michael@0: if (a.length != b.length) { michael@0: return false; michael@0: } michael@0: for (var i = a.length - 1; i >= 0; i--) { michael@0: if (!a[i].equals(b[i])) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: state.prototype.isSubset = function (other) { michael@0: return arraySubset(this.stack, other.stack) && arraySubset(this.scope, other.scope) && arraySubset(this.local, other.local); michael@0: }; michael@0: function arraySubset(a, b) { michael@0: if (a.length != b.length) { michael@0: return false; michael@0: } michael@0: for (var i = a.length - 1; i >= 0; i--) { michael@0: if (a[i] === b[i] || a[i].equals(b[i])) { michael@0: continue; michael@0: } michael@0: if (a[i].merge(b[i]) !== a[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: state.prototype.merge = function (other) { michael@0: mergeArrays(this.local, other.local); michael@0: mergeArrays(this.stack, other.stack); michael@0: mergeArrays(this.scope, other.scope); michael@0: }; michael@0: function mergeArrays(a, b) { michael@0: true; michael@0: for (var i = a.length - 1; i >= 0; i--) { michael@0: true; michael@0: if (a[i] === b[i]) { michael@0: continue; michael@0: } michael@0: a[i] = a[i].merge(b[i]); michael@0: } michael@0: } michael@0: return state; michael@0: }(); michael@0: var Verification = function () { michael@0: function verification(methodInfo, domain, savedScope) { michael@0: this.savedScope = savedScope; michael@0: this.methodInfo = methodInfo; michael@0: this.domain = domain; michael@0: this.writer = new IndentingWriter(); michael@0: this.returnType = Type.Undefined; michael@0: } michael@0: verification.prototype.verify = function verify() { michael@0: var mi = this.methodInfo; michael@0: var writer = verifierTraceLevel.value ? this.writer : null; michael@0: var blocks = mi.analysis.blocks; michael@0: blocks.forEach(function (x) { michael@0: x.entryState = x.exitState = null; michael@0: }); michael@0: if (writer) { michael@0: this.methodInfo.trace(writer); michael@0: } michael@0: var entryState = new State(); michael@0: true; michael@0: this.thisType = mi.holder ? Type.from(mi.holder, this.domain) : Type.Any; michael@0: entryState.local.push(this.thisType); michael@0: for (var i = 0; i < mi.parameters.length; i++) { michael@0: entryState.local.push(Type.fromName(mi.parameters[i].type, this.domain).instanceType()); michael@0: } michael@0: var remainingLocals = mi.localCount - mi.parameters.length - 1; michael@0: if (mi.needsRest() || mi.needsArguments()) { michael@0: entryState.local.push(Type.Array); michael@0: remainingLocals -= 1; michael@0: } michael@0: for (var i = 0; i < remainingLocals; i++) { michael@0: entryState.local.push(Type.Undefined); michael@0: } michael@0: true; michael@0: if (writer) { michael@0: entryState.trace(writer); michael@0: } michael@0: for (var bi = 0, len = blocks.length; bi < len; bi++) { michael@0: blocks[bi].bdo = bi; michael@0: } michael@0: var worklist = new Shumway.SortedList(function compare(blockA, blockB) { michael@0: return blockA.bdo - blockB.bdo; michael@0: }); michael@0: blocks[0].entryState = entryState; michael@0: worklist.push(blocks[0]); michael@0: while (!worklist.isEmpty()) { michael@0: var block = worklist.pop(); michael@0: var exitState = block.exitState = block.entryState.clone(); michael@0: this.verifyBlock(block, exitState); michael@0: block.succs.forEach(function (successor) { michael@0: if (worklist.contains(successor)) { michael@0: if (writer) { michael@0: writer.writeLn('Forward Merged Block: ' + successor.bid + ' ' + exitState.toString() + ' with ' + successor.entryState.toString()); michael@0: } michael@0: successor.entryState.merge(exitState); michael@0: if (writer) { michael@0: writer.writeLn('Merged State: ' + successor.entryState); michael@0: } michael@0: return; michael@0: } michael@0: if (successor.entryState) { michael@0: if (!successor.entryState.isSubset(exitState)) { michael@0: if (writer) { michael@0: writer.writeLn('Backward Merged Block: ' + block.bid + ' with ' + successor.bid + ' ' + exitState.toString() + ' with ' + successor.entryState.toString()); michael@0: } michael@0: successor.entryState.merge(exitState); michael@0: worklist.push(successor); michael@0: if (writer) { michael@0: writer.writeLn('Merged State: ' + successor.entryState); michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: successor.entryState = exitState.clone(); michael@0: worklist.push(successor); michael@0: if (writer) { michael@0: writer.writeLn('Added Block: ' + successor.bid + ' to worklist: ' + successor.entryState.toString()); michael@0: } michael@0: }); michael@0: } michael@0: if (writer) { michael@0: writer.writeLn('Inferred return type: ' + this.returnType); michael@0: } michael@0: this.methodInfo.inferredReturnType = this.returnType; michael@0: }; michael@0: verification.prototype.verifyBlock = function verifyBlock(block, state) { michael@0: var savedScope = this.savedScope; michael@0: var globalScope = savedScope[0]; michael@0: var local = state.local; michael@0: var stack = state.stack; michael@0: var scope = state.scope; michael@0: var writer = verifierTraceLevel.value ? this.writer : null; michael@0: var bytecodes = this.methodInfo.analysis.bytecodes; michael@0: var domain = this.domain; michael@0: var multinames = this.methodInfo.abc.constantPool.multinames; michael@0: var mi = this.methodInfo; michael@0: var bc, obj, fn, mn, l, r, val, type, returnType; michael@0: if (writer) { michael@0: writer.enter('verifyBlock: ' + block.bid + ', range: [' + block.position + ', ' + block.end.position + '], entryState: ' + state.toString() + ' {'); michael@0: } michael@0: function construct(obj) { michael@0: if (obj instanceof TraitsType || obj instanceof ParameterizedType) { michael@0: if (obj === Type.Function || obj === Type.Class || obj === Type.Object) { michael@0: return Type.Object; michael@0: } michael@0: return obj.instanceType(); michael@0: } else { michael@0: return Type.Any; michael@0: } michael@0: } michael@0: function ti() { michael@0: return bc.ti || (bc.ti = new TypeInformation()); michael@0: } michael@0: function push(x) { michael@0: true; michael@0: ti().type = x; michael@0: stack.push(x); michael@0: } michael@0: function pop() { michael@0: return stack.pop(); michael@0: } michael@0: function findProperty(mn, strict) { michael@0: if (mn instanceof MultinameType) { michael@0: if (mn.name === 'Array') { michael@0: debugger; michael@0: } michael@0: return Type.Any; michael@0: } michael@0: for (var i = scope.length - 1; i >= -savedScope.length; i--) { michael@0: var s = i >= 0 ? scope[i] : savedScope[savedScope.length + i]; michael@0: if (s instanceof TraitsType) { michael@0: var trait = s.getTrait(mn, false, true); michael@0: if (trait) { michael@0: ti().scopeDepth = scope.length - i - 1; michael@0: if (s.isClassInfo() || s.isScriptInfo()) { michael@0: ti().object = LazyInitializer.create(s.object); michael@0: } michael@0: return s; michael@0: } michael@0: } else { michael@0: if (mn.name === 'Array') { michael@0: debugger; michael@0: } michael@0: return Type.Any; michael@0: } michael@0: } michael@0: var resolved = domain.findDefiningScript(mn, false); michael@0: if (resolved) { michael@0: ti().object = LazyInitializer.create(resolved.script); michael@0: return Type.from(resolved.script, domain); michael@0: } michael@0: if (mn.name === 'Array') { michael@0: debugger; michael@0: } michael@0: return Type.Any; michael@0: } michael@0: function popMultiname() { michael@0: var mn = multinames[bc.index]; michael@0: if (mn.isRuntime()) { michael@0: var namespaces = mn.namespaces; michael@0: var name = mn.name; michael@0: if (mn.isRuntimeName()) { michael@0: name = pop(); michael@0: } michael@0: if (mn.isRuntimeNamespace()) { michael@0: namespaces = [ michael@0: pop() michael@0: ]; michael@0: } michael@0: return new MultinameType(namespaces, name, mn.flags); michael@0: } michael@0: return mn; michael@0: } michael@0: function accessSlot(obj) { michael@0: if (obj instanceof TraitsType) { michael@0: var trait = obj.getTraitAt(bc.index); michael@0: writer && writer.debugLn('accessSlot() -> ' + trait); michael@0: if (trait) { michael@0: ti().trait = trait; michael@0: if (trait.isSlot()) { michael@0: return Type.fromName(trait.typeName, domain).instanceType(); michael@0: } else if (trait.isClass()) { michael@0: return Type.from(trait.classInfo, domain); michael@0: } michael@0: } michael@0: } michael@0: return Type.Any; michael@0: } michael@0: function isNumericMultiname(mn) { michael@0: return mn instanceof Multiname && Multiname.isNumeric(mn) || mn instanceof MultinameType && (mn.name instanceof TraitsType && mn.name.isNumeric()); michael@0: } michael@0: function getProperty(obj, mn) { michael@0: if (obj instanceof TraitsType || obj instanceof ParameterizedType) { michael@0: var trait = obj.getTrait(mn, false, true); michael@0: writer && writer.debugLn('getProperty(' + mn + ') -> ' + trait); michael@0: if (trait) { michael@0: ti().trait = trait; michael@0: if (trait.isSlot() || trait.isConst()) { michael@0: return Type.fromName(trait.typeName, domain).instanceType(); michael@0: } else if (trait.isGetter()) { michael@0: return Type.fromName(trait.methodInfo.returnType, domain).instanceType(); michael@0: } else if (trait.isClass()) { michael@0: return Type.from(trait.classInfo, domain); michael@0: } else if (trait.isMethod()) { michael@0: return Type.from(trait.methodInfo, domain); michael@0: } michael@0: } else if (obj.isDirectlyReadable() && mn instanceof Multiname) { michael@0: ti().propertyQName = Multiname.getPublicQualifiedName(mn.name); michael@0: } michael@0: if (isNumericMultiname(mn)) { michael@0: if (obj.isIndexedReadable()) { michael@0: ti().isIndexedReadable = true; michael@0: if (obj.isVector()) { michael@0: return obj.parameter; michael@0: } michael@0: } else if (obj.isDirectlyReadable()) { michael@0: ti().isDirectlyReadable = true; michael@0: } michael@0: } michael@0: } michael@0: return Type.Any; michael@0: } michael@0: function setProperty(obj, mn, value) { michael@0: if (obj instanceof TraitsType || obj instanceof ParameterizedType) { michael@0: var trait = obj.getTrait(mn, true, true); michael@0: writer && writer.debugLn('setProperty(' + mn + ') -> ' + trait); michael@0: if (trait) { michael@0: ti().trait = trait; michael@0: } else if (obj.isDirectlyWriteable() && mn instanceof Multiname) { michael@0: ti().propertyQName = Multiname.getPublicQualifiedName(mn.name); michael@0: } michael@0: if (isNumericMultiname(mn)) { michael@0: if (obj.isDirectlyWriteable()) { michael@0: ti().isDirectlyWriteable = true; michael@0: } else if (obj.isVector()) { michael@0: ti().isIndexedWriteable = true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: for (var bci = block.position, end = block.end.position; bci <= end; bci++) { michael@0: bc = bytecodes[bci]; michael@0: var op = bc.op; michael@0: if (writer && verifierTraceLevel.value > 1) { michael@0: writer.writeLn(('stateBefore: ' + state.toString() + ' $$[' + savedScope.join(', ') + ']').padRight(' ', 100) + ' : ' + bci + ', ' + bc.toString(mi.abc)); michael@0: } michael@0: switch (op) { michael@0: case 1: michael@0: break; michael@0: case 3: michael@0: pop(); michael@0: break; michael@0: case 4: michael@0: mn = popMultiname(); michael@0: obj = pop(); michael@0: true; michael@0: ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); michael@0: push(getProperty(obj.super(), mn)); michael@0: break; michael@0: case 5: michael@0: val = pop(); michael@0: mn = popMultiname(); michael@0: obj = pop(); michael@0: true; michael@0: ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); michael@0: setProperty(obj.super(), mn, val); michael@0: break; michael@0: case 6: michael@0: notImplemented(bc); michael@0: break; michael@0: case 7: michael@0: notImplemented(bc); michael@0: break; michael@0: case 8: michael@0: state.local[bc.index] = Type.Undefined; michael@0: break; michael@0: case 10: michael@0: notImplemented(bc); michael@0: break; michael@0: case 11: michael@0: notImplemented(bc); michael@0: break; michael@0: case 12: michael@0: case 24: michael@0: case 13: michael@0: case 23: michael@0: case 14: michael@0: case 22: michael@0: case 15: michael@0: case 21: michael@0: case 19: michael@0: case 20: michael@0: case 25: michael@0: case 26: michael@0: pop(); michael@0: pop(); michael@0: break; michael@0: case 16: michael@0: break; michael@0: case 17: michael@0: case 18: michael@0: pop(); michael@0: break; michael@0: case 27: michael@0: pop(Type.Int); michael@0: break; michael@0: case 29: michael@0: scope.pop(); michael@0: break; michael@0: case 30: michael@0: case 35: michael@0: pop(Type.Int); michael@0: pop(); michael@0: push(Type.Any); michael@0: break; michael@0: case 31: michael@0: push(Type.Boolean); michael@0: break; michael@0: case 50: michael@0: push(Type.Boolean); michael@0: break; michael@0: case 32: michael@0: push(Type.Null); michael@0: break; michael@0: case 33: michael@0: push(Type.Undefined); michael@0: break; michael@0: case 34: michael@0: notImplemented(bc); michael@0: break; michael@0: case 36: michael@0: push(Type.Int); michael@0: break; michael@0: case 37: michael@0: push(Type.Int); michael@0: break; michael@0: case 44: michael@0: push(Type.String); michael@0: break; michael@0: case 45: michael@0: push(Type.Int); michael@0: break; michael@0: case 46: michael@0: push(Type.Uint); michael@0: break; michael@0: case 47: michael@0: push(Type.Number); michael@0: break; michael@0: case 38: michael@0: push(Type.Boolean); michael@0: break; michael@0: case 39: michael@0: push(Type.Boolean); michael@0: break; michael@0: case 40: michael@0: push(Type.Number); michael@0: break; michael@0: case 41: michael@0: pop(); michael@0: break; michael@0: case 42: michael@0: val = pop(); michael@0: push(val); michael@0: push(val); michael@0: break; michael@0: case 43: michael@0: l = pop(); michael@0: r = pop(); michael@0: push(l); michael@0: push(r); michael@0: break; michael@0: case 28: michael@0: pop(); michael@0: scope.push(Type.Any); michael@0: break; michael@0: case 48: michael@0: scope.push(pop()); michael@0: break; michael@0: case 49: michael@0: notImplemented(bc); michael@0: break; michael@0: case 53: michael@0: case 54: michael@0: case 55: michael@0: push(Type.Int); michael@0: break; michael@0: case 56: michael@0: case 57: michael@0: push(Type.Number); michael@0: break; michael@0: case 58: michael@0: case 59: michael@0: case 60: michael@0: pop(Type.Int); michael@0: break; michael@0: case 61: michael@0: case 62: michael@0: pop(Type.Number); michael@0: break; michael@0: case 64: michael@0: push(Type.Function); michael@0: break; michael@0: case 65: michael@0: stack.popMany(bc.argCount); michael@0: obj = pop(); michael@0: fn = pop(); michael@0: push(Type.Any); michael@0: break; michael@0: case 67: michael@0: throw new VerifierError('callmethod'); michael@0: case 68: michael@0: notImplemented(bc); michael@0: break; michael@0: case 69: michael@0: case 78: michael@0: case 79: michael@0: case 70: michael@0: case 76: michael@0: stack.popMany(bc.argCount); michael@0: mn = popMultiname(); michael@0: obj = pop(); michael@0: if (op === OP_callsuper || op === OP_callsupervoid) { michael@0: obj = this.thisType.super(); michael@0: ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); michael@0: } michael@0: type = getProperty(obj, mn); michael@0: if (op === OP_callpropvoid || op === OP_callsupervoid) { michael@0: break; michael@0: } michael@0: if (type instanceof MethodType) { michael@0: returnType = Type.fromName(type.methodInfo.returnType, domain).instanceType(); michael@0: } else if (type instanceof TraitsType && type.isClassInfo()) { michael@0: returnType = type.instanceType(); michael@0: } else { michael@0: returnType = Type.Any; michael@0: } michael@0: push(returnType); michael@0: break; michael@0: case 71: michael@0: this.returnType.merge(Type.Undefined); michael@0: break; michael@0: case 72: michael@0: type = pop(); michael@0: if (mi.returnType) { michael@0: var coerceType = Type.fromName(mi.returnType, this.domain).instanceType(); michael@0: if (coerceType.isSubtypeOf(type)) { michael@0: ti().noCoercionNeeded = true; michael@0: } michael@0: } michael@0: break; michael@0: case 73: michael@0: stack.popMany(bc.argCount); michael@0: stack.pop(); michael@0: if (this.thisType.isInstanceInfo() && this.thisType.super() === Type.Object) { michael@0: ti().noCallSuperNeeded = true; michael@0: } else { michael@0: ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object); michael@0: } michael@0: break; michael@0: case 66: michael@0: stack.popMany(bc.argCount); michael@0: push(construct(pop())); michael@0: break; michael@0: case 74: michael@0: stack.popMany(bc.argCount); michael@0: mn = popMultiname(); michael@0: push(construct(getProperty(stack.pop(), mn))); michael@0: break; michael@0: case 75: michael@0: notImplemented(bc); michael@0: break; michael@0: case 77: michael@0: notImplemented(bc); michael@0: break; michael@0: case 80: michael@0: case 81: michael@0: case 82: michael@0: break; michael@0: case 83: michael@0: true; michael@0: val = pop(); michael@0: obj = pop(); michael@0: if (obj === Type.Any) { michael@0: push(Type.Any); michael@0: } else { michael@0: push(obj.applyType(val)); michael@0: } michael@0: break; michael@0: case 84: michael@0: notImplemented(bc); michael@0: break; michael@0: case 85: michael@0: stack.popMany(bc.argCount * 2); michael@0: push(Type.Object); michael@0: break; michael@0: case 86: michael@0: stack.popMany(bc.argCount); michael@0: push(Type.Array); michael@0: break; michael@0: case 87: michael@0: push(Type.from(new ActivationInfo(this.methodInfo))); michael@0: break; michael@0: case 88: michael@0: push(Type.Any); michael@0: break; michael@0: case 89: michael@0: popMultiname(); michael@0: pop(); michael@0: push(Type.XMLList); michael@0: break; michael@0: case 90: michael@0: push(Type.Any); michael@0: break; michael@0: case 93: michael@0: push(findProperty(popMultiname(), true)); michael@0: break; michael@0: case 94: michael@0: push(findProperty(popMultiname(), false)); michael@0: break; michael@0: case 95: michael@0: notImplemented(bc); michael@0: break; michael@0: case 96: michael@0: mn = popMultiname(); michael@0: push(getProperty(findProperty(mn, true), mn)); michael@0: break; michael@0: case 104: michael@0: case 97: michael@0: val = pop(); michael@0: mn = popMultiname(); michael@0: obj = pop(); michael@0: setProperty(obj, mn, val, bc); michael@0: break; michael@0: case 98: michael@0: push(local[bc.index]); michael@0: break; michael@0: case 99: michael@0: local[bc.index] = pop(); michael@0: break; michael@0: case 100: michael@0: push(globalScope); michael@0: ti().object = LazyInitializer.create(globalScope.object); michael@0: break; michael@0: case 101: michael@0: push(scope[bc.index]); michael@0: break; michael@0: case 102: michael@0: mn = popMultiname(); michael@0: obj = pop(); michael@0: push(getProperty(obj, mn)); michael@0: break; michael@0: case 103: michael@0: notImplemented(bc); michael@0: break; michael@0: case 105: michael@0: notImplemented(bc); michael@0: break; michael@0: case 106: michael@0: popMultiname(); michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 107: michael@0: notImplemented(bc); michael@0: break; michael@0: case 108: michael@0: push(accessSlot(pop())); michael@0: break; michael@0: case 109: michael@0: val = pop(); michael@0: obj = pop(); michael@0: accessSlot(obj); michael@0: break; michael@0: case 110: michael@0: notImplemented(bc); michael@0: break; michael@0: case 111: michael@0: notImplemented(bc); michael@0: break; michael@0: case 112: michael@0: pop(); michael@0: push(Type.String); michael@0: break; michael@0: case 113: michael@0: pop(); michael@0: push(Type.String); michael@0: break; michael@0: case 114: michael@0: pop(); michael@0: push(Type.String); michael@0: break; michael@0: case 131: michael@0: case 115: michael@0: pop(); michael@0: push(Type.Int); michael@0: break; michael@0: case 136: michael@0: case 116: michael@0: pop(); michael@0: push(Type.Uint); michael@0: break; michael@0: case 132: michael@0: case 117: michael@0: pop(); michael@0: push(Type.Number); michael@0: break; michael@0: case 129: michael@0: case 118: michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 119: michael@0: notImplemented(bc); michael@0: break; michael@0: case 120: michael@0: break; michael@0: case 121: michael@0: pop(); michael@0: push(Type.Number); michael@0: break; michael@0: case 122: michael@0: notImplemented(bc); michael@0: break; michael@0: case 123: michael@0: notImplemented(bc); michael@0: break; michael@0: case 128: michael@0: type = pop(); michael@0: var coerceType = Type.fromName(multinames[bc.index], this.domain).instanceType(); michael@0: if (coerceType.isSubtypeOf(type)) { michael@0: ti().noCoercionNeeded = true; michael@0: } michael@0: push(coerceType); michael@0: break; michael@0: case 130: michael@0: break; michael@0: case 133: michael@0: pop(); michael@0: push(Type.String); michael@0: break; michael@0: case 134: michael@0: notImplemented(bc); michael@0: break; michael@0: case 135: michael@0: type = pop(); michael@0: pop(); michael@0: if (type instanceof TraitsType) { michael@0: push(type.instanceType()); michael@0: } else { michael@0: push(Type.Any); michael@0: } michael@0: break; michael@0: case 137: michael@0: notImplemented(bc); michael@0: break; michael@0: case 144: michael@0: case 145: michael@0: case 147: michael@0: pop(); michael@0: push(Type.Number); michael@0: break; michael@0: case 146: michael@0: case 148: michael@0: local[bc.index] = Type.Number; michael@0: break; michael@0: case 149: michael@0: pop(); michael@0: push(Type.String); michael@0: break; michael@0: case 150: michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 160: michael@0: r = pop(); michael@0: l = pop(); michael@0: if (l.isNumeric() && r.isNumeric()) { michael@0: push(Type.Number); michael@0: } else if (l === Type.String || r === Type.String) { michael@0: push(Type.String); michael@0: } else { michael@0: push(Type.Any); michael@0: } michael@0: break; michael@0: case 161: michael@0: case 162: michael@0: case 163: michael@0: case 164: michael@0: pop(); michael@0: pop(); michael@0: push(Type.Number); michael@0: break; michael@0: case 168: michael@0: case 169: michael@0: case 170: michael@0: case 165: michael@0: case 166: michael@0: case 167: michael@0: pop(); michael@0: pop(); michael@0: push(Type.Int); michael@0: break; michael@0: case 151: michael@0: pop(); michael@0: push(Type.Int); michael@0: break; michael@0: case 171: michael@0: case 172: michael@0: case 173: michael@0: case 174: michael@0: case 175: michael@0: case 176: michael@0: case 177: michael@0: case 180: michael@0: pop(); michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 178: michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 179: michael@0: pop(); michael@0: pop(); michael@0: push(Type.Boolean); michael@0: break; michael@0: case 194: michael@0: case 195: michael@0: local[bc.index] = Type.Int; michael@0: break; michael@0: case 193: michael@0: case 192: michael@0: case 196: michael@0: pop(); michael@0: push(Type.Int); michael@0: break; michael@0: case 197: michael@0: case 198: michael@0: case 199: michael@0: pop(); michael@0: pop(); michael@0: push(Type.Int); michael@0: break; michael@0: case 208: michael@0: case 209: michael@0: case 210: michael@0: case 211: michael@0: push(local[op - OP_getlocal0]); michael@0: break; michael@0: case 212: michael@0: case 213: michael@0: case 214: michael@0: case 215: michael@0: local[op - OP_setlocal0] = pop(); michael@0: break; michael@0: case 239: michael@0: break; michael@0: case 240: michael@0: break; michael@0: case 241: michael@0: break; michael@0: case 242: michael@0: break; michael@0: case 243: michael@0: break; michael@0: default: michael@0: console.info('Not Implemented: ' + bc); michael@0: } michael@0: if (writer) { michael@0: if (bc.ti) { michael@0: writer.debugLn('> TI: ' + bc.ti); michael@0: } michael@0: } michael@0: } michael@0: if (writer) { michael@0: writer.leave('}'); michael@0: writer.writeLn('verifiedBlock: ' + block.bid + ', range: [' + block.position + ', ' + block.end.position + '], exitState: ' + state.toString()); michael@0: } michael@0: }; michael@0: return verification; michael@0: }(); michael@0: function verifier() { michael@0: this.writer = new IndentingWriter(); michael@0: } michael@0: verifier.prototype.verifyMethod = function (methodInfo, scope) { michael@0: try { michael@0: var domain = methodInfo.abc.applicationDomain; michael@0: var scopeObjects = scope.getScopeObjects(); michael@0: if (!scopeObjects[scopeObjects.length - 1]) { michael@0: if (methodInfo.holder instanceof InstanceInfo) { michael@0: scopeObjects[scopeObjects.length - 1] = methodInfo.holder.classInfo; michael@0: } else if (methodInfo.holder instanceof ClassInfo) { michael@0: scopeObjects[scopeObjects.length - 1] = methodInfo.holder; michael@0: } michael@0: } michael@0: var savedScope = scopeObjects.map(function (object) { michael@0: if (object instanceof MethodInfo) { michael@0: return Type.from(new ActivationInfo(object)); michael@0: } michael@0: return Type.from(object, domain); michael@0: }); michael@0: new Verification(methodInfo, methodInfo.abc.applicationDomain, savedScope).verify(); michael@0: methodInfo.verified = true; michael@0: Counter.count('Verifier: Methods'); michael@0: } catch (e) { michael@0: if (e instanceof VerifierError) { michael@0: return; michael@0: } michael@0: throw e; michael@0: } michael@0: }; michael@0: return verifier; michael@0: }(); michael@0: (function (exports) { michael@0: var debug = false; michael@0: var IRDefinition = { michael@0: Control: { michael@0: Region: { michael@0: predecessors: { michael@0: array: true, michael@0: expand: 'control' michael@0: }, michael@0: Start: { michael@0: _constructorText: 'this.control = this;', michael@0: scope: { michael@0: dynamic: true michael@0: }, michael@0: domain: { michael@0: dynamic: true michael@0: } michael@0: } michael@0: }, michael@0: End: { michael@0: control: { michael@0: assert: 'isControlOrNull' michael@0: }, michael@0: Stop: { michael@0: store: { michael@0: assert: 'isStore' michael@0: }, michael@0: argument: { michael@0: assert: '' michael@0: } michael@0: }, michael@0: If: { michael@0: predicate: { michael@0: assert: '' michael@0: } michael@0: }, michael@0: Switch: { michael@0: determinant: { michael@0: assert: '' michael@0: } michael@0: }, michael@0: Jump: {} michael@0: } michael@0: }, michael@0: Value: { michael@0: StoreDependent: { michael@0: control: { michael@0: assert: 'isControlOrNull', michael@0: nullable: true michael@0: }, michael@0: store: { michael@0: assert: 'isStoreOrNull', michael@0: nullable: true michael@0: }, michael@0: loads: { michael@0: dynamic: true, michael@0: nullable: true, michael@0: array: true michael@0: }, michael@0: Call: { michael@0: callee: { michael@0: assert: '' michael@0: }, michael@0: object: { michael@0: assert: 'isValueOrNull', michael@0: nullable: true michael@0: }, michael@0: args: { michael@0: assert: 'isArray', michael@0: array: true michael@0: }, michael@0: flags: { michael@0: internal: true, michael@0: assert: 'isNumber' michael@0: } michael@0: }, michael@0: CallProperty: { michael@0: object: { michael@0: assert: '' michael@0: }, michael@0: name: { michael@0: assert: '' michael@0: }, michael@0: args: { michael@0: assert: 'isArray', michael@0: array: true michael@0: }, michael@0: flags: { michael@0: internal: true, michael@0: assert: 'isNumber' michael@0: }, michael@0: ASCallProperty: { michael@0: isLex: { michael@0: assert: '', michael@0: internal: true michael@0: } michael@0: }, michael@0: ASCallSuper: { michael@0: scope: { michael@0: assert: '' michael@0: } michael@0: } michael@0: }, michael@0: New: { michael@0: callee: { michael@0: assert: '' michael@0: }, michael@0: args: { michael@0: assert: '', michael@0: array: true michael@0: }, michael@0: ASNew: {} michael@0: }, michael@0: GetProperty: { michael@0: object: { michael@0: assert: '' michael@0: }, michael@0: name: { michael@0: assert: '' michael@0: }, michael@0: ASGetProperty: { michael@0: flags: { michael@0: internal: true, michael@0: assert: 'isNumber' michael@0: } michael@0: }, michael@0: ASGetDescendants: {}, michael@0: ASHasProperty: {}, michael@0: ASGetSlot: {}, michael@0: ASGetSuper: { michael@0: scope: { michael@0: assert: '' michael@0: } michael@0: } michael@0: }, michael@0: SetProperty: { michael@0: object: { michael@0: assert: '' michael@0: }, michael@0: name: { michael@0: assert: '' michael@0: }, michael@0: value: { michael@0: assert: '' michael@0: }, michael@0: ASSetProperty: { michael@0: flags: { michael@0: internal: true michael@0: } michael@0: }, michael@0: ASSetSlot: {}, michael@0: ASSetSuper: { michael@0: scope: { michael@0: assert: '' michael@0: } michael@0: } michael@0: }, michael@0: DeleteProperty: { michael@0: object: { michael@0: assert: '' michael@0: }, michael@0: name: { michael@0: assert: '' michael@0: }, michael@0: ASDeleteProperty: {} michael@0: }, michael@0: ASFindProperty: { michael@0: scope: { michael@0: assert: '' michael@0: }, michael@0: name: { michael@0: assert: '' michael@0: }, michael@0: domain: { michael@0: assert: '' michael@0: }, michael@0: strict: { michael@0: internal: true michael@0: } michael@0: } michael@0: }, michael@0: Store: {}, michael@0: Phi: { michael@0: control: { michael@0: assert: 'isControl', michael@0: nullable: true michael@0: }, michael@0: args: { michael@0: array: true, michael@0: expand: 'value' michael@0: } michael@0: }, michael@0: Variable: { michael@0: name: { michael@0: internal: true michael@0: } michael@0: }, michael@0: Copy: { michael@0: argument: {} michael@0: }, michael@0: Move: { michael@0: to: {}, michael@0: from: {} michael@0: }, michael@0: Projection: { michael@0: argument: {}, michael@0: type: { michael@0: internal: true michael@0: }, michael@0: selector: { michael@0: internal: true, michael@0: optional: true michael@0: } michael@0: }, michael@0: Latch: { michael@0: control: { michael@0: assert: 'isControlOrNull', michael@0: nullable: true michael@0: }, michael@0: condition: {}, michael@0: left: {}, michael@0: right: {} michael@0: }, michael@0: Binary: { michael@0: operator: { michael@0: internal: true michael@0: }, michael@0: left: {}, michael@0: right: {} michael@0: }, michael@0: Unary: { michael@0: operator: { michael@0: internal: true michael@0: }, michael@0: argument: {} michael@0: }, michael@0: Constant: { michael@0: value: { michael@0: internal: true michael@0: } michael@0: }, michael@0: GlobalProperty: { michael@0: name: { michael@0: internal: true michael@0: } michael@0: }, michael@0: This: { michael@0: control: { michael@0: assert: 'isControl' michael@0: } michael@0: }, michael@0: Throw: { michael@0: control: { michael@0: assert: 'isControl' michael@0: }, michael@0: argument: {} michael@0: }, michael@0: Arguments: { michael@0: control: { michael@0: assert: 'isControl' michael@0: } michael@0: }, michael@0: Parameter: { michael@0: control: { michael@0: assert: 'isControl' michael@0: }, michael@0: index: { michael@0: internal: true michael@0: }, michael@0: name: { michael@0: internal: true michael@0: } michael@0: }, michael@0: NewArray: { michael@0: control: { michael@0: assert: 'isControl' michael@0: }, michael@0: elements: { michael@0: array: true michael@0: } michael@0: }, michael@0: NewObject: { michael@0: control: { michael@0: assert: 'isControl' michael@0: }, michael@0: properties: { michael@0: array: true michael@0: } michael@0: }, michael@0: KeyValuePair: { michael@0: key: {}, michael@0: value: {} michael@0: }, michael@0: ASScope: { michael@0: parent: {}, michael@0: object: {}, michael@0: isWith: { michael@0: internal: true michael@0: } michael@0: }, michael@0: ASGlobal: { michael@0: control: { michael@0: assert: 'isControlOrNull', michael@0: nullable: true michael@0: }, michael@0: scope: { michael@0: assert: 'isScope' michael@0: } michael@0: }, michael@0: ASNewActivation: { michael@0: methodInfo: { michael@0: internal: true michael@0: } michael@0: }, michael@0: ASMultiname: { michael@0: namespaces: {}, michael@0: name: {}, michael@0: flags: { michael@0: internal: true michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: function IRGenerator(root) { michael@0: var str = ''; michael@0: function out(s) { michael@0: str += s + '\n'; michael@0: } michael@0: var writer = new IndentingWriter(false, out); michael@0: function makeProperties(node) { michael@0: var result = []; michael@0: for (var k in node) { michael@0: if (isProperty(k)) { michael@0: node[k].name = k; michael@0: result.push(node[k]); michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: function isProperty(v) { michael@0: if (v[0] === '_') { michael@0: return false; michael@0: } michael@0: return v[0].toLowerCase() === v[0]; michael@0: } michael@0: function generate(node, path) { michael@0: path = path.concat([ michael@0: node michael@0: ]); michael@0: writer.enter('var ' + node._name + ' = (function () {'); michael@0: var constructorName = node._name[0].toLowerCase() + node._name.slice(1) + 'Node'; michael@0: if (constructorName.substring(0, 2) === 'aS') { michael@0: constructorName = 'as' + constructorName.substring(2); michael@0: } michael@0: var prototypeName = constructorName + '.prototype'; michael@0: var properties = path.reduce(function (a, v) { michael@0: return a.concat(makeProperties(v)); michael@0: }, []); michael@0: var parameters = properties.filter(function (property) { michael@0: return !property.dynamic; michael@0: }); michael@0: var optionalParameters = parameters.filter(function (property) { michael@0: return property.optional; michael@0: }); michael@0: var parameterString = parameters.map(function (property) { michael@0: if (property.expand) { michael@0: return property.expand; michael@0: } michael@0: return property.name; michael@0: }).join(', '); michael@0: writer.enter('function ' + constructorName + '(' + parameterString + ') {'); michael@0: if (true) { michael@0: properties.forEach(function (property) { michael@0: if (property.assert === '') { michael@0: writer.writeLn('release || assert (!(' + property.name + ' == undefined), "' + property.name + '");'); michael@0: } else if (property.assert) { michael@0: writer.writeLn('release || assert (' + property.assert + '(' + property.name + '), "' + property.name + '");'); michael@0: } michael@0: }); michael@0: writer.writeLn('release || assert (arguments.length >= ' + (parameters.length - optionalParameters.length) + ', "' + node._name + ' not enough args.");'); michael@0: } michael@0: if (node._constructorText) { michael@0: writer.writeLn(node._constructorText); michael@0: } michael@0: properties.forEach(function (property) { michael@0: if (property.expand) { michael@0: writer.writeLn('this.' + property.name + ' = ' + property.expand + ' ? [' + property.expand + '] : [];'); michael@0: } else if (property.dynamic) { michael@0: writer.writeLn('this.' + property.name + ' = undefined;'); michael@0: } else { michael@0: writer.writeLn('this.' + property.name + ' = ' + property.name + ';'); michael@0: } michael@0: }); michael@0: writer.writeLn('this.id = nextID[nextID.length - 1] += 1;'); michael@0: writer.leave('}'); michael@0: if (path.length > 1) { michael@0: writer.writeLn(prototypeName + ' = ' + 'extend(' + path[path.length - 2]._name + ', "' + node._name + '");'); michael@0: } michael@0: writer.writeLn(prototypeName + '.nodeName = "' + node._name + '";'); michael@0: writer.enter(prototypeName + '.visitInputs = function (visitor) {'); michael@0: properties.forEach(function (property) { michael@0: if (property.internal) { michael@0: return; michael@0: } michael@0: var str = ''; michael@0: if (property.nullable) { michael@0: str += 'this.' + property.name + ' && '; michael@0: } michael@0: if (property.array) { michael@0: str += 'visitArrayInputs(this.' + property.name + ', visitor);'; michael@0: } else { michael@0: str += 'visitor(this.' + property.name + ');'; michael@0: } michael@0: writer.writeLn(str); michael@0: }); michael@0: writer.leave('};'); michael@0: writer.writeLn('return ' + constructorName + ';'); michael@0: writer.leave('})();'); michael@0: writer.writeLn(''); michael@0: for (var name in node) { michael@0: if (name[0] === '_' || isProperty(name)) { michael@0: continue; michael@0: } michael@0: var child = node[name]; michael@0: child._name = name; michael@0: generate(child, path); michael@0: } michael@0: } michael@0: IRDefinition._name = 'Node'; michael@0: generate(IRDefinition, []); michael@0: return str; michael@0: } michael@0: var nextID = []; michael@0: var Node = function () { michael@0: function nodeNode() { michael@0: true; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: nodeNode.prototype.nodeName = 'Node'; michael@0: nodeNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return nodeNode; michael@0: }(); michael@0: var Control = function () { michael@0: function controlNode() { michael@0: true; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: controlNode.prototype = extend(Node, 'Control'); michael@0: controlNode.prototype.nodeName = 'Control'; michael@0: controlNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return controlNode; michael@0: }(); michael@0: var Region = function () { michael@0: function regionNode(control) { michael@0: true; michael@0: this.predecessors = control ? [ michael@0: control michael@0: ] : []; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: regionNode.prototype = extend(Control, 'Region'); michael@0: regionNode.prototype.nodeName = 'Region'; michael@0: regionNode.prototype.visitInputs = function (visitor) { michael@0: visitArrayInputs(this.predecessors, visitor); michael@0: }; michael@0: return regionNode; michael@0: }(); michael@0: var Start = function () { michael@0: function startNode(control) { michael@0: true; michael@0: this.control = this; michael@0: this.predecessors = control ? [ michael@0: control michael@0: ] : []; michael@0: this.scope = undefined; michael@0: this.domain = undefined; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: startNode.prototype = extend(Region, 'Start'); michael@0: startNode.prototype.nodeName = 'Start'; michael@0: startNode.prototype.visitInputs = function (visitor) { michael@0: visitArrayInputs(this.predecessors, visitor); michael@0: visitor(this.scope); michael@0: visitor(this.domain); michael@0: }; michael@0: return startNode; michael@0: }(); michael@0: var End = function () { michael@0: function endNode(control) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: endNode.prototype = extend(Control, 'End'); michael@0: endNode.prototype.nodeName = 'End'; michael@0: endNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: }; michael@0: return endNode; michael@0: }(); michael@0: var Stop = function () { michael@0: function stopNode(control, store, argument) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.argument = argument; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: stopNode.prototype = extend(End, 'Stop'); michael@0: stopNode.prototype.nodeName = 'Stop'; michael@0: stopNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitor(this.store); michael@0: visitor(this.argument); michael@0: }; michael@0: return stopNode; michael@0: }(); michael@0: var If = function () { michael@0: function ifNode(control, predicate) { michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.predicate = predicate; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: ifNode.prototype = extend(End, 'If'); michael@0: ifNode.prototype.nodeName = 'If'; michael@0: ifNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitor(this.predicate); michael@0: }; michael@0: return ifNode; michael@0: }(); michael@0: var Switch = function () { michael@0: function switchNode(control, determinant) { michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.determinant = determinant; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: switchNode.prototype = extend(End, 'Switch'); michael@0: switchNode.prototype.nodeName = 'Switch'; michael@0: switchNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitor(this.determinant); michael@0: }; michael@0: return switchNode; michael@0: }(); michael@0: var Jump = function () { michael@0: function jumpNode(control) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: jumpNode.prototype = extend(End, 'Jump'); michael@0: jumpNode.prototype.nodeName = 'Jump'; michael@0: jumpNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: }; michael@0: return jumpNode; michael@0: }(); michael@0: var Value = function () { michael@0: function valueNode() { michael@0: true; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: valueNode.prototype = extend(Node, 'Value'); michael@0: valueNode.prototype.nodeName = 'Value'; michael@0: valueNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return valueNode; michael@0: }(); michael@0: var StoreDependent = function () { michael@0: function storeDependentNode(control, store) { michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: storeDependentNode.prototype = extend(Value, 'StoreDependent'); michael@0: storeDependentNode.prototype.nodeName = 'StoreDependent'; michael@0: storeDependentNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: }; michael@0: return storeDependentNode; michael@0: }(); michael@0: var Call = function () { michael@0: function callNode(control, store, callee, object, args, flags) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.callee = callee; michael@0: this.object = object; michael@0: this.args = args; michael@0: this.flags = flags; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: callNode.prototype = extend(StoreDependent, 'Call'); michael@0: callNode.prototype.nodeName = 'Call'; michael@0: callNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.callee); michael@0: this.object && visitor(this.object); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return callNode; michael@0: }(); michael@0: var CallProperty = function () { michael@0: function callPropertyNode(control, store, object, name, args, flags) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.args = args; michael@0: this.flags = flags; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: callPropertyNode.prototype = extend(StoreDependent, 'CallProperty'); michael@0: callPropertyNode.prototype.nodeName = 'CallProperty'; michael@0: callPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return callPropertyNode; michael@0: }(); michael@0: var ASCallProperty = function () { michael@0: function asCallPropertyNode(control, store, object, name, args, flags, isLex) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.args = args; michael@0: this.flags = flags; michael@0: this.isLex = isLex; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asCallPropertyNode.prototype = extend(CallProperty, 'ASCallProperty'); michael@0: asCallPropertyNode.prototype.nodeName = 'ASCallProperty'; michael@0: asCallPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return asCallPropertyNode; michael@0: }(); michael@0: var ASCallSuper = function () { michael@0: function asCallSuperNode(control, store, object, name, args, flags, scope) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.args = args; michael@0: this.flags = flags; michael@0: this.scope = scope; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asCallSuperNode.prototype = extend(CallProperty, 'ASCallSuper'); michael@0: asCallSuperNode.prototype.nodeName = 'ASCallSuper'; michael@0: asCallSuperNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitArrayInputs(this.args, visitor); michael@0: visitor(this.scope); michael@0: }; michael@0: return asCallSuperNode; michael@0: }(); michael@0: var New = function () { michael@0: function newNode(control, store, callee, args) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.callee = callee; michael@0: this.args = args; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: newNode.prototype = extend(StoreDependent, 'New'); michael@0: newNode.prototype.nodeName = 'New'; michael@0: newNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.callee); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return newNode; michael@0: }(); michael@0: var ASNew = function () { michael@0: function asNewNode(control, store, callee, args) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.callee = callee; michael@0: this.args = args; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asNewNode.prototype = extend(New, 'ASNew'); michael@0: asNewNode.prototype.nodeName = 'ASNew'; michael@0: asNewNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.callee); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return asNewNode; michael@0: }(); michael@0: var GetProperty = function () { michael@0: function getPropertyNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: getPropertyNode.prototype = extend(StoreDependent, 'GetProperty'); michael@0: getPropertyNode.prototype.nodeName = 'GetProperty'; michael@0: getPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return getPropertyNode; michael@0: }(); michael@0: var ASGetProperty = function () { michael@0: function asGetPropertyNode(control, store, object, name, flags) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.flags = flags; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asGetPropertyNode.prototype = extend(GetProperty, 'ASGetProperty'); michael@0: asGetPropertyNode.prototype.nodeName = 'ASGetProperty'; michael@0: asGetPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return asGetPropertyNode; michael@0: }(); michael@0: var ASGetDescendants = function () { michael@0: function asGetDescendantsNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asGetDescendantsNode.prototype = extend(GetProperty, 'ASGetDescendants'); michael@0: asGetDescendantsNode.prototype.nodeName = 'ASGetDescendants'; michael@0: asGetDescendantsNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return asGetDescendantsNode; michael@0: }(); michael@0: var ASHasProperty = function () { michael@0: function asHasPropertyNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asHasPropertyNode.prototype = extend(GetProperty, 'ASHasProperty'); michael@0: asHasPropertyNode.prototype.nodeName = 'ASHasProperty'; michael@0: asHasPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return asHasPropertyNode; michael@0: }(); michael@0: var ASGetSlot = function () { michael@0: function asGetSlotNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asGetSlotNode.prototype = extend(GetProperty, 'ASGetSlot'); michael@0: asGetSlotNode.prototype.nodeName = 'ASGetSlot'; michael@0: asGetSlotNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return asGetSlotNode; michael@0: }(); michael@0: var ASGetSuper = function () { michael@0: function asGetSuperNode(control, store, object, name, scope) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.scope = scope; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asGetSuperNode.prototype = extend(GetProperty, 'ASGetSuper'); michael@0: asGetSuperNode.prototype.nodeName = 'ASGetSuper'; michael@0: asGetSuperNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitor(this.scope); michael@0: }; michael@0: return asGetSuperNode; michael@0: }(); michael@0: var SetProperty = function () { michael@0: function setPropertyNode(control, store, object, name, value) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.value = value; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: setPropertyNode.prototype = extend(StoreDependent, 'SetProperty'); michael@0: setPropertyNode.prototype.nodeName = 'SetProperty'; michael@0: setPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitor(this.value); michael@0: }; michael@0: return setPropertyNode; michael@0: }(); michael@0: var ASSetProperty = function () { michael@0: function asSetPropertyNode(control, store, object, name, value, flags) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.value = value; michael@0: this.flags = flags; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asSetPropertyNode.prototype = extend(SetProperty, 'ASSetProperty'); michael@0: asSetPropertyNode.prototype.nodeName = 'ASSetProperty'; michael@0: asSetPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitor(this.value); michael@0: }; michael@0: return asSetPropertyNode; michael@0: }(); michael@0: var ASSetSlot = function () { michael@0: function asSetSlotNode(control, store, object, name, value) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.value = value; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asSetSlotNode.prototype = extend(SetProperty, 'ASSetSlot'); michael@0: asSetSlotNode.prototype.nodeName = 'ASSetSlot'; michael@0: asSetSlotNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitor(this.value); michael@0: }; michael@0: return asSetSlotNode; michael@0: }(); michael@0: var ASSetSuper = function () { michael@0: function asSetSuperNode(control, store, object, name, value, scope) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.value = value; michael@0: this.scope = scope; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asSetSuperNode.prototype = extend(SetProperty, 'ASSetSuper'); michael@0: asSetSuperNode.prototype.nodeName = 'ASSetSuper'; michael@0: asSetSuperNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: visitor(this.value); michael@0: visitor(this.scope); michael@0: }; michael@0: return asSetSuperNode; michael@0: }(); michael@0: var DeleteProperty = function () { michael@0: function deletePropertyNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: deletePropertyNode.prototype = extend(StoreDependent, 'DeleteProperty'); michael@0: deletePropertyNode.prototype.nodeName = 'DeleteProperty'; michael@0: deletePropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return deletePropertyNode; michael@0: }(); michael@0: var ASDeleteProperty = function () { michael@0: function asDeletePropertyNode(control, store, object, name) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.object = object; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asDeletePropertyNode.prototype = extend(DeleteProperty, 'ASDeleteProperty'); michael@0: asDeletePropertyNode.prototype.nodeName = 'ASDeleteProperty'; michael@0: asDeletePropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.object); michael@0: visitor(this.name); michael@0: }; michael@0: return asDeletePropertyNode; michael@0: }(); michael@0: var ASFindProperty = function () { michael@0: function asFindPropertyNode(control, store, scope, name, domain, strict) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.store = store; michael@0: this.loads = undefined; michael@0: this.scope = scope; michael@0: this.name = name; michael@0: this.domain = domain; michael@0: this.strict = strict; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asFindPropertyNode.prototype = extend(StoreDependent, 'ASFindProperty'); michael@0: asFindPropertyNode.prototype.nodeName = 'ASFindProperty'; michael@0: asFindPropertyNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: this.store && visitor(this.store); michael@0: this.loads && visitArrayInputs(this.loads, visitor); michael@0: visitor(this.scope); michael@0: visitor(this.name); michael@0: visitor(this.domain); michael@0: }; michael@0: return asFindPropertyNode; michael@0: }(); michael@0: var Store = function () { michael@0: function storeNode() { michael@0: true; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: storeNode.prototype = extend(Value, 'Store'); michael@0: storeNode.prototype.nodeName = 'Store'; michael@0: storeNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return storeNode; michael@0: }(); michael@0: var Phi = function () { michael@0: function phiNode(control, value) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.args = value ? [ michael@0: value michael@0: ] : []; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: phiNode.prototype = extend(Value, 'Phi'); michael@0: phiNode.prototype.nodeName = 'Phi'; michael@0: phiNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: visitArrayInputs(this.args, visitor); michael@0: }; michael@0: return phiNode; michael@0: }(); michael@0: var Variable = function () { michael@0: function variableNode(name) { michael@0: true; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: variableNode.prototype = extend(Value, 'Variable'); michael@0: variableNode.prototype.nodeName = 'Variable'; michael@0: variableNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return variableNode; michael@0: }(); michael@0: var Copy = function () { michael@0: function copyNode(argument) { michael@0: true; michael@0: this.argument = argument; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: copyNode.prototype = extend(Value, 'Copy'); michael@0: copyNode.prototype.nodeName = 'Copy'; michael@0: copyNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.argument); michael@0: }; michael@0: return copyNode; michael@0: }(); michael@0: var Move = function () { michael@0: function moveNode(to, from) { michael@0: true; michael@0: this.to = to; michael@0: this.from = from; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: moveNode.prototype = extend(Value, 'Move'); michael@0: moveNode.prototype.nodeName = 'Move'; michael@0: moveNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.to); michael@0: visitor(this.from); michael@0: }; michael@0: return moveNode; michael@0: }(); michael@0: var Projection = function () { michael@0: function projectionNode(argument, type, selector) { michael@0: true; michael@0: this.argument = argument; michael@0: this.type = type; michael@0: this.selector = selector; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: projectionNode.prototype = extend(Value, 'Projection'); michael@0: projectionNode.prototype.nodeName = 'Projection'; michael@0: projectionNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.argument); michael@0: }; michael@0: return projectionNode; michael@0: }(); michael@0: var Latch = function () { michael@0: function latchNode(control, condition, left, right) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.condition = condition; michael@0: this.left = left; michael@0: this.right = right; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: latchNode.prototype = extend(Value, 'Latch'); michael@0: latchNode.prototype.nodeName = 'Latch'; michael@0: latchNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: visitor(this.condition); michael@0: visitor(this.left); michael@0: visitor(this.right); michael@0: }; michael@0: return latchNode; michael@0: }(); michael@0: var Binary = function () { michael@0: function binaryNode(operator, left, right) { michael@0: true; michael@0: this.operator = operator; michael@0: this.left = left; michael@0: this.right = right; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: binaryNode.prototype = extend(Value, 'Binary'); michael@0: binaryNode.prototype.nodeName = 'Binary'; michael@0: binaryNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.left); michael@0: visitor(this.right); michael@0: }; michael@0: return binaryNode; michael@0: }(); michael@0: var Unary = function () { michael@0: function unaryNode(operator, argument) { michael@0: true; michael@0: this.operator = operator; michael@0: this.argument = argument; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: unaryNode.prototype = extend(Value, 'Unary'); michael@0: unaryNode.prototype.nodeName = 'Unary'; michael@0: unaryNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.argument); michael@0: }; michael@0: return unaryNode; michael@0: }(); michael@0: var Constant = function () { michael@0: function constantNode(value) { michael@0: true; michael@0: this.value = value; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: constantNode.prototype = extend(Value, 'Constant'); michael@0: constantNode.prototype.nodeName = 'Constant'; michael@0: constantNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return constantNode; michael@0: }(); michael@0: var GlobalProperty = function () { michael@0: function globalPropertyNode(name) { michael@0: true; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: globalPropertyNode.prototype = extend(Value, 'GlobalProperty'); michael@0: globalPropertyNode.prototype.nodeName = 'GlobalProperty'; michael@0: globalPropertyNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return globalPropertyNode; michael@0: }(); michael@0: var This = function () { michael@0: function thisNode(control) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: thisNode.prototype = extend(Value, 'This'); michael@0: thisNode.prototype.nodeName = 'This'; michael@0: thisNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: }; michael@0: return thisNode; michael@0: }(); michael@0: var Throw = function () { michael@0: function throwNode(control, argument) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.argument = argument; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: throwNode.prototype = extend(Value, 'Throw'); michael@0: throwNode.prototype.nodeName = 'Throw'; michael@0: throwNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitor(this.argument); michael@0: }; michael@0: return throwNode; michael@0: }(); michael@0: var Arguments = function () { michael@0: function argumentsNode(control) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: argumentsNode.prototype = extend(Value, 'Arguments'); michael@0: argumentsNode.prototype.nodeName = 'Arguments'; michael@0: argumentsNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: }; michael@0: return argumentsNode; michael@0: }(); michael@0: var Parameter = function () { michael@0: function parameterNode(control, index, name) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.index = index; michael@0: this.name = name; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: parameterNode.prototype = extend(Value, 'Parameter'); michael@0: parameterNode.prototype.nodeName = 'Parameter'; michael@0: parameterNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: }; michael@0: return parameterNode; michael@0: }(); michael@0: var NewArray = function () { michael@0: function newArrayNode(control, elements) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.elements = elements; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: newArrayNode.prototype = extend(Value, 'NewArray'); michael@0: newArrayNode.prototype.nodeName = 'NewArray'; michael@0: newArrayNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitArrayInputs(this.elements, visitor); michael@0: }; michael@0: return newArrayNode; michael@0: }(); michael@0: var NewObject = function () { michael@0: function newObjectNode(control, properties) { michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.properties = properties; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: newObjectNode.prototype = extend(Value, 'NewObject'); michael@0: newObjectNode.prototype.nodeName = 'NewObject'; michael@0: newObjectNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.control); michael@0: visitArrayInputs(this.properties, visitor); michael@0: }; michael@0: return newObjectNode; michael@0: }(); michael@0: var KeyValuePair = function () { michael@0: function keyValuePairNode(key, value) { michael@0: true; michael@0: this.key = key; michael@0: this.value = value; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: keyValuePairNode.prototype = extend(Value, 'KeyValuePair'); michael@0: keyValuePairNode.prototype.nodeName = 'KeyValuePair'; michael@0: keyValuePairNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.key); michael@0: visitor(this.value); michael@0: }; michael@0: return keyValuePairNode; michael@0: }(); michael@0: var ASScope = function () { michael@0: function asScopeNode(parent, object, isWith) { michael@0: true; michael@0: this.parent = parent; michael@0: this.object = object; michael@0: this.isWith = isWith; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asScopeNode.prototype = extend(Value, 'ASScope'); michael@0: asScopeNode.prototype.nodeName = 'ASScope'; michael@0: asScopeNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.parent); michael@0: visitor(this.object); michael@0: }; michael@0: return asScopeNode; michael@0: }(); michael@0: var ASGlobal = function () { michael@0: function asGlobalNode(control, scope) { michael@0: true; michael@0: true; michael@0: true; michael@0: this.control = control; michael@0: this.scope = scope; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asGlobalNode.prototype = extend(Value, 'ASGlobal'); michael@0: asGlobalNode.prototype.nodeName = 'ASGlobal'; michael@0: asGlobalNode.prototype.visitInputs = function (visitor) { michael@0: this.control && visitor(this.control); michael@0: visitor(this.scope); michael@0: }; michael@0: return asGlobalNode; michael@0: }(); michael@0: var ASNewActivation = function () { michael@0: function asNewActivationNode(methodInfo) { michael@0: true; michael@0: this.methodInfo = methodInfo; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asNewActivationNode.prototype = extend(Value, 'ASNewActivation'); michael@0: asNewActivationNode.prototype.nodeName = 'ASNewActivation'; michael@0: asNewActivationNode.prototype.visitInputs = function (visitor) { michael@0: }; michael@0: return asNewActivationNode; michael@0: }(); michael@0: var ASMultiname = function () { michael@0: function asMultinameNode(namespaces, name, flags) { michael@0: true; michael@0: this.namespaces = namespaces; michael@0: this.name = name; michael@0: this.flags = flags; michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: asMultinameNode.prototype = extend(Value, 'ASMultiname'); michael@0: asMultinameNode.prototype.nodeName = 'ASMultiname'; michael@0: asMultinameNode.prototype.visitInputs = function (visitor) { michael@0: visitor(this.namespaces); michael@0: visitor(this.name); michael@0: }; michael@0: return asMultinameNode; michael@0: }(); michael@0: function node() { michael@0: this.id = nextID[nextID.length - 1] += 1; michael@0: } michael@0: Node.startNumbering = function () { michael@0: nextID.push(0); michael@0: }; michael@0: Node.stopNumbering = function () { michael@0: nextID.pop(); michael@0: }; michael@0: Node.prototype.toString = function (brief) { michael@0: if (brief) { michael@0: return nameOf(this); michael@0: } michael@0: var inputs = []; michael@0: this.visitInputs(function (input) { michael@0: inputs.push(nameOf(input)); michael@0: }); michael@0: var str = nameOf(this) + ' = ' + this.nodeName.toUpperCase(); michael@0: if (this.toStringDetails) { michael@0: str += ' ' + this.toStringDetails(); michael@0: } michael@0: if (inputs.length) { michael@0: str += ' ' + inputs.join(', '); michael@0: } michael@0: return str; michael@0: }; michael@0: Node.prototype.visitInputsNoConstants = function visitInputs(visitor) { michael@0: this.visitInputs(function (node) { michael@0: if (isConstant(node)) { michael@0: return; michael@0: } michael@0: visitor(node); michael@0: }); michael@0: }; michael@0: Node.prototype.replaceInput = function (oldInput, newInput) { michael@0: var count = 0; michael@0: for (var k in this) { michael@0: var v = this[k]; michael@0: if (v instanceof Node) { michael@0: if (v === oldInput) { michael@0: this[k] = newInput; michael@0: count++; michael@0: } michael@0: } michael@0: if (v instanceof Array) { michael@0: count += v.replace(oldInput, newInput); michael@0: } michael@0: } michael@0: return count; michael@0: }; michael@0: Projection.Type = { michael@0: CASE: 'case', michael@0: TRUE: 'true', michael@0: FALSE: 'false', michael@0: STORE: 'store', michael@0: SCOPE: 'scope' michael@0: }; michael@0: Projection.prototype.project = function () { michael@0: return this.argument; michael@0: }; michael@0: Phi.prototype.seal = function seal() { michael@0: this.sealed = true; michael@0: }; michael@0: Phi.prototype.pushValue = function pushValue(x) { michael@0: true; michael@0: true; michael@0: this.args.push(x); michael@0: }; michael@0: KeyValuePair.prototype.mustFloat = true; michael@0: ASMultiname.prototype.mustFloat = true; michael@0: ASMultiname.prototype.isAttribute = function () { michael@0: return this.flags & 1; michael@0: }; michael@0: var Flags = { michael@0: INDEXED: 1, michael@0: RESOLVED: 2, michael@0: PRISTINE: 4, michael@0: IS_METHOD: 8 michael@0: }; michael@0: var Operator = function () { michael@0: var map = {}; michael@0: function operator(name, evaluate, binary) { michael@0: this.name = name; michael@0: this.binary = binary; michael@0: this.evaluate = evaluate; michael@0: map[name] = this; michael@0: } michael@0: operator.ADD = new operator('+', function (l, r) { michael@0: return l + r; michael@0: }, true); michael@0: operator.SUB = new operator('-', function (l, r) { michael@0: return l - r; michael@0: }, true); michael@0: operator.MUL = new operator('*', function (l, r) { michael@0: return l * r; michael@0: }, true); michael@0: operator.DIV = new operator('/', function (l, r) { michael@0: return l / r; michael@0: }, true); michael@0: operator.MOD = new operator('%', function (l, r) { michael@0: return l % r; michael@0: }, true); michael@0: operator.AND = new operator('&', function (l, r) { michael@0: return l & r; michael@0: }, true); michael@0: operator.OR = new operator('|', function (l, r) { michael@0: return l | r; michael@0: }, true); michael@0: operator.XOR = new operator('^', function (l, r) { michael@0: return l ^ r; michael@0: }, true); michael@0: operator.LSH = new operator('<<', function (l, r) { michael@0: return l << r; michael@0: }, true); michael@0: operator.RSH = new operator('>>', function (l, r) { michael@0: return l >> r; michael@0: }, true); michael@0: operator.URSH = new operator('>>>', function (l, r) { michael@0: return l >>> r; michael@0: }, true); michael@0: operator.SEQ = new operator('===', function (l, r) { michael@0: return l === r; michael@0: }, true); michael@0: operator.SNE = new operator('!==', function (l, r) { michael@0: return l !== r; michael@0: }, true); michael@0: operator.EQ = new operator('==', function (l, r) { michael@0: return l == r; michael@0: }, true); michael@0: operator.NE = new operator('!=', function (l, r) { michael@0: return l != r; michael@0: }, true); michael@0: operator.LE = new operator('<=', function (l, r) { michael@0: return l <= r; michael@0: }, true); michael@0: operator.GT = new operator('>', function (l, r) { michael@0: return l > r; michael@0: }, true); michael@0: operator.LT = new operator('<', function (l, r) { michael@0: return l < r; michael@0: }, true); michael@0: operator.GE = new operator('>=', function (l, r) { michael@0: return l >= r; michael@0: }, true); michael@0: operator.BITWISE_NOT = new operator('~', function (a) { michael@0: return ~a; michael@0: }, false); michael@0: operator.PLUS = new operator('+', function (a) { michael@0: return +a; michael@0: }, false); michael@0: operator.NEG = new operator('-', function (a) { michael@0: return -a; michael@0: }, false); michael@0: operator.TYPE_OF = new operator('typeof', function (a) { michael@0: return typeof a; michael@0: }, false); michael@0: operator.TRUE = new operator('!!', function (a) { michael@0: return !(!a); michael@0: }, false); michael@0: operator.FALSE = new operator('!', function (a) { michael@0: return !a; michael@0: }, false); michael@0: operator.AS_ADD = new operator('+', function (l, r) { michael@0: if (typeof l === 'string' || typeof r === 'string') { michael@0: return String(l) + String(r); michael@0: } michael@0: return l + r; michael@0: }, true); michael@0: function linkOpposites(a, b) { michael@0: a.not = b; michael@0: b.not = a; michael@0: } michael@0: linkOpposites(operator.SEQ, operator.SNE); michael@0: linkOpposites(operator.EQ, operator.NE); michael@0: linkOpposites(operator.TRUE, operator.FALSE); michael@0: operator.fromName = function fromName(name) { michael@0: return map[name]; michael@0: }; michael@0: operator.prototype.isBinary = function isBinary() { michael@0: return this.binary; michael@0: }; michael@0: operator.prototype.toString = function toString() { michael@0: return this.name; michael@0: }; michael@0: return operator; michael@0: }(); michael@0: function extend(c, name) { michael@0: true; michael@0: return Object.create(c.prototype, { michael@0: nodeName: { michael@0: value: name michael@0: } michael@0: }); michael@0: } michael@0: function nameOf(o) { michael@0: var useColors = false; michael@0: var result; michael@0: if (o instanceof Constant) { michael@0: if (o.value instanceof Multiname) { michael@0: return o.value.name; michael@0: } michael@0: return o.value; michael@0: } else if (o instanceof Variable) { michael@0: return o.name; michael@0: } else if (o instanceof Phi) { michael@0: return result = '|' + o.id + '|', useColors ? PURPLE + result + ENDC : result; michael@0: } else if (o instanceof Control) { michael@0: return result = '{' + o.id + '}', useColors ? RED + result + ENDC : result; michael@0: } else if (o instanceof Projection) { michael@0: if (o.type === Projection.Type.STORE) { michael@0: return result = '[' + o.id + '->' + o.argument.id + ']', useColors ? YELLOW + result + ENDC : result; michael@0: } michael@0: return result = '(' + o.id + ')', useColors ? GREEN + result + ENDC : result; michael@0: } else if (o instanceof Value) { michael@0: return result = '(' + o.id + ')', useColors ? GREEN + result + ENDC : result; michael@0: } else if (o instanceof Node) { michael@0: return o.id; michael@0: } michael@0: unexpected(o + ' ' + typeof o); michael@0: } michael@0: function toID(node) { michael@0: return node.id; michael@0: } michael@0: function visitArrayInputs(array, visitor) { michael@0: for (var i = 0; i < array.length; i++) { michael@0: visitor(array[i]); michael@0: } michael@0: } michael@0: function visitNothing() { michael@0: } michael@0: function isNotPhi(phi) { michael@0: return !isPhi(phi); michael@0: } michael@0: function isPhi(phi) { michael@0: return phi instanceof Phi; michael@0: } michael@0: function isScope(scope) { michael@0: return isPhi(scope) || scope instanceof ASScope || isProjection(scope, Projection.Type.SCOPE); michael@0: } michael@0: function isMultinameConstant(node) { michael@0: return node instanceof Constant && node.value instanceof Multiname; michael@0: } michael@0: function isMultiname(name) { michael@0: return isMultinameConstant(name) || name instanceof ASMultiname; michael@0: } michael@0: function isStore(store) { michael@0: return isPhi(store) || store instanceof Store || isProjection(store, Projection.Type.STORE); michael@0: } michael@0: function isConstant(constant) { michael@0: return constant instanceof Constant; michael@0: } michael@0: function isBoolean(boolean) { michael@0: return boolean === true || boolean === false; michael@0: } michael@0: function isInteger(integer) { michael@0: return integer | 0 === integer; michael@0: } michael@0: function isArray(array) { michael@0: return array instanceof Array; michael@0: } michael@0: function isControlOrNull(control) { michael@0: return isControl(control) || control === null; michael@0: } michael@0: function isStoreOrNull(store) { michael@0: return isStore(store) || store === null; michael@0: } michael@0: function isControl(control) { michael@0: return control instanceof Control; michael@0: } michael@0: function isValueOrNull(value) { michael@0: return isValue(value) || value === null; michael@0: } michael@0: function isValue(value) { michael@0: return value instanceof Value; michael@0: } michael@0: function isProjection(node, type) { michael@0: return node instanceof Projection && (!type || node.type === type); michael@0: } michael@0: var Null = new Constant(null); michael@0: var Undefined = new Constant(undefined); michael@0: Undefined.toString = function () { michael@0: return '_'; michael@0: }; michael@0: var Block = function () { michael@0: function block(id, start, end) { michael@0: if (start) { michael@0: true; michael@0: } michael@0: this.region = start; michael@0: this.id = id; michael@0: this.successors = []; michael@0: this.predecessors = []; michael@0: this.nodes = [ michael@0: start, michael@0: end michael@0: ]; michael@0: } michael@0: block.prototype.pushSuccessorAt = function pushSuccessor(successor, index, pushPredecessor) { michael@0: true; michael@0: true; michael@0: this.successors[index] = successor; michael@0: if (pushPredecessor) { michael@0: successor.pushPredecessor(this); michael@0: } michael@0: }; michael@0: block.prototype.pushSuccessor = function pushSuccessor(successor, pushPredecessor) { michael@0: true; michael@0: this.successors.push(successor); michael@0: if (pushPredecessor) { michael@0: successor.pushPredecessor(this); michael@0: } michael@0: }; michael@0: block.prototype.pushPredecessor = function pushPredecessor(predecessor) { michael@0: true; michael@0: this.predecessors.push(predecessor); michael@0: }; michael@0: block.prototype.visitNodes = function (fn) { michael@0: var nodes = this.nodes; michael@0: for (var i = 0, j = nodes.length; i < j; i++) { michael@0: fn(nodes[i]); michael@0: } michael@0: }; michael@0: block.prototype.visitSuccessors = function (fn) { michael@0: var successors = this.successors; michael@0: for (var i = 0, j = successors.length; i < j; i++) { michael@0: fn(successors[i]); michael@0: } michael@0: }; michael@0: block.prototype.visitPredecessors = function (fn) { michael@0: var predecessors = this.predecessors; michael@0: for (var i = 0, j = predecessors.length; i < j; i++) { michael@0: fn(predecessors[i]); michael@0: } michael@0: }; michael@0: block.prototype.append = function (node) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: if (node.mustFloat) { michael@0: return; michael@0: } michael@0: this.nodes.splice(this.nodes.length - 1, 0, node); michael@0: }; michael@0: block.prototype.toString = function () { michael@0: return 'B' + this.id + (this.name ? ' (' + this.name + ')' : ''); michael@0: }; michael@0: block.prototype.trace = function (writer) { michael@0: writer.writeLn(this); michael@0: }; michael@0: return block; michael@0: }(); michael@0: var DFG = function () { michael@0: function constructor(exit) { michael@0: this.exit = exit; michael@0: } michael@0: constructor.prototype.buildCFG = function () { michael@0: return CFG.fromDFG(this); michael@0: }; michael@0: function preOrderDepthFirstSearch(root, visitChildren, pre) { michael@0: var visited = []; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var push = worklist.push.bind(worklist); michael@0: var node; michael@0: while (node = worklist.pop()) { michael@0: if (visited[node.id] === 1) { michael@0: continue; michael@0: } michael@0: visited[node.id] = 1; michael@0: pre(node); michael@0: worklist.push(node); michael@0: visitChildren(node, push); michael@0: } michael@0: } michael@0: function postOrderDepthFirstSearch(root, visitChildren, post) { michael@0: var ONE_TIME = 1, MANY_TIMES = 2; michael@0: var visited = []; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: function visitChild(child) { michael@0: if (!visited[child.id]) { michael@0: worklist.push(child); michael@0: } michael@0: } michael@0: var node; michael@0: while (node = worklist.top()) { michael@0: if (visited[node.id]) { michael@0: if (visited[node.id] === ONE_TIME) { michael@0: visited[node.id] = MANY_TIMES; michael@0: post(node); michael@0: } michael@0: worklist.pop(); michael@0: continue; michael@0: } michael@0: visited[node.id] = ONE_TIME; michael@0: visitChildren(node, visitChild); michael@0: } michael@0: } michael@0: constructor.prototype.forEachInPreOrderDepthFirstSearch = function forEachInPreOrderDepthFirstSearch(visitor) { michael@0: var visited = new Array(1024); michael@0: var worklist = [ michael@0: this.exit michael@0: ]; michael@0: function push(node) { michael@0: if (isConstant(node)) { michael@0: return; michael@0: } michael@0: true; michael@0: worklist.push(node); michael@0: } michael@0: var node; michael@0: while (node = worklist.pop()) { michael@0: if (visited[node.id]) { michael@0: continue; michael@0: } michael@0: visited[node.id] = 1; michael@0: visitor && visitor(node); michael@0: worklist.push(node); michael@0: node.visitInputs(push); michael@0: } michael@0: }; michael@0: constructor.prototype.forEach = function forEach(visitor, postOrder) { michael@0: var search = postOrder ? postOrderDepthFirstSearch : preOrderDepthFirstSearch; michael@0: search(this.exit, function (node, v) { michael@0: node.visitInputsNoConstants(v); michael@0: }, visitor); michael@0: }; michael@0: constructor.prototype.traceMetrics = function (writer) { michael@0: var counter = new metrics.Counter(true); michael@0: preOrderDepthFirstSearch(this.exit, function (node, visitor) { michael@0: node.visitInputsNoConstants(visitor); michael@0: }, function (node) { michael@0: counter.count(node.nodeName); michael@0: }); michael@0: counter.trace(writer); michael@0: }; michael@0: constructor.prototype.trace = function (writer) { michael@0: var nodes = []; michael@0: var visited = {}; michael@0: function colorOf(node) { michael@0: if (node instanceof Control) { michael@0: return 'yellow'; michael@0: } else if (node instanceof Phi) { michael@0: return 'purple'; michael@0: } else if (node instanceof Value) { michael@0: return 'green'; michael@0: } michael@0: return 'white'; michael@0: } michael@0: var blocks = []; michael@0: function followProjection(node) { michael@0: return node instanceof Projection ? node.project() : node; michael@0: } michael@0: function next(node) { michael@0: node = followProjection(node); michael@0: if (!visited[node.id]) { michael@0: visited[node.id] = true; michael@0: if (node.block) { michael@0: blocks.push(node.block); michael@0: } michael@0: nodes.push(node); michael@0: node.visitInputsNoConstants(next); michael@0: } michael@0: } michael@0: next(this.exit); michael@0: writer.writeLn(''); michael@0: writer.enter('digraph DFG {'); michael@0: writer.writeLn('graph [bgcolor = gray10];'); michael@0: writer.writeLn('edge [color = white];'); michael@0: writer.writeLn('node [shape = box, fontname = Consolas, fontsize = 11, color = white, fontcolor = white];'); michael@0: writer.writeLn('rankdir = BT;'); michael@0: function writeNode(node) { michael@0: writer.writeLn('N' + node.id + ' [label = "' + node.toString() + '", color = "' + colorOf(node) + '"];'); michael@0: } michael@0: function defineNode(node) { michael@0: writer.writeLn('N' + node.id + ';'); michael@0: } michael@0: blocks.forEach(function (block) { michael@0: writer.enter('subgraph cluster' + block.nodes[0].id + ' { bgcolor = gray20;'); michael@0: block.visitNodes(function (node) { michael@0: defineNode(followProjection(node)); michael@0: }); michael@0: writer.leave('}'); michael@0: }); michael@0: nodes.forEach(writeNode); michael@0: nodes.forEach(function (node) { michael@0: node.visitInputsNoConstants(function (input) { michael@0: input = followProjection(input); michael@0: writer.writeLn('N' + node.id + ' -> ' + 'N' + input.id + ' [color=' + colorOf(input) + '];'); michael@0: }); michael@0: }); michael@0: writer.leave('}'); michael@0: writer.writeLn(''); michael@0: }; michael@0: return constructor; michael@0: }(); michael@0: var CFG = function () { michael@0: function constructor() { michael@0: this.nextBlockID = 0; michael@0: this.blocks = []; michael@0: this.exit; michael@0: this.root; michael@0: } michael@0: constructor.fromDFG = function fromDFG(dfg) { michael@0: var cfg = new CFG(); michael@0: true; michael@0: cfg.dfg = dfg; michael@0: var visited = []; michael@0: function buildEnd(end) { michael@0: if (end instanceof Projection) { michael@0: end = end.project(); michael@0: } michael@0: true; michael@0: if (visited[end.id]) { michael@0: return; michael@0: } michael@0: visited[end.id] = true; michael@0: var start = end.control; michael@0: if (!(start instanceof Region)) { michael@0: start = end.control = new Region(start); michael@0: } michael@0: var block = start.block = cfg.buildBlock(start, end); michael@0: if (start instanceof Start) { michael@0: cfg.root = block; michael@0: } michael@0: for (var i = 0; i < start.predecessors.length; i++) { michael@0: var c = start.predecessors[i]; michael@0: var d; michael@0: var trueProjection = false; michael@0: if (c instanceof Projection) { michael@0: d = c.project(); michael@0: trueProjection = c.type === Projection.Type.TRUE; michael@0: } else { michael@0: d = c; michael@0: } michael@0: if (d instanceof Region) { michael@0: d = new Jump(c); michael@0: d = new Projection(d, Projection.Type.TRUE); michael@0: start.predecessors[i] = d; michael@0: d = d.project(); michael@0: trueProjection = true; michael@0: } michael@0: buildEnd(d); michael@0: var controlBlock = d.control.block; michael@0: if (d instanceof Switch) { michael@0: true; michael@0: controlBlock.pushSuccessorAt(block, c.selector.value, true); michael@0: } else if (trueProjection && controlBlock.successors.length > 0) { michael@0: controlBlock.pushSuccessor(block, true); michael@0: controlBlock.hasFlippedSuccessors = true; michael@0: } else { michael@0: controlBlock.pushSuccessor(block, true); michael@0: } michael@0: } michael@0: } michael@0: buildEnd(dfg.exit); michael@0: cfg.splitCriticalEdges(); michael@0: cfg.exit = dfg.exit.control.block; michael@0: cfg.computeDominators(true); michael@0: return cfg; michael@0: }; michael@0: constructor.prototype.buildRootAndExit = function buildRootAndExit() { michael@0: true; michael@0: if (this.blocks[0].predecessors.length > 0) { michael@0: this.root = new Block(this.nextBlockID++); michael@0: this.blocks.push(this.root); michael@0: this.root.pushSuccessor(this.blocks[0], true); michael@0: } else { michael@0: this.root = this.blocks[0]; michael@0: } michael@0: var exitBlocks = []; michael@0: for (var i = 0; i < this.blocks.length; i++) { michael@0: var block = this.blocks[i]; michael@0: if (block.successors.length === 0) { michael@0: exitBlocks.push(block); michael@0: } michael@0: } michael@0: if (exitBlocks.length === 0) { michael@0: unexpected('Must have an exit block.'); michael@0: } else if (exitBlocks.length === 1 && exitBlocks[0] !== this.root) { michael@0: this.exit = exitBlocks[0]; michael@0: } else { michael@0: this.exit = new Block(this.nextBlockID++); michael@0: this.blocks.push(this.exit); michael@0: for (var i = 0; i < exitBlocks.length; i++) { michael@0: exitBlocks[i].pushSuccessor(this.exit, true); michael@0: } michael@0: } michael@0: true; michael@0: true; michael@0: }; michael@0: constructor.prototype.fromString = function (list, rootName) { michael@0: var cfg = this; michael@0: var names = cfg.blockNames || (cfg.blockNames = {}); michael@0: var blocks = cfg.blocks; michael@0: var sets = list.replace(/\ /g, '').split(','); michael@0: sets.forEach(function (set) { michael@0: var edgeList = set.split('->'); michael@0: var last = null; michael@0: for (var i = 0; i < edgeList.length; i++) { michael@0: var next = edgeList[i]; michael@0: if (last) { michael@0: buildEdge(last, next); michael@0: } else { michael@0: buildBlock(next); michael@0: } michael@0: last = next; michael@0: } michael@0: }); michael@0: function buildBlock(name) { michael@0: var block = names[name]; michael@0: if (block) { michael@0: return block; michael@0: } michael@0: names[name] = block = new Block(cfg.nextBlockID++); michael@0: block.name = name; michael@0: blocks.push(block); michael@0: return block; michael@0: } michael@0: function buildEdge(from, to) { michael@0: buildBlock(from).pushSuccessor(buildBlock(to), true); michael@0: } michael@0: true; michael@0: this.root = names[rootName]; michael@0: }; michael@0: constructor.prototype.buildBlock = function (start, end) { michael@0: var block = new Block(this.nextBlockID++, start, end); michael@0: this.blocks.push(block); michael@0: return block; michael@0: }; michael@0: constructor.prototype.createBlockSet = function () { michael@0: if (!this.setConstructor) { michael@0: this.setConstructor = BitSetFunctor(this.blocks.length); michael@0: } michael@0: return new this.setConstructor(); michael@0: }; michael@0: constructor.prototype.computeReversePostOrder = function computeReversePostOrder() { michael@0: if (this.order) { michael@0: return this.order; michael@0: } michael@0: var order = this.order = []; michael@0: this.depthFirstSearch(null, order.push.bind(order)); michael@0: order.reverse(); michael@0: for (var i = 0; i < order.length; i++) { michael@0: order[i].rpo = i; michael@0: } michael@0: return order; michael@0: }; michael@0: constructor.prototype.depthFirstSearch = function depthFirstSearch(preFn, postFn) { michael@0: var visited = this.createBlockSet(); michael@0: function visit(node) { michael@0: visited.set(node.id); michael@0: if (preFn) michael@0: preFn(node); michael@0: var successors = node.successors; michael@0: for (var i = 0, j = successors.length; i < j; i++) { michael@0: var s = successors[i]; michael@0: if (!visited.get(s.id)) { michael@0: visit(s); michael@0: } michael@0: } michael@0: if (postFn) michael@0: postFn(node); michael@0: } michael@0: visit(this.root); michael@0: }; michael@0: constructor.prototype.computeDominators = function (apply) { michael@0: true; michael@0: var dom = new Int32Array(this.blocks.length); michael@0: for (var i = 0; i < dom.length; i++) { michael@0: dom[i] = -1; michael@0: } michael@0: var map = this.createBlockSet(); michael@0: function computeCommonDominator(a, b) { michael@0: map.clearAll(); michael@0: while (a >= 0) { michael@0: map.set(a); michael@0: a = dom[a]; michael@0: } michael@0: while (b >= 0 && !map.get(b)) { michael@0: b = dom[b]; michael@0: } michael@0: return b; michael@0: } michael@0: function computeDominator(blockID, parentID) { michael@0: if (dom[blockID] < 0) { michael@0: dom[blockID] = parentID; michael@0: } else { michael@0: dom[blockID] = computeCommonDominator(dom[blockID], parentID); michael@0: } michael@0: } michael@0: this.depthFirstSearch(function visit(block) { michael@0: var s = block.successors; michael@0: for (var i = 0, j = s.length; i < j; i++) { michael@0: computeDominator(s[i].id, block.id); michael@0: } michael@0: }); michael@0: if (apply) { michael@0: for (var i = 0, j = this.blocks.length; i < j; i++) { michael@0: this.blocks[i].dominator = this.blocks[dom[i]]; michael@0: } michael@0: function computeDominatorDepth(block) { michael@0: var dominatorDepth; michael@0: if (block.dominatorDepth !== undefined) { michael@0: return block.dominatorDepth; michael@0: } else if (!block.dominator) { michael@0: dominatorDepth = 0; michael@0: } else { michael@0: dominatorDepth = computeDominatorDepth(block.dominator) + 1; michael@0: } michael@0: return block.dominatorDepth = dominatorDepth; michael@0: } michael@0: for (var i = 0, j = this.blocks.length; i < j; i++) { michael@0: computeDominatorDepth(this.blocks[i]); michael@0: } michael@0: } michael@0: return dom; michael@0: }; michael@0: constructor.prototype.computeLoops = function computeLoops() { michael@0: var active = this.createBlockSet(); michael@0: var visited = this.createBlockSet(); michael@0: var nextLoop = 0; michael@0: function makeLoopHeader(block) { michael@0: if (!block.isLoopHeader) { michael@0: block.isLoopHeader = true; michael@0: block.loops = 1 << nextLoop; michael@0: nextLoop += 1; michael@0: } michael@0: } michael@0: function visit(block) { michael@0: if (visited.get(block.id)) { michael@0: if (active.get(block.id)) { michael@0: makeLoopHeader(block); michael@0: } michael@0: return block.loops; michael@0: } michael@0: visited.set(block.id); michael@0: active.set(block.id); michael@0: var loops = 0; michael@0: for (var i = 0, j = block.successors.length; i < j; i++) { michael@0: loops |= visit(block.successors[i]); michael@0: } michael@0: if (block.isLoopHeader) { michael@0: loops &= ~block.loops; michael@0: } michael@0: block.loops = loops; michael@0: active.clear(block.id); michael@0: return loops; michael@0: } michael@0: var loop = visit(this.root); michael@0: }; michael@0: function followProjection(node) { michael@0: return node instanceof Projection ? node.project() : node; michael@0: } michael@0: var Uses = function () { michael@0: function constructor() { michael@0: this.entries = []; michael@0: } michael@0: constructor.prototype.addUse = function addUse(def, use) { michael@0: var entry = this.entries[def.id]; michael@0: if (!entry) { michael@0: entry = this.entries[def.id] = { michael@0: def: def, michael@0: uses: [] michael@0: }; michael@0: } michael@0: entry.uses.pushUnique(use); michael@0: }; michael@0: constructor.prototype.trace = function (writer) { michael@0: writer.enter('> Uses'); michael@0: this.entries.forEach(function (entry) { michael@0: writer.writeLn(entry.def.id + ' -> [' + entry.uses.map(toID).join(', ') + '] ' + entry.def); michael@0: }); michael@0: writer.leave('<'); michael@0: }; michael@0: constructor.prototype.replace = function (def, value) { michael@0: var entry = this.entries[def.id]; michael@0: if (entry.uses.length === 0) { michael@0: return false; michael@0: } michael@0: var count = 0; michael@0: entry.uses.forEach(function (use) { michael@0: count += use.replaceInput(def, value); michael@0: }); michael@0: true; michael@0: entry.uses = []; michael@0: return true; michael@0: }; michael@0: function updateUses(def, value) { michael@0: debug && writer.writeLn('Update ' + def + ' with ' + value); michael@0: var entry = useEntries[def.id]; michael@0: if (entry.uses.length === 0) { michael@0: return false; michael@0: } michael@0: debug && writer.writeLn('Replacing: ' + def.id + ' in [' + entry.uses.map(toID).join(', ') + '] with ' + value.id); michael@0: var count = 0; michael@0: entry.uses.forEach(function (use) { michael@0: count += use.replaceInput(def, value); michael@0: }); michael@0: true; michael@0: entry.uses = []; michael@0: return true; michael@0: } michael@0: return constructor; michael@0: }(); michael@0: constructor.prototype.computeUses = function computeUses() { michael@0: Timer.start('computeUses'); michael@0: var writer = debug && new IndentingWriter(); michael@0: debug && writer.enter('> Compute Uses'); michael@0: var dfg = this.dfg; michael@0: var uses = new Uses(); michael@0: dfg.forEachInPreOrderDepthFirstSearch(function (use) { michael@0: use.visitInputs(function (def) { michael@0: uses.addUse(def, use); michael@0: }); michael@0: }); michael@0: if (debug) { michael@0: writer.enter('> Uses'); michael@0: uses.entries.forEach(function (entry) { michael@0: writer.writeLn(entry.def.id + ' -> [' + entry.uses.map(toID).join(', ') + '] ' + entry.def); michael@0: }); michael@0: writer.leave('<'); michael@0: writer.leave('<'); michael@0: } michael@0: Timer.stop(); michael@0: return uses; michael@0: }; michael@0: constructor.prototype.verify = function verify() { michael@0: var writer = debug && new IndentingWriter(); michael@0: debug && writer.enter('> Verify'); michael@0: var order = this.computeReversePostOrder(); michael@0: order.forEach(function (block) { michael@0: if (block.phis) { michael@0: block.phis.forEach(function (phi) { michael@0: true; michael@0: true; michael@0: }); michael@0: } michael@0: }); michael@0: debug && writer.leave('<'); michael@0: }; michael@0: constructor.prototype.optimizePhis = function optimizePhis() { michael@0: var writer = debug && new IndentingWriter(); michael@0: debug && writer.enter('> Optimize Phis'); michael@0: var phis = []; michael@0: var useEntries = this.computeUses().entries; michael@0: useEntries.forEach(function (entry) { michael@0: if (isPhi(entry.def)) { michael@0: phis.push(entry.def); michael@0: } michael@0: }); michael@0: debug && writer.writeLn('Trying to optimize ' + phis.length + ' phis.'); michael@0: function updateUses(def, value) { michael@0: debug && writer.writeLn('Update ' + def + ' with ' + value); michael@0: var entry = useEntries[def.id]; michael@0: if (entry.uses.length === 0) { michael@0: return false; michael@0: } michael@0: debug && writer.writeLn('Replacing: ' + def.id + ' in [' + entry.uses.map(toID).join(', ') + '] with ' + value.id); michael@0: var count = 0; michael@0: var entryUses = entry.uses; michael@0: for (var i = 0, j = entryUses.length; i < j; i++) { michael@0: count += entryUses[i].replaceInput(def, value); michael@0: } michael@0: true; michael@0: entry.uses = []; michael@0: return true; michael@0: } michael@0: function simplify(phi, args) { michael@0: args = args.unique(); michael@0: if (args.length === 1) { michael@0: return args[0]; michael@0: } else { michael@0: if (args.length === 2) { michael@0: if (args[0] === phi) { michael@0: return args[1]; michael@0: } else if (args[1] === phi) { michael@0: return args[0]; michael@0: } michael@0: return phi; michael@0: } michael@0: } michael@0: return phi; michael@0: } michael@0: var count = 0; michael@0: var iterations = 0; michael@0: var changed = true; michael@0: while (changed) { michael@0: iterations++; michael@0: changed = false; michael@0: phis.forEach(function (phi) { michael@0: var value = simplify(phi, phi.args); michael@0: if (value !== phi) { michael@0: if (updateUses(phi, value)) { michael@0: changed = true; michael@0: count++; michael@0: } michael@0: } michael@0: }); michael@0: } michael@0: if (debug) { michael@0: writer.writeLn('Simplified ' + count + ' phis, in ' + iterations + ' iterations.'); michael@0: writer.leave('<'); michael@0: } michael@0: }; michael@0: constructor.prototype.splitCriticalEdges = function splitCriticalEdges() { michael@0: var writer = debug && new IndentingWriter(); michael@0: var blocks = this.blocks; michael@0: var criticalEdges = []; michael@0: debug && writer.enter('> Splitting Critical Edges'); michael@0: for (var i = 0; i < blocks.length; i++) { michael@0: var successors = blocks[i].successors; michael@0: if (successors.length > 1) { michael@0: for (var j = 0; j < successors.length; j++) { michael@0: if (successors[j].predecessors.length > 1) { michael@0: criticalEdges.push({ michael@0: from: blocks[i], michael@0: to: successors[j] michael@0: }); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var criticalEdgeCount = criticalEdges.length; michael@0: if (criticalEdgeCount && debug) { michael@0: writer.writeLn('Splitting: ' + criticalEdgeCount); michael@0: this.trace(writer); michael@0: } michael@0: var edge; michael@0: while (edge = criticalEdges.pop()) { michael@0: var fromIndex = edge.from.successors.indexOf(edge.to); michael@0: var toIndex = edge.to.predecessors.indexOf(edge.from); michael@0: true; michael@0: debug && writer.writeLn('Splitting critical edge: ' + edge.from + ' -> ' + edge.to); michael@0: var toBlock = edge.to; michael@0: var toRegion = toBlock.region; michael@0: var control = toRegion.predecessors[toIndex]; michael@0: var region = new Region(control); michael@0: var jump = new Jump(region); michael@0: var block = this.buildBlock(region, jump); michael@0: toRegion.predecessors[toIndex] = new Projection(jump, Projection.Type.TRUE); michael@0: var fromBlock = edge.from; michael@0: fromBlock.successors[fromIndex] = block; michael@0: block.pushPredecessor(fromBlock); michael@0: block.pushSuccessor(toBlock); michael@0: toBlock.predecessors[toIndex] = block; michael@0: } michael@0: if (criticalEdgeCount && debug) { michael@0: this.trace(writer); michael@0: } michael@0: if (criticalEdgeCount && !true) { michael@0: true; michael@0: } michael@0: debug && writer.leave('<'); michael@0: return criticalEdgeCount; michael@0: }; michael@0: constructor.prototype.allocateVariables = function allocateVariables() { michael@0: var writer = debug && new IndentingWriter(); michael@0: debug && writer.enter('> Allocating Virtual Registers'); michael@0: var order = this.computeReversePostOrder(); michael@0: function allocate(node) { michael@0: if (isProjection(node, Projection.Type.STORE)) { michael@0: return; michael@0: } michael@0: if (node instanceof SetProperty) { michael@0: return; michael@0: } michael@0: if (node instanceof Value) { michael@0: node.variable = new Variable('v' + node.id); michael@0: debug && writer.writeLn('Allocated: ' + node.variable + ' to ' + node); michael@0: } michael@0: } michael@0: order.forEach(function (block) { michael@0: block.nodes.forEach(allocate); michael@0: if (block.phis) { michael@0: block.phis.forEach(allocate); michael@0: } michael@0: }); michael@0: var blockMoves = []; michael@0: for (var i = 0; i < order.length; i++) { michael@0: var block = order[i]; michael@0: var phis = block.phis; michael@0: var predecessors = block.predecessors; michael@0: if (phis) { michael@0: for (var j = 0; j < phis.length; j++) { michael@0: var phi = phis[j]; michael@0: debug && writer.writeLn('Emitting moves for: ' + phi); michael@0: var arguments = phi.args; michael@0: true; michael@0: for (var k = 0; k < predecessors.length; k++) { michael@0: var predecessor = predecessors[k]; michael@0: var argument = arguments[k]; michael@0: if (argument.abstract || isProjection(argument, Projection.Type.STORE)) { michael@0: continue; michael@0: } michael@0: var moves = blockMoves[predecessor.id] || (blockMoves[predecessor.id] = []); michael@0: argument = argument.variable || argument; michael@0: if (phi.variable !== argument) { michael@0: moves.push(new Move(phi.variable, argument)); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var blocks = this.blocks; michael@0: blockMoves.forEach(function (moves, blockID) { michael@0: var block = blocks[blockID]; michael@0: var temporary = 0; michael@0: debug && writer.writeLn(block + ' Moves: ' + moves); michael@0: while (moves.length) { michael@0: for (var i = 0; i < moves.length; i++) { michael@0: var move = moves[i]; michael@0: for (var j = 0; j < moves.length; j++) { michael@0: if (i === j) { michael@0: continue; michael@0: } michael@0: if (moves[j].from === move.to) { michael@0: move = null; michael@0: break; michael@0: } michael@0: } michael@0: if (move) { michael@0: moves.splice(i--, 1); michael@0: block.append(move); michael@0: } michael@0: } michael@0: if (moves.length) { michael@0: debug && writer.writeLn('Breaking Cycle'); michael@0: var move = moves[0]; michael@0: var temp = new Variable('t' + temporary++); michael@0: blocks[blockID].append(new Move(temp, move.to)); michael@0: for (var i = 1; i < moves.length; i++) { michael@0: if (moves[i].from === move.to) { michael@0: moves[i].from = temp; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }); michael@0: debug && writer.leave('<'); michael@0: }; michael@0: constructor.prototype.scheduleEarly = function scheduleEarly() { michael@0: var debugScheduler = false; michael@0: var writer = debugScheduler && new IndentingWriter(); michael@0: debugScheduler && writer.enter('> Schedule Early'); michael@0: var cfg = this; michael@0: var dfg = this.dfg; michael@0: var scheduled = []; michael@0: var roots = []; michael@0: dfg.forEachInPreOrderDepthFirstSearch(function (node) { michael@0: if (node instanceof Region || node instanceof Jump) { michael@0: return; michael@0: } michael@0: if (node.control) { michael@0: roots.push(node); michael@0: } michael@0: if (isPhi(node)) { michael@0: node.args.forEach(function (input) { michael@0: if (shouldFloat(input)) { michael@0: input.mustNotFloat = true; michael@0: } michael@0: }); michael@0: } michael@0: }, true); michael@0: if (debugScheduler) { michael@0: roots.forEach(function (node) { michael@0: print('Root: ' + node); michael@0: }); michael@0: } michael@0: for (var i = 0; i < roots.length; i++) { michael@0: var root = roots[i]; michael@0: if (root instanceof Phi) { michael@0: var block = root.control.block; michael@0: (block.phis || (block.phis = [])).push(root); michael@0: } michael@0: if (root.control) { michael@0: schedule(root); michael@0: } michael@0: } michael@0: function isScheduled(node) { michael@0: return scheduled[node.id]; michael@0: } michael@0: function shouldFloat(node) { michael@0: if (node.mustNotFloat || node.shouldNotFloat) { michael@0: return false; michael@0: } michael@0: if (node.mustFloat || node.shouldFloat) { michael@0: return true; michael@0: } michael@0: if (node instanceof Parameter || node instanceof This || node instanceof Arguments) { michael@0: return true; michael@0: } michael@0: return node instanceof Binary || node instanceof Unary || node instanceof Parameter; michael@0: } michael@0: function append(node) { michael@0: true; michael@0: scheduled[node.id] = true; michael@0: true; michael@0: if (shouldFloat(node)) { michael@0: } else { michael@0: node.control.block.append(node); michael@0: } michael@0: } michael@0: function scheduleIn(node, region) { michael@0: true; michael@0: true; michael@0: true; michael@0: debugScheduler && writer.writeLn('Scheduled: ' + node + ' in ' + region); michael@0: node.control = region; michael@0: append(node); michael@0: } michael@0: function schedule(node) { michael@0: debugScheduler && writer.enter('> Schedule: ' + node); michael@0: var inputs = []; michael@0: node.visitInputs(function (input) { michael@0: if (isConstant(input)) { michael@0: { michael@0: return; michael@0: } michael@0: } michael@0: if (isValue(input)) { michael@0: inputs.push(followProjection(input)); michael@0: } michael@0: }); michael@0: debugScheduler && writer.writeLn('Inputs: [' + inputs.map(toID) + '], length: ' + inputs.length); michael@0: for (var i = 0; i < inputs.length; i++) { michael@0: var input = inputs[i]; michael@0: if (isNotPhi(input) && !isScheduled(input)) { michael@0: schedule(input); michael@0: } michael@0: } michael@0: if (node.control) { michael@0: if (node instanceof End || node instanceof Phi || node instanceof Start || isScheduled(node)) { michael@0: } else { michael@0: append(node); michael@0: } michael@0: } else { michael@0: if (inputs.length) { michael@0: var x = inputs[0].control; michael@0: for (var i = 1; i < inputs.length; i++) { michael@0: var y = inputs[i].control; michael@0: if (x.block.dominatorDepth < y.block.dominatorDepth) { michael@0: x = y; michael@0: } michael@0: } michael@0: scheduleIn(node, x); michael@0: } else { michael@0: scheduleIn(node, cfg.root.region); michael@0: } michael@0: } michael@0: debugScheduler && writer.leave('<'); michael@0: } michael@0: debugScheduler && writer.leave('<'); michael@0: roots.forEach(function (node) { michael@0: node = followProjection(node); michael@0: if (node === dfg.start || node instanceof Region) { michael@0: return; michael@0: } michael@0: true; michael@0: }); michael@0: }; michael@0: constructor.prototype.trace = function (writer) { michael@0: var visited = []; michael@0: var blocks = []; michael@0: function next(block) { michael@0: if (!visited[block.id]) { michael@0: visited[block.id] = true; michael@0: blocks.push(block); michael@0: block.visitSuccessors(next); michael@0: } michael@0: } michael@0: var root = this.root; michael@0: var exit = this.exit; michael@0: next(root); michael@0: function colorOf(block) { michael@0: return 'black'; michael@0: } michael@0: function styleOf(block) { michael@0: return 'filled'; michael@0: } michael@0: function shapeOf(block) { michael@0: true; michael@0: if (block === root) { michael@0: return 'house'; michael@0: } else if (block === exit) { michael@0: return 'invhouse'; michael@0: } michael@0: return 'box'; michael@0: } michael@0: writer.writeLn(''); michael@0: writer.enter('digraph CFG {'); michael@0: writer.writeLn('graph [bgcolor = gray10];'); michael@0: writer.writeLn('edge [fontname = Consolas, fontsize = 11, color = white, fontcolor = white];'); michael@0: writer.writeLn('node [shape = box, fontname = Consolas, fontsize = 11, color = white, fontcolor = white, style = filled];'); michael@0: writer.writeLn('rankdir = TB;'); michael@0: blocks.forEach(function (block) { michael@0: var loopInfo = ''; michael@0: var blockInfo = ''; michael@0: var intervalInfo = ''; michael@0: if (block.loops !== undefined) { michael@0: } michael@0: if (block.name !== undefined) { michael@0: blockInfo += ' ' + block.name; michael@0: } michael@0: if (block.rpo !== undefined) { michael@0: blockInfo += ' O: ' + block.rpo; michael@0: } michael@0: writer.writeLn('B' + block.id + ' [label = "B' + block.id + blockInfo + loopInfo + '", fillcolor = "' + colorOf(block) + '", shape=' + shapeOf(block) + ', style=' + styleOf(block) + '];'); michael@0: }); michael@0: blocks.forEach(function (block) { michael@0: block.visitSuccessors(function (successor) { michael@0: writer.writeLn('B' + block.id + ' -> ' + 'B' + successor.id); michael@0: }); michael@0: if (block.dominator) { michael@0: writer.writeLn('B' + block.id + ' -> ' + 'B' + block.dominator.id + ' [color = orange];'); michael@0: } michael@0: if (block.follow) { michael@0: writer.writeLn('B' + block.id + ' -> ' + 'B' + block.follow.id + ' [color = purple];'); michael@0: } michael@0: }); michael@0: writer.leave('}'); michael@0: writer.writeLn(''); michael@0: }; michael@0: return constructor; michael@0: }(); michael@0: var PeepholeOptimizer = function () { michael@0: function constructor() { michael@0: } michael@0: function foldUnary(node, truthy) { michael@0: true; michael@0: if (isConstant(node.argument)) { michael@0: return new Constant(node.operator.evaluate(node.argument.value)); michael@0: } michael@0: if (truthy) { michael@0: var argument = fold(node.argument, true); michael@0: if (node.operator === Operator.TRUE) { michael@0: return argument; michael@0: } michael@0: if (argument instanceof Unary) { michael@0: if (node.operator === Operator.FALSE && argument.operator === Operator.FALSE) { michael@0: return argument.argument; michael@0: } michael@0: } else { michael@0: return new Unary(node.operator, argument); michael@0: } michael@0: } michael@0: return node; michael@0: } michael@0: function foldBinary(node, truthy) { michael@0: true; michael@0: if (isConstant(node.left) && isConstant(node.right)) { michael@0: return new Constant(node.operator.evaluate(node.left.value, node.right.value)); michael@0: } michael@0: return node; michael@0: } michael@0: function fold(node, truthy) { michael@0: if (node instanceof Unary) { michael@0: return foldUnary(node, truthy); michael@0: } else if (node instanceof Binary) { michael@0: return foldBinary(node, truthy); michael@0: } michael@0: return node; michael@0: } michael@0: constructor.prototype.tryFold = fold; michael@0: return constructor; michael@0: }(); michael@0: exports.isConstant = isConstant; michael@0: exports.Block = Block; michael@0: exports.Node = Node; michael@0: exports.Start = Start; michael@0: exports.Null = Null; michael@0: exports.Undefined = Undefined; michael@0: exports.This = This; michael@0: exports.Throw = Throw; michael@0: exports.Arguments = Arguments; michael@0: exports.ASGlobal = ASGlobal; michael@0: exports.Projection = Projection; michael@0: exports.Region = Region; michael@0: exports.Latch = Latch; michael@0: exports.Binary = Binary; michael@0: exports.Unary = Unary; michael@0: exports.Constant = Constant; michael@0: exports.ASFindProperty = ASFindProperty; michael@0: exports.GlobalProperty = GlobalProperty; michael@0: exports.GetProperty = GetProperty; michael@0: exports.SetProperty = SetProperty; michael@0: exports.CallProperty = CallProperty; michael@0: exports.ASCallProperty = ASCallProperty; michael@0: exports.ASCallSuper = ASCallSuper; michael@0: exports.ASGetProperty = ASGetProperty; michael@0: exports.ASGetSuper = ASGetSuper; michael@0: exports.ASHasProperty = ASHasProperty; michael@0: exports.ASDeleteProperty = ASDeleteProperty; michael@0: exports.ASGetDescendants = ASGetDescendants; michael@0: exports.ASSetProperty = ASSetProperty; michael@0: exports.ASSetSuper = ASSetSuper; michael@0: exports.ASGetSlot = ASGetSlot; michael@0: exports.ASSetSlot = ASSetSlot; michael@0: exports.Call = Call; michael@0: exports.ASNew = ASNew; michael@0: exports.Phi = Phi; michael@0: exports.Stop = Stop; michael@0: exports.If = If; michael@0: exports.Switch = Switch; michael@0: exports.End = End; michael@0: exports.Jump = Jump; michael@0: exports.ASScope = ASScope; michael@0: exports.Operator = Operator; michael@0: exports.Variable = Variable; michael@0: exports.Move = Move; michael@0: exports.Copy = Copy; michael@0: exports.Parameter = Parameter; michael@0: exports.NewArray = NewArray; michael@0: exports.NewObject = NewObject; michael@0: exports.ASNewActivation = ASNewActivation; michael@0: exports.KeyValuePair = KeyValuePair; michael@0: exports.ASMultiname = ASMultiname; michael@0: exports.DFG = DFG; michael@0: exports.CFG = CFG; michael@0: exports.Flags = Flags; michael@0: exports.PeepholeOptimizer = PeepholeOptimizer; michael@0: }(typeof exports === 'undefined' ? IR = {} : exports)); michael@0: var c4Options = systemOptions.register(new OptionSet('C4 Options')); michael@0: var enableC4 = c4Options.register(new Option('c4', 'c4', 'boolean', false, 'Enable the C4 compiler.')); michael@0: var c4TraceLevel = c4Options.register(new Option('tc4', 'tc4', 'number', 0, 'Compiler Trace Level')); michael@0: var enableRegisterAllocator = c4Options.register(new Option('ra', 'ra', 'boolean', false, 'Enable register allocator.')); michael@0: var getPublicQualifiedName = Multiname.getPublicQualifiedName; michael@0: var createName = function createName(namespaces, name) { michael@0: if (isNumeric(name) || isObject(name)) { michael@0: return name; michael@0: } michael@0: return new Multiname(namespaces, name); michael@0: }; michael@0: (function (exports) { michael@0: var Node = IR.Node; michael@0: var Start = IR.Start; michael@0: var Null = IR.Null; michael@0: var Undefined = IR.Undefined; michael@0: var This = IR.This; michael@0: var Projection = IR.Projection; michael@0: var Region = IR.Region; michael@0: var Binary = IR.Binary; michael@0: var Unary = IR.Unary; michael@0: var Constant = IR.Constant; michael@0: var Call = IR.Call; michael@0: var Phi = IR.Phi; michael@0: var Stop = IR.Stop; michael@0: var Operator = IR.Operator; michael@0: var Parameter = IR.Parameter; michael@0: var NewArray = IR.NewArray; michael@0: var NewObject = IR.NewObject; michael@0: var KeyValuePair = IR.KeyValuePair; michael@0: var isConstant = IR.isConstant; michael@0: var DFG = IR.DFG; michael@0: var CFG = IR.CFG; michael@0: var writer = new IndentingWriter(); michael@0: var peepholeOptimizer = new IR.PeepholeOptimizer(); michael@0: var USE_TYPE_OF_DEFAULT_ARGUMENT_CHECKING = false; michael@0: var State = function () { michael@0: var nextID = 0; michael@0: function constructor(index) { michael@0: this.id = nextID += 1; michael@0: this.index = index; michael@0: this.local = []; michael@0: this.stack = []; michael@0: this.scope = []; michael@0: this.store = Undefined; michael@0: this.loads = []; michael@0: this.saved = Undefined; michael@0: } michael@0: constructor.prototype.clone = function clone(index) { michael@0: var s = new State(); michael@0: s.index = index !== undefined ? index : this.index; michael@0: s.local = this.local.slice(0); michael@0: s.stack = this.stack.slice(0); michael@0: s.scope = this.scope.slice(0); michael@0: s.loads = this.loads.slice(0); michael@0: s.saved = this.saved; michael@0: s.store = this.store; michael@0: return s; michael@0: }; michael@0: constructor.prototype.matches = function matches(other) { michael@0: return this.stack.length === other.stack.length && this.scope.length === other.scope.length && this.local.length === other.local.length; michael@0: }; michael@0: constructor.prototype.makeLoopPhis = function makeLoopPhis(control) { michael@0: var s = new State(); michael@0: true; michael@0: function makePhi(x) { michael@0: var phi = new Phi(control, x); michael@0: phi.isLoop = true; michael@0: return phi; michael@0: } michael@0: s.index = this.index; michael@0: s.local = this.local.map(makePhi); michael@0: s.stack = this.stack.map(makePhi); michael@0: s.scope = this.scope.map(makePhi); michael@0: s.loads = this.loads.slice(0); michael@0: s.saved = this.saved; michael@0: s.store = makePhi(this.store); michael@0: return s; michael@0: }; michael@0: constructor.prototype.optimize = function optimize() { michael@0: function optimize(x) { michael@0: if (x instanceof Phi && !x.isLoop) { michael@0: var args = x.args.unique(); michael@0: if (args.length === 1) { michael@0: x.seal(); michael@0: Counter.count('Builder: OptimizedPhi'); michael@0: return args[0]; michael@0: } michael@0: } michael@0: return x; michael@0: } michael@0: this.local = this.local.map(optimize); michael@0: this.stack = this.stack.map(optimize); michael@0: this.scope = this.scope.map(optimize); michael@0: this.saved = optimize(this.saved); michael@0: this.store = optimize(this.store); michael@0: }; michael@0: function mergeValue(control, a, b) { michael@0: var phi = a instanceof Phi && a.control === control ? a : new Phi(control, a); michael@0: phi.pushValue(b); michael@0: return phi; michael@0: } michael@0: function mergeValues(control, a, b) { michael@0: for (var i = 0; i < a.length; i++) { michael@0: a[i] = mergeValue(control, a[i], b[i]); michael@0: } michael@0: } michael@0: constructor.prototype.merge = function merge(control, other) { michael@0: true; michael@0: true; michael@0: mergeValues(control, this.local, other.local); michael@0: mergeValues(control, this.stack, other.stack); michael@0: mergeValues(control, this.scope, other.scope); michael@0: this.store = mergeValue(control, this.store, other.store); michael@0: this.store.abstract = true; michael@0: }; michael@0: constructor.prototype.trace = function trace(writer) { michael@0: writer.writeLn(this.toString()); michael@0: }; michael@0: function toBriefString(x) { michael@0: if (x instanceof Node) { michael@0: return x.toString(true); michael@0: } michael@0: return x; michael@0: } michael@0: constructor.prototype.toString = function () { michael@0: return '<' + String(this.id + ' @ ' + this.index).padRight(' ', 10) + (' M: ' + toBriefString(this.store)).padRight(' ', 14) + (' X: ' + toBriefString(this.saved)).padRight(' ', 14) + (' $: ' + this.scope.map(toBriefString).join(', ')).padRight(' ', 20) + (' L: ' + this.local.map(toBriefString).join(', ')).padRight(' ', 40) + (' S: ' + this.stack.map(toBriefString).join(', ')).padRight(' ', 60); michael@0: }; michael@0: return constructor; michael@0: }(); michael@0: function isNumericConstant(node) { michael@0: return node instanceof Constant && isNumeric(node.value); michael@0: } michael@0: function isStringConstant(node) { michael@0: return node instanceof Constant && isString(node.value); michael@0: } michael@0: function isMultinameConstant(node) { michael@0: return node instanceof Constant && node.value instanceof Multiname; michael@0: } michael@0: function hasNumericType(node) { michael@0: if (isNumericConstant(node)) { michael@0: return true; michael@0: } michael@0: return node.ty && node.ty.isNumeric(); michael@0: } michael@0: function typesAreEqual(a, b) { michael@0: if (hasNumericType(a) && hasNumericType(b) || hasStringType(a) && hasStringType(b)) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: function hasStringType(node) { michael@0: if (isStringConstant(node)) { michael@0: return true; michael@0: } michael@0: return node.ty && node.ty.isString(); michael@0: } michael@0: function constant(value) { michael@0: return new Constant(value); michael@0: } michael@0: function qualifiedNameConstant(name) { michael@0: return constant(Multiname.getQualifiedName(name)); michael@0: } michael@0: function getJSPropertyWithState(state, object, path) { michael@0: true; michael@0: var names = path.split('.'); michael@0: var node = object; michael@0: for (var i = 0; i < names.length; i++) { michael@0: node = new IR.GetProperty(null, state.store, node, constant(names[i])); michael@0: node.shouldFloat = true; michael@0: state.loads.push(node); michael@0: } michael@0: return node; michael@0: } michael@0: function globalProperty(name) { michael@0: var node = new IR.GlobalProperty(name); michael@0: node.mustFloat = true; michael@0: return node; michael@0: } michael@0: function warn(message) { michael@0: } michael@0: function unary(operator, argument) { michael@0: var node = new Unary(operator, argument); michael@0: if (peepholeOptimizer) { michael@0: node = peepholeOptimizer.tryFold(node); michael@0: } michael@0: return node; michael@0: } michael@0: function binary(operator, left, right) { michael@0: var node = new Binary(operator, left, right); michael@0: if (left.ty && left.ty !== Type.Any && left.ty === right.ty) { michael@0: if (operator === Operator.EQ) { michael@0: node.operator = Operator.SEQ; michael@0: } else if (operator === Operator.NE) { michael@0: node.operator = Operator.SNE; michael@0: } michael@0: } michael@0: if (peepholeOptimizer) { michael@0: node = peepholeOptimizer.tryFold(node); michael@0: } michael@0: return node; michael@0: } michael@0: function coerceInt(value) { michael@0: return binary(Operator.OR, value, constant(0)); michael@0: } michael@0: function coerceUint(value) { michael@0: return binary(Operator.URSH, value, constant(0)); michael@0: } michael@0: function coerceNumber(value) { michael@0: if (hasNumericType(value)) { michael@0: return value; michael@0: } michael@0: return unary(Operator.PLUS, value); michael@0: } michael@0: function coerceBoolean(value) { michael@0: return unary(Operator.FALSE, unary(Operator.FALSE, value)); michael@0: } michael@0: function shouldNotFloat(node) { michael@0: node.shouldNotFloat = true; michael@0: return node; michael@0: } michael@0: function shouldFloat(node) { michael@0: true; michael@0: node.shouldFloat = true; michael@0: return node; michael@0: } michael@0: function mustFloat(node) { michael@0: node.mustFloat = true; michael@0: return node; michael@0: } michael@0: function callPure(callee, object, args) { michael@0: return new Call(null, null, callee, object, args, IR.Flags.PRISTINE); michael@0: } michael@0: function callGlobalProperty(name, value) { michael@0: return callPure(globalProperty(name), null, [ michael@0: value michael@0: ]); michael@0: } michael@0: function convertString(value) { michael@0: if (isStringConstant(value)) { michael@0: return value; michael@0: } michael@0: return callPure(globalProperty('String'), null, [ michael@0: value michael@0: ]); michael@0: } michael@0: function coerceString(value) { michael@0: if (isStringConstant(value)) { michael@0: return value; michael@0: } michael@0: return callPure(globalProperty('asCoerceString'), null, [ michael@0: value michael@0: ]); michael@0: } michael@0: var coerceObject = callGlobalProperty.bind(null, 'asCoerceObject'); michael@0: var coercers = createEmptyObject(); michael@0: coercers[Multiname.Int] = coerceInt; michael@0: coercers[Multiname.Uint] = coerceUint; michael@0: coercers[Multiname.Number] = coerceNumber; michael@0: coercers[Multiname.String] = coerceString; michael@0: coercers[Multiname.Object] = coerceObject; michael@0: coercers[Multiname.Boolean] = coerceBoolean; michael@0: function getCoercerForType(multiname) { michael@0: true; michael@0: return coercers[Multiname.getQualifiedName(multiname)]; michael@0: } michael@0: var callableConstructors = createEmptyObject(); michael@0: callableConstructors[Multiname.Int] = coerceInt; michael@0: callableConstructors[Multiname.Uint] = coerceUint; michael@0: callableConstructors[Multiname.Number] = callGlobalProperty.bind(null, 'Number'); michael@0: callableConstructors[Multiname.String] = callGlobalProperty.bind(null, 'String'); michael@0: callableConstructors[Multiname.Object] = callGlobalProperty.bind(null, 'Object'); michael@0: callableConstructors[Multiname.Boolean] = callGlobalProperty.bind(null, 'Boolean'); michael@0: function getCallableConstructorForType(multiname) { michael@0: true; michael@0: return callableConstructors[Multiname.getQualifiedName(multiname)]; michael@0: } michael@0: var Builder = function () { michael@0: function builder(methodInfo, scope, hasDynamicScope) { michael@0: true; michael@0: this.abc = methodInfo.abc; michael@0: this.scope = scope; michael@0: this.methodInfo = methodInfo; michael@0: this.hasDynamicScope = hasDynamicScope; michael@0: } michael@0: builder.prototype.buildStart = function (start) { michael@0: var mi = this.methodInfo; michael@0: var state = start.entryState = new State(0); michael@0: state.local.push(new This(start)); michael@0: var parameterIndexOffset = this.hasDynamicScope ? 1 : 0; michael@0: var parameterCount = mi.parameters.length; michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: state.local.push(new Parameter(start, parameterIndexOffset + i, mi.parameters[i].name)); michael@0: } michael@0: for (var i = parameterCount; i < mi.localCount; i++) { michael@0: state.local.push(Undefined); michael@0: } michael@0: state.store = new Projection(start, Projection.Type.STORE); michael@0: if (this.hasDynamicScope) { michael@0: start.scope = new Parameter(start, 0, SAVED_SCOPE_NAME); michael@0: } else { michael@0: start.scope = new Constant(this.scope); michael@0: } michael@0: state.saved = new Projection(start, Projection.Type.SCOPE); michael@0: start.domain = new Constant(this.domain); michael@0: var args = new IR.Arguments(start); michael@0: if (mi.needsRest() || mi.needsArguments()) { michael@0: var offset = constant(parameterIndexOffset + (mi.needsRest() ? parameterCount : 0)); michael@0: state.local[parameterCount + 1] = new Call(start, state.store, globalProperty('sliceArguments'), null, [ michael@0: args, michael@0: offset michael@0: ], IR.Flags.PRISTINE); michael@0: } michael@0: var argumentsLength = getJSPropertyWithState(state, args, 'length'); michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: var parameter = mi.parameters[i]; michael@0: var index = i + 1; michael@0: var local = state.local[index]; michael@0: if (parameter.value !== undefined) { michael@0: var condition; michael@0: if (USE_TYPE_OF_DEFAULT_ARGUMENT_CHECKING) { michael@0: condition = new IR.Binary(Operator.SEQ, new IR.Unary(Operator.TYPE_OF, local), constant('undefined')); michael@0: } else { michael@0: condition = new IR.Binary(Operator.LT, argumentsLength, constant(parameterIndexOffset + i + 1)); michael@0: } michael@0: local = new IR.Latch(null, condition, constant(parameter.value), local); michael@0: } michael@0: if (parameter.type && !parameter.type.isAnyName()) { michael@0: var coercer = getCoercerForType(parameter.type); michael@0: if (coercer) { michael@0: local = coercer(local); michael@0: } else if (c4CoerceNonPrimitiveParameters) { michael@0: local = new Call(start, state.store, globalProperty('asCoerceByMultiname'), null, [ michael@0: constant(this.abc.applicationDomain), michael@0: constant(parameter.type), michael@0: local michael@0: ], true); michael@0: } michael@0: } michael@0: state.local[index] = local; michael@0: } michael@0: return start; michael@0: }; michael@0: builder.prototype.buildGraph = function buildGraph(callerRegion, callerState, inlineArguments) { michael@0: var analysis = this.methodInfo.analysis; michael@0: var blocks = analysis.blocks; michael@0: var bytecodes = analysis.bytecodes; michael@0: var methodInfo = this.methodInfo; michael@0: var ints = this.abc.constantPool.ints; michael@0: var uints = this.abc.constantPool.uints; michael@0: var doubles = this.abc.constantPool.doubles; michael@0: var strings = this.abc.constantPool.strings; michael@0: var methods = this.abc.methods; michael@0: var classes = this.abc.classes; michael@0: var multinames = this.abc.constantPool.multinames; michael@0: var domain = new Constant(this.abc.applicationDomain); michael@0: var traceBuilder = c4TraceLevel.value > 2; michael@0: var stopPoints = []; michael@0: for (var i = 0; i < blocks.length; i++) { michael@0: blocks[i].blockDominatorOrder = i; michael@0: } michael@0: var worklist = new Shumway.SortedList(function compare(a, b) { michael@0: return a.block.blockDominatorOrder - b.block.blockDominatorOrder; michael@0: }); michael@0: var start = new Start(null); michael@0: this.buildStart(start); michael@0: var createFunctionCallee = globalProperty('createFunction'); michael@0: worklist.push({ michael@0: region: start, michael@0: block: blocks[0] michael@0: }); michael@0: var next; michael@0: while (next = worklist.pop()) { michael@0: buildBlock(next.region, next.block, next.region.entryState.clone()).forEach(function (stop) { michael@0: var target = stop.target; michael@0: var region = target.region; michael@0: if (region) { michael@0: traceBuilder && writer.enter('Merging into region: ' + region + ' @ ' + target.position + ', block ' + target.bid + ' {'); michael@0: traceBuilder && writer.writeLn(' R ' + region.entryState); michael@0: traceBuilder && writer.writeLn('+ I ' + stop.state); michael@0: region.entryState.merge(region, stop.state); michael@0: region.predecessors.push(stop.control); michael@0: traceBuilder && writer.writeLn(' = ' + region.entryState); michael@0: traceBuilder && writer.leave('}'); michael@0: } else { michael@0: region = target.region = new Region(stop.control); michael@0: if (target.loop) { michael@0: traceBuilder && writer.writeLn('Adding PHIs to loop region.'); michael@0: } michael@0: region.entryState = target.loop ? stop.state.makeLoopPhis(region) : stop.state.clone(target.position); michael@0: traceBuilder && writer.writeLn('Adding new region: ' + region + ' @ ' + target.position + ' to worklist.'); michael@0: worklist.push({ michael@0: region: region, michael@0: block: target michael@0: }); michael@0: } michael@0: }); michael@0: traceBuilder && writer.enter('Worklist: {'); michael@0: worklist.forEach(function (item) { michael@0: traceBuilder && writer.writeLn(item.region + ' ' + item.block.bdo + ' ' + item.region.entryState); michael@0: }); michael@0: traceBuilder && writer.leave('}'); michael@0: } michael@0: traceBuilder && writer.writeLn('Done'); michael@0: function buildBlock(region, block, state) { michael@0: true; michael@0: state.optimize(); michael@0: var typeState = block.entryState; michael@0: if (typeState) { michael@0: traceBuilder && writer.writeLn('Type State: ' + typeState); michael@0: for (var i = 0; i < typeState.local.length; i++) { michael@0: var type = typeState.local[i]; michael@0: var local = state.local[i]; michael@0: if (local.ty) { michael@0: } else { michael@0: local.ty = type; michael@0: } michael@0: } michael@0: } michael@0: var local = state.local; michael@0: var stack = state.stack; michael@0: var scope = state.scope; michael@0: function savedScope() { michael@0: return state.saved; michael@0: } michael@0: function topScope(depth) { michael@0: if (depth !== undefined) { michael@0: if (depth < scope.length) { michael@0: return scope[scope.length - 1 - depth]; michael@0: } else if (depth === scope.length) { michael@0: return savedScope(); michael@0: } else { michael@0: var s = savedScope(); michael@0: var savedScopeDepth = depth - scope.length; michael@0: for (var i = 0; i < savedScopeDepth; i++) { michael@0: s = getJSProperty(s, 'parent'); michael@0: } michael@0: return s; michael@0: } michael@0: } michael@0: if (scope.length > 0) { michael@0: return scope.top(); michael@0: } michael@0: return savedScope(); michael@0: } michael@0: var object, receiver, index, callee, value, multiname, type, args, pristine, left, right, operator; michael@0: function push(x) { michael@0: true; michael@0: if (bc.ti) { michael@0: if (x.ty) { michael@0: } else { michael@0: x.ty = bc.ti.type; michael@0: } michael@0: } michael@0: stack.push(x); michael@0: } michael@0: function pop() { michael@0: return stack.pop(); michael@0: } michael@0: function popMany(count) { michael@0: return stack.popMany(count); michael@0: } michael@0: function pushLocal(index) { michael@0: push(local[index]); michael@0: } michael@0: function popLocal(index) { michael@0: local[index] = shouldNotFloat(pop()); michael@0: } michael@0: function buildMultiname(index) { michael@0: var multiname = multinames[index]; michael@0: var namespaces, name, flags = multiname.flags; michael@0: if (multiname.isRuntimeName()) { michael@0: name = stack.pop(); michael@0: } else { michael@0: name = constant(multiname.name); michael@0: } michael@0: if (multiname.isRuntimeNamespace()) { michael@0: namespaces = shouldFloat(new NewArray(region, [ michael@0: pop() michael@0: ])); michael@0: } else { michael@0: namespaces = constant(multiname.namespaces); michael@0: } michael@0: return new IR.ASMultiname(namespaces, name, flags); michael@0: } michael@0: function simplifyName(name) { michael@0: if (isMultinameConstant(name) && Multiname.isQName(name.value)) { michael@0: return constant(Multiname.getQualifiedName(name.value)); michael@0: } michael@0: return name; michael@0: } michael@0: function getGlobalScope(ti) { michael@0: if (ti && ti.object) { michael@0: return constant(ti.object); michael@0: } michael@0: return new IR.ASGlobal(null, savedScope()); michael@0: } michael@0: function findProperty(multiname, strict, ti) { michael@0: var slowPath = new IR.ASFindProperty(region, state.store, topScope(), multiname, domain, strict); michael@0: if (ti) { michael@0: if (ti.object) { michael@0: if (ti.object instanceof Global && !ti.object.isExecuting()) { michael@0: warn('Can\'t optimize findProperty ' + multiname + ', global object is not yet executed or executing.'); michael@0: return slowPath; michael@0: } michael@0: return constant(ti.object); michael@0: } else if (ti.scopeDepth !== undefined) { michael@0: return getScopeObject(topScope(ti.scopeDepth)); michael@0: } michael@0: } michael@0: warn('Can\'t optimize findProperty ' + multiname); michael@0: return slowPath; michael@0: } michael@0: function getJSProperty(object, path) { michael@0: return getJSPropertyWithState(state, object, path); michael@0: } michael@0: function coerce(multiname, value) { michael@0: if (false && isConstant(value)) { michael@0: return constant(asCoerceByMultiname(domain.value, multiname, value.value)); michael@0: } else { michael@0: var coercer = getCoercerForType(multiname); michael@0: if (coercer) { michael@0: return coercer(value); michael@0: } michael@0: } michael@0: if (c4CoerceNonPrimitive) { michael@0: return call(globalProperty('asCoerceByMultiname'), null, [ michael@0: domain, michael@0: constant(multiname), michael@0: value michael@0: ]); michael@0: } michael@0: return value; michael@0: } michael@0: function getScopeObject(scope) { michael@0: if (scope instanceof IR.ASScope) { michael@0: return scope.object; michael@0: } michael@0: return getJSProperty(scope, 'object'); michael@0: } michael@0: function store(node) { michael@0: state.store = new Projection(node, Projection.Type.STORE); michael@0: node.loads = state.loads.slice(0); michael@0: state.loads.length = 0; michael@0: return node; michael@0: } michael@0: function load(node) { michael@0: state.loads.push(node); michael@0: return node; michael@0: } michael@0: function resolveMultinameGlobally(multiname) { michael@0: var namespaces = multiname.namespaces; michael@0: var name = multiname.name; michael@0: if (!Shumway.AVM2.Runtime.globalMultinameAnalysis.value) { michael@0: return; michael@0: } michael@0: if (!isConstant(namespaces) || !isConstant(name) || multiname.isAttribute()) { michael@0: Counter.count('GlobalMultinameResolver: Cannot resolve runtime multiname or attribute.'); michael@0: return; michael@0: } michael@0: if (isNumeric(name.value) || !isString(name.value) || !name.value) { michael@0: Counter.count('GlobalMultinameResolver: Cannot resolve numeric or any names.'); michael@0: return false; michael@0: } michael@0: return GlobalMultinameResolver.resolveMultiname(new Multiname(namespaces.value, name.value, multiname.flags)); michael@0: } michael@0: function callSuper(scope, object, multiname, args, ti) { michael@0: if (ti && ti.trait && ti.trait.isMethod() && ti.baseClass) { michael@0: var qn = VM_OPEN_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); michael@0: var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); michael@0: return call(callee, object, args); michael@0: } michael@0: return store(new IR.ASCallSuper(region, state.store, object, multiname, args, IR.Flags.PRISTINE, scope)); michael@0: } michael@0: function getSuper(scope, object, multiname, ti) { michael@0: if (ti && ti.trait && ti.trait.isGetter() && ti.baseClass) { michael@0: var qn = VM_OPEN_GET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); michael@0: var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); michael@0: return call(callee, object, []); michael@0: } michael@0: return store(new IR.ASGetSuper(region, state.store, object, multiname, scope)); michael@0: } michael@0: function setSuper(scope, object, multiname, value, ti) { michael@0: if (ti && ti.trait && ti.trait.isSetter() && ti.baseClass) { michael@0: var qn = VM_OPEN_SET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name); michael@0: var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn); michael@0: return call(callee, object, [ michael@0: value michael@0: ]); michael@0: } michael@0: return store(new IR.ASSetSuper(region, state.store, object, multiname, value, scope)); michael@0: } michael@0: function constructSuper(scope, object, args, ti) { michael@0: if (ti) { michael@0: if (ti.noCallSuperNeeded) { michael@0: return; michael@0: } else if (ti.baseClass) { michael@0: var callee = getJSProperty(constant(ti.baseClass), 'instanceConstructorNoInitialize'); michael@0: call(callee, object, args); michael@0: return; michael@0: } michael@0: } michael@0: callee = getJSProperty(scope, 'object.baseClass.instanceConstructorNoInitialize'); michael@0: call(callee, object, args); michael@0: return; michael@0: } michael@0: function callProperty(object, multiname, args, isLex, ti) { michael@0: if (ti && ti.trait) { michael@0: if (ti.trait.isMethod()) { michael@0: var openQn; michael@0: if (ti.trait.holder instanceof InstanceInfo && ti.trait.holder.isInterface()) { michael@0: openQn = Multiname.getPublicQualifiedName(Multiname.getName(ti.trait.name)); michael@0: } else { michael@0: openQn = Multiname.getQualifiedName(ti.trait.name); michael@0: } michael@0: openQn = VM_OPEN_METHOD_PREFIX + openQn; michael@0: return store(new IR.CallProperty(region, state.store, object, constant(openQn), args, IR.Flags.PRISTINE)); michael@0: } else if (ti.trait.isClass()) { michael@0: var constructor = getCallableConstructorForType(ti.trait.name); michael@0: if (constructor) { michael@0: return constructor(args[0]); michael@0: } michael@0: var qn = Multiname.getQualifiedName(ti.trait.name); michael@0: return store(new IR.CallProperty(region, state.store, object, constant(qn), args, 0)); michael@0: } michael@0: } else if (ti && ti.propertyQName) { michael@0: return store(new IR.CallProperty(region, state.store, object, constant(ti.propertyQName), args, IR.Flags.PRISTINE)); michael@0: } michael@0: var qn = resolveMultinameGlobally(multiname); michael@0: if (qn) { michael@0: return store(new IR.ASCallProperty(region, state.store, object, constant(Multiname.getQualifiedName(qn)), args, IR.Flags.PRISTINE | IR.Flags.RESOLVED, isLex)); michael@0: } michael@0: return store(new IR.ASCallProperty(region, state.store, object, multiname, args, IR.Flags.PRISTINE, isLex)); michael@0: } michael@0: function getProperty(object, multiname, ti, getOpenMethod) { michael@0: true; michael@0: getOpenMethod = !(!getOpenMethod); michael@0: if (ti) { michael@0: if (ti.trait) { michael@0: if (ti.trait.isConst() && ti.trait.hasDefaultValue) { michael@0: return constant(ti.trait.value); michael@0: } michael@0: var get = new IR.GetProperty(region, state.store, object, qualifiedNameConstant(ti.trait.name)); michael@0: return ti.trait.isGetter() ? store(get) : load(get); michael@0: } michael@0: if (ti.propertyQName) { michael@0: return store(new IR.GetProperty(region, state.store, object, constant(ti.propertyQName))); michael@0: } else if (ti.isDirectlyReadable) { michael@0: return store(new IR.GetProperty(region, state.store, object, multiname.name)); michael@0: } else if (ti.isIndexedReadable) { michael@0: return store(new IR.ASGetProperty(region, state.store, object, multiname, IR.Flags.INDEXED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0))); michael@0: } michael@0: } michael@0: warn('Can\'t optimize getProperty ' + multiname); michael@0: var qn = resolveMultinameGlobally(multiname); michael@0: if (qn) { michael@0: return store(new IR.ASGetProperty(region, state.store, object, constant(Multiname.getQualifiedName(qn)), IR.Flags.RESOLVED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0))); michael@0: } michael@0: Counter.count('Compiler: Slow ASGetProperty'); michael@0: return store(new IR.ASGetProperty(region, state.store, object, multiname, getOpenMethod ? IR.Flagas.IS_METHOD : 0)); michael@0: } michael@0: function setProperty(object, multiname, value, ti) { michael@0: true; michael@0: if (ti) { michael@0: if (ti.trait) { michael@0: var coercer = ti.trait.typeName ? getCoercerForType(ti.trait.typeName) : null; michael@0: if (coercer) { michael@0: value = coercer(value); michael@0: } michael@0: store(new IR.SetProperty(region, state.store, object, qualifiedNameConstant(ti.trait.name), value)); michael@0: return; michael@0: } michael@0: if (ti.propertyQName) { michael@0: return store(new IR.SetProperty(region, state.store, object, constant(ti.propertyQName), value)); michael@0: } else if (ti.isDirectlyWriteable) { michael@0: return store(new IR.SetProperty(region, state.store, object, multiname.name, value)); michael@0: } else if (ti.isIndexedWriteable) { michael@0: return store(new IR.ASSetProperty(region, state.store, object, multiname, value, IR.Flags.INDEXED)); michael@0: } michael@0: } michael@0: warn('Can\'t optimize setProperty ' + multiname); michael@0: var qn = resolveMultinameGlobally(multiname); michael@0: if (qn) { michael@0: } michael@0: return store(new IR.ASSetProperty(region, state.store, object, multiname, value, 0)); michael@0: } michael@0: function getDescendants(object, name, ti) { michael@0: name = simplifyName(name); michael@0: return new IR.ASGetDescendants(region, state.store, object, name); michael@0: } michael@0: function getSlot(object, index, ti) { michael@0: if (ti) { michael@0: var trait = ti.trait; michael@0: if (trait) { michael@0: if (trait.isConst() && ti.trait.hasDefaultValue) { michael@0: return constant(trait.value); michael@0: } michael@0: var slotQn = Multiname.getQualifiedName(trait.name); michael@0: return store(new IR.GetProperty(region, state.store, object, constant(slotQn))); michael@0: } michael@0: } michael@0: warn('Can\'t optimize getSlot ' + index); michael@0: return store(new IR.ASGetSlot(null, state.store, object, index)); michael@0: } michael@0: function setSlot(object, index, value, ti) { michael@0: if (ti) { michael@0: var trait = ti.trait; michael@0: if (trait) { michael@0: var slotQn = Multiname.getQualifiedName(trait.name); michael@0: store(new IR.SetProperty(region, state.store, object, constant(slotQn), value)); michael@0: return; michael@0: } michael@0: } michael@0: warn('Can\'t optimize setSlot ' + index); michael@0: store(new IR.ASSetSlot(region, state.store, object, index, value)); michael@0: } michael@0: function call(callee, object, args) { michael@0: return store(new Call(region, state.store, callee, object, args, IR.Flags.PRISTINE)); michael@0: } michael@0: function callCall(callee, object, args, pristine) { michael@0: return store(new Call(region, state.store, callee, object, args, pristine ? IR.Flags.PRISTINE : 0)); michael@0: } michael@0: function truthyCondition(operator) { michael@0: var right; michael@0: if (operator.isBinary()) { michael@0: right = pop(); michael@0: } michael@0: var left = pop(); michael@0: var node; michael@0: if (right) { michael@0: node = binary(operator, left, right); michael@0: } else { michael@0: node = unary(operator, left); michael@0: } michael@0: if (peepholeOptimizer) { michael@0: node = peepholeOptimizer.tryFold(node, true); michael@0: } michael@0: return node; michael@0: } michael@0: function negatedTruthyCondition(operator) { michael@0: var node = unary(Operator.FALSE, truthyCondition(operator)); michael@0: if (peepholeOptimizer) { michael@0: node = peepholeOptimizer.tryFold(node, true); michael@0: } michael@0: return node; michael@0: } michael@0: function pushExpression(operator, toInt) { michael@0: var left, right; michael@0: if (operator.isBinary()) { michael@0: right = pop(); michael@0: left = pop(); michael@0: if (toInt) { michael@0: right = coerceInt(right); michael@0: left = coerceInt(left); michael@0: } michael@0: push(binary(operator, left, right)); michael@0: } else { michael@0: left = pop(); michael@0: if (toInt) { michael@0: left = coerceInt(left); michael@0: } michael@0: push(unary(operator, left)); michael@0: } michael@0: } michael@0: var stops = null; michael@0: function buildIfStops(predicate) { michael@0: true; michael@0: var _if = new IR.If(region, predicate); michael@0: stops = [ michael@0: { michael@0: control: new Projection(_if, Projection.Type.FALSE), michael@0: target: bytecodes[bc.position + 1], michael@0: state: state michael@0: }, michael@0: { michael@0: control: new Projection(_if, Projection.Type.TRUE), michael@0: target: bc.target, michael@0: state: state michael@0: } michael@0: ]; michael@0: } michael@0: function buildJumpStop() { michael@0: true; michael@0: stops = [ michael@0: { michael@0: control: region, michael@0: target: bc.target, michael@0: state: state michael@0: } michael@0: ]; michael@0: } michael@0: function buildThrowStop() { michael@0: true; michael@0: stops = []; michael@0: } michael@0: function buildReturnStop() { michael@0: true; michael@0: stops = []; michael@0: } michael@0: function buildSwitchStops(determinant) { michael@0: true; michael@0: if (bc.targets.length > 2) { michael@0: stops = []; michael@0: var _switch = new IR.Switch(region, determinant); michael@0: for (var i = 0; i < bc.targets.length; i++) { michael@0: stops.push({ michael@0: control: new Projection(_switch, Projection.Type.CASE, constant(i)), michael@0: target: bc.targets[i], michael@0: state: state michael@0: }); michael@0: } michael@0: } else { michael@0: true; michael@0: var predicate = binary(Operator.SEQ, determinant, constant(0)); michael@0: var _if = new IR.If(region, predicate); michael@0: stops = [ michael@0: { michael@0: control: new Projection(_if, Projection.Type.FALSE), michael@0: target: bc.targets[1], michael@0: state: state michael@0: }, michael@0: { michael@0: control: new Projection(_if, Projection.Type.TRUE), michael@0: target: bc.targets[0], michael@0: state: state michael@0: } michael@0: ]; michael@0: } michael@0: } michael@0: if (traceBuilder) { michael@0: writer.writeLn('Processing Region: ' + region + ', Block: ' + block.bid); michael@0: writer.enter(('> state: ' + region.entryState.toString()).padRight(' ', 100)); michael@0: } michael@0: region.processed = true; michael@0: var bc; michael@0: for (var bci = block.position, end = block.end.position; bci <= end; bci++) { michael@0: bc = bytecodes[bci]; michael@0: var op = bc.op; michael@0: state.index = bci; michael@0: switch (op) { michael@0: case 3: michael@0: store(new IR.Throw(region, pop())); michael@0: stopPoints.push({ michael@0: region: region, michael@0: store: state.store, michael@0: value: Undefined michael@0: }); michael@0: buildThrowStop(); michael@0: break; michael@0: case 98: michael@0: pushLocal(bc.index); michael@0: break; michael@0: case 208: michael@0: case 209: michael@0: case 210: michael@0: case 211: michael@0: pushLocal(op - OP_getlocal0); michael@0: break; michael@0: case 99: michael@0: popLocal(bc.index); michael@0: break; michael@0: case 212: michael@0: case 213: michael@0: case 214: michael@0: case 215: michael@0: popLocal(op - OP_setlocal0); michael@0: break; michael@0: case 28: michael@0: scope.push(new IR.ASScope(topScope(), pop(), true)); michael@0: break; michael@0: case 48: michael@0: scope.push(new IR.ASScope(topScope(), pop(), false)); michael@0: break; michael@0: case 29: michael@0: scope.pop(); michael@0: break; michael@0: case 100: michael@0: push(getGlobalScope(bc.ti)); michael@0: break; michael@0: case 101: michael@0: push(getScopeObject(state.scope[bc.index])); michael@0: break; michael@0: case 93: michael@0: push(findProperty(buildMultiname(bc.index), true, bc.ti)); michael@0: break; michael@0: case 94: michael@0: push(findProperty(buildMultiname(bc.index), false, bc.ti)); michael@0: break; michael@0: case 102: michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: push(getProperty(object, multiname, bc.ti, false)); michael@0: break; michael@0: case 89: michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: push(getDescendants(object, multiname, bc.ti)); michael@0: break; michael@0: case 96: michael@0: multiname = buildMultiname(bc.index); michael@0: push(getProperty(findProperty(multiname, true, bc.ti), multiname, bc.ti, false)); michael@0: break; michael@0: case 104: michael@0: case 97: michael@0: value = pop(); michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: setProperty(object, multiname, value, bc.ti); michael@0: break; michael@0: case 106: michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: push(store(new IR.ASDeleteProperty(region, state.store, object, multiname))); michael@0: break; michael@0: case 108: michael@0: object = pop(); michael@0: push(getSlot(object, constant(bc.index), bc.ti)); michael@0: break; michael@0: case 109: michael@0: value = pop(); michael@0: object = pop(); michael@0: setSlot(object, constant(bc.index), value, bc.ti); michael@0: break; michael@0: case 4: michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: push(getSuper(savedScope(), object, multiname, bc.ti)); michael@0: break; michael@0: case 5: michael@0: value = pop(); michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: setSuper(savedScope(), object, multiname, value, bc.ti); michael@0: break; michael@0: case 241: michael@0: case 240: michael@0: break; michael@0: case 64: michael@0: push(callPure(createFunctionCallee, null, [ michael@0: constant(methods[bc.index]), michael@0: topScope(), michael@0: constant(true) michael@0: ])); michael@0: break; michael@0: case 65: michael@0: args = popMany(bc.argCount); michael@0: object = pop(); michael@0: callee = pop(); michael@0: push(callCall(callee, object, args)); michael@0: break; michael@0: case 70: michael@0: case 79: michael@0: case 76: michael@0: args = popMany(bc.argCount); michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: value = callProperty(object, multiname, args, op === OP_callproplex, bc.ti); michael@0: if (op !== OP_callpropvoid) { michael@0: push(value); michael@0: } michael@0: break; michael@0: case 69: michael@0: case 78: michael@0: multiname = buildMultiname(bc.index); michael@0: args = popMany(bc.argCount); michael@0: object = pop(); michael@0: value = callSuper(savedScope(), object, multiname, args, bc.ti); michael@0: if (op !== OP_callsupervoid) { michael@0: push(value); michael@0: } michael@0: break; michael@0: case 66: michael@0: args = popMany(bc.argCount); michael@0: object = pop(); michael@0: push(store(new IR.ASNew(region, state.store, object, args))); michael@0: break; michael@0: case 73: michael@0: args = popMany(bc.argCount); michael@0: object = pop(); michael@0: constructSuper(savedScope(), object, args, bc.ti); michael@0: break; michael@0: case 74: michael@0: args = popMany(bc.argCount); michael@0: multiname = buildMultiname(bc.index); michael@0: object = pop(); michael@0: callee = getProperty(object, multiname, bc.ti, false); michael@0: push(store(new IR.ASNew(region, state.store, callee, args))); michael@0: break; michael@0: case 128: michael@0: if (bc.ti && bc.ti.noCoercionNeeded) { michael@0: Counter.count('Compiler: NoCoercionNeeded'); michael@0: break; michael@0: } else { michael@0: Counter.count('Compiler: CoercionNeeded'); michael@0: } michael@0: value = pop(); michael@0: push(coerce(multinames[bc.index], value)); michael@0: break; michael@0: case 131: michael@0: case 115: michael@0: push(coerceInt(pop())); michael@0: break; michael@0: case 136: michael@0: case 116: michael@0: push(coerceUint(pop())); michael@0: break; michael@0: case 132: michael@0: case 117: michael@0: push(coerceNumber(pop())); michael@0: break; michael@0: case 129: michael@0: case 118: michael@0: push(coerceBoolean(pop())); michael@0: break; michael@0: case 120: michael@0: push(call(globalProperty('checkFilter'), null, [ michael@0: pop() michael@0: ])); michael@0: break; michael@0: case 130: michael@0: break; michael@0: case 133: michael@0: push(coerceString(pop())); michael@0: break; michael@0: case 112: michael@0: push(convertString(pop())); michael@0: break; michael@0: case 135: michael@0: type = pop(); michael@0: if (c4AsTypeLate) { michael@0: value = pop(); michael@0: push(call(globalProperty('asAsType'), null, [ michael@0: type, michael@0: value michael@0: ])); michael@0: } michael@0: break; michael@0: case 72: michael@0: case 71: michael@0: value = Undefined; michael@0: if (op === OP_returnvalue) { michael@0: value = pop(); michael@0: if (methodInfo.returnType) { michael@0: if (!(bc.ti && bc.ti.noCoercionNeeded)) { michael@0: value = coerce(methodInfo.returnType, value); michael@0: } michael@0: } michael@0: } michael@0: stopPoints.push({ michael@0: region: region, michael@0: store: state.store, michael@0: value: value michael@0: }); michael@0: buildReturnStop(); michael@0: break; michael@0: case 30: michael@0: case 35: michael@0: index = pop(); michael@0: object = pop(); michael@0: push(new IR.CallProperty(region, state.store, object, constant(op === OP_nextname ? 'asNextName' : 'asNextValue'), [ michael@0: index michael@0: ], IR.Flags.PRISTINE)); michael@0: break; michael@0: case 50: michael@0: var temp = call(globalProperty('asHasNext2'), null, [ michael@0: local[bc.object], michael@0: local[bc.index] michael@0: ]); michael@0: local[bc.object] = getJSProperty(temp, 'object'); michael@0: push(local[bc.index] = getJSProperty(temp, 'index')); michael@0: break; michael@0: case 32: michael@0: push(Null); michael@0: break; michael@0: case 33: michael@0: push(Undefined); michael@0: break; michael@0: case 34: michael@0: notImplemented(); michael@0: break; michael@0: case 36: michael@0: push(constant(bc.value)); michael@0: break; michael@0: case 37: michael@0: push(constant(bc.value)); michael@0: break; michael@0: case 44: michael@0: push(constant(strings[bc.index])); michael@0: break; michael@0: case 45: michael@0: push(constant(ints[bc.index])); michael@0: break; michael@0: case 46: michael@0: push(constant(uints[bc.index])); michael@0: break; michael@0: case 47: michael@0: push(constant(doubles[bc.index])); michael@0: break; michael@0: case 38: michael@0: push(constant(true)); michael@0: break; michael@0: case 39: michael@0: push(constant(false)); michael@0: break; michael@0: case 40: michael@0: push(constant(NaN)); michael@0: break; michael@0: case 41: michael@0: pop(); michael@0: break; michael@0: case 42: michael@0: value = shouldNotFloat(pop()); michael@0: push(value); michael@0: push(value); michael@0: break; michael@0: case 43: michael@0: state.stack.push(pop(), pop()); michael@0: break; michael@0: case 239: michael@0: case OP_debugline: michael@0: case OP_debugfile: michael@0: break; michael@0: case 12: michael@0: buildIfStops(negatedTruthyCondition(Operator.LT)); michael@0: break; michael@0: case 24: michael@0: buildIfStops(truthyCondition(Operator.GE)); michael@0: break; michael@0: case 13: michael@0: buildIfStops(negatedTruthyCondition(Operator.LE)); michael@0: break; michael@0: case 23: michael@0: buildIfStops(truthyCondition(Operator.GT)); michael@0: break; michael@0: case 14: michael@0: buildIfStops(negatedTruthyCondition(Operator.GT)); michael@0: break; michael@0: case 22: michael@0: buildIfStops(truthyCondition(Operator.LE)); michael@0: break; michael@0: case 15: michael@0: buildIfStops(negatedTruthyCondition(Operator.GE)); michael@0: break; michael@0: case 21: michael@0: buildIfStops(truthyCondition(Operator.LT)); michael@0: break; michael@0: case 16: michael@0: buildJumpStop(); michael@0: break; michael@0: case 17: michael@0: buildIfStops(truthyCondition(Operator.TRUE)); michael@0: break; michael@0: case 18: michael@0: buildIfStops(truthyCondition(Operator.FALSE)); michael@0: break; michael@0: case 19: michael@0: buildIfStops(truthyCondition(Operator.EQ)); michael@0: break; michael@0: case 20: michael@0: buildIfStops(truthyCondition(Operator.NE)); michael@0: break; michael@0: case 25: michael@0: buildIfStops(truthyCondition(Operator.SEQ)); michael@0: break; michael@0: case 26: michael@0: buildIfStops(truthyCondition(Operator.SNE)); michael@0: break; michael@0: case 27: michael@0: buildSwitchStops(pop()); michael@0: break; michael@0: case 150: michael@0: pushExpression(Operator.FALSE); michael@0: break; michael@0: case 151: michael@0: pushExpression(Operator.BITWISE_NOT); michael@0: break; michael@0: case 160: michael@0: right = pop(); michael@0: left = pop(); michael@0: if (typesAreEqual(left, right)) { michael@0: operator = Operator.ADD; michael@0: } else if (Shumway.AVM2.Runtime.useAsAdd) { michael@0: operator = Operator.AS_ADD; michael@0: } else { michael@0: operator = Operator.ADD; michael@0: } michael@0: push(binary(operator, left, right)); michael@0: break; michael@0: case 197: michael@0: pushExpression(Operator.ADD, true); michael@0: break; michael@0: case 161: michael@0: pushExpression(Operator.SUB); michael@0: break; michael@0: case 198: michael@0: pushExpression(Operator.SUB, true); michael@0: break; michael@0: case 162: michael@0: pushExpression(Operator.MUL); michael@0: break; michael@0: case 199: michael@0: pushExpression(Operator.MUL, true); michael@0: break; michael@0: case 163: michael@0: pushExpression(Operator.DIV); michael@0: break; michael@0: case 164: michael@0: pushExpression(Operator.MOD); michael@0: break; michael@0: case 165: michael@0: pushExpression(Operator.LSH); michael@0: break; michael@0: case 166: michael@0: pushExpression(Operator.RSH); michael@0: break; michael@0: case 167: michael@0: pushExpression(Operator.URSH); michael@0: break; michael@0: case 168: michael@0: pushExpression(Operator.AND); michael@0: break; michael@0: case 169: michael@0: pushExpression(Operator.OR); michael@0: break; michael@0: case 170: michael@0: pushExpression(Operator.XOR); michael@0: break; michael@0: case 171: michael@0: pushExpression(Operator.EQ); michael@0: break; michael@0: case 172: michael@0: pushExpression(Operator.SEQ); michael@0: break; michael@0: case 173: michael@0: pushExpression(Operator.LT); michael@0: break; michael@0: case 174: michael@0: pushExpression(Operator.LE); michael@0: break; michael@0: case 175: michael@0: pushExpression(Operator.GT); michael@0: break; michael@0: case 176: michael@0: pushExpression(Operator.GE); michael@0: break; michael@0: case 144: michael@0: pushExpression(Operator.NEG); michael@0: break; michael@0: case 196: michael@0: pushExpression(Operator.NEG, true); michael@0: break; michael@0: case 145: michael@0: case 192: michael@0: case 147: michael@0: case 193: michael@0: push(constant(1)); michael@0: if (op === OP_increment || op === OP_decrement) { michael@0: push(coerceNumber(pop())); michael@0: } else { michael@0: push(coerceInt(pop())); michael@0: } michael@0: if (op === OP_increment || op === OP_increment_i) { michael@0: pushExpression(Operator.ADD); michael@0: } else { michael@0: pushExpression(Operator.SUB); michael@0: } michael@0: break; michael@0: case 146: michael@0: case 194: michael@0: case 148: michael@0: case 195: michael@0: push(constant(1)); michael@0: if (op === OP_inclocal || op === OP_declocal) { michael@0: push(coerceNumber(local[bc.index])); michael@0: } else { michael@0: push(coerceInt(local[bc.index])); michael@0: } michael@0: if (op === OP_inclocal || op === OP_inclocal_i) { michael@0: pushExpression(Operator.ADD); michael@0: } else { michael@0: pushExpression(Operator.SUB); michael@0: } michael@0: popLocal(bc.index); michael@0: break; michael@0: case 177: michael@0: type = pop(); michael@0: value = pop(); michael@0: push(call(getJSProperty(type, 'isInstanceOf'), null, [ michael@0: value michael@0: ])); michael@0: break; michael@0: case 178: michael@0: value = pop(); michael@0: multiname = buildMultiname(bc.index); michael@0: type = getProperty(findProperty(multiname, false), multiname); michael@0: push(call(globalProperty('asIsType'), null, [ michael@0: type, michael@0: value michael@0: ])); michael@0: break; michael@0: case 179: michael@0: type = pop(); michael@0: value = pop(); michael@0: push(call(globalProperty('asIsType'), null, [ michael@0: type, michael@0: value michael@0: ])); michael@0: break; michael@0: case 180: michael@0: object = pop(); michael@0: value = pop(); michael@0: multiname = new IR.ASMultiname(Undefined, value, 0); michael@0: push(store(new IR.ASHasProperty(region, state.store, object, multiname))); michael@0: break; michael@0: case 149: michael@0: push(call(globalProperty('asTypeOf'), null, [ michael@0: pop() michael@0: ])); michael@0: break; michael@0: case 8: michael@0: push(Undefined); michael@0: popLocal(bc.index); michael@0: break; michael@0: case 83: michael@0: args = popMany(bc.argCount); michael@0: type = pop(); michael@0: callee = globalProperty('applyType'); michael@0: push(call(callee, null, [ michael@0: domain, michael@0: type, michael@0: new NewArray(region, args) michael@0: ])); michael@0: break; michael@0: case 86: michael@0: args = popMany(bc.argCount); michael@0: push(new NewArray(region, args)); michael@0: break; michael@0: case 85: michael@0: var properties = []; michael@0: for (var i = 0; i < bc.argCount; i++) { michael@0: var value = pop(); michael@0: var key = pop(); michael@0: true; michael@0: key = constant(Multiname.getPublicQualifiedName(key.value)); michael@0: properties.push(new KeyValuePair(key, value)); michael@0: } michael@0: push(new NewObject(region, properties)); michael@0: break; michael@0: case 87: michael@0: push(new IR.ASNewActivation(constant(methodInfo))); michael@0: break; michael@0: case 88: michael@0: callee = globalProperty('createClass'); michael@0: push(call(callee, null, [ michael@0: constant(classes[bc.index]), michael@0: pop(), michael@0: topScope() michael@0: ])); michael@0: break; michael@0: default: michael@0: unexpected('Not Implemented: ' + bc); michael@0: } michael@0: if (op === OP_debug || op === OP_debugfile || op === OP_debugline) { michael@0: continue; michael@0: } michael@0: if (traceBuilder) { michael@0: writer.writeLn(('state: ' + state.toString()).padRight(' ', 100) + ' : ' + bci + ', ' + bc.toString(this.abc)); michael@0: } michael@0: } michael@0: if (traceBuilder) { michael@0: writer.leave(('< state: ' + state.toString()).padRight(' ', 100)); michael@0: } michael@0: if (!stops) { michael@0: stops = []; michael@0: if (bc.position + 1 <= bytecodes.length) { michael@0: stops.push({ michael@0: control: region, michael@0: target: bytecodes[bc.position + 1], michael@0: state: state michael@0: }); michael@0: } michael@0: } michael@0: return stops; michael@0: } michael@0: var stop; michael@0: if (stopPoints.length > 1) { michael@0: var stopRegion = new Region(null); michael@0: var stopValuePhi = new Phi(stopRegion, null); michael@0: var stopStorePhi = new Phi(stopRegion, null); michael@0: stopPoints.forEach(function (stopPoint) { michael@0: stopRegion.predecessors.push(stopPoint.region); michael@0: stopValuePhi.pushValue(stopPoint.value); michael@0: stopStorePhi.pushValue(stopPoint.store); michael@0: }); michael@0: stop = new Stop(stopRegion, stopStorePhi, stopValuePhi); michael@0: } else { michael@0: stop = new Stop(stopPoints[0].region, stopPoints[0].store, stopPoints[0].value); michael@0: } michael@0: return new DFG(stop); michael@0: }; michael@0: return builder; michael@0: }(); michael@0: function buildMethod(verifier, methodInfo, scope, hasDynamicScope) { michael@0: true; michael@0: true; michael@0: true; michael@0: Counter.count('Compiler: Compiled Methods'); michael@0: Timer.start('Compiler'); michael@0: Timer.start('Mark Loops'); michael@0: methodInfo.analysis.markLoops(); michael@0: Timer.stop(); michael@0: if (Shumway.AVM2.Runtime.enableVerifier.value) { michael@0: Timer.start('Verify'); michael@0: verifier.verifyMethod(methodInfo, scope); michael@0: Timer.stop(); michael@0: } michael@0: var traceSource = c4TraceLevel.value > 0; michael@0: var traceIR = c4TraceLevel.value > 1; michael@0: Timer.start('Build IR'); michael@0: Node.startNumbering(); michael@0: var dfg = new Builder(methodInfo, scope, hasDynamicScope).buildGraph(); michael@0: Timer.stop(); michael@0: traceIR && dfg.trace(writer); michael@0: Timer.start('Build CFG'); michael@0: var cfg = dfg.buildCFG(); michael@0: Timer.stop(); michael@0: Timer.start('Optimize Phis'); michael@0: cfg.optimizePhis(); michael@0: Timer.stop(); michael@0: Timer.start('Schedule Nodes'); michael@0: cfg.scheduleEarly(); michael@0: Timer.stop(); michael@0: traceIR && cfg.trace(writer); michael@0: Timer.start('Verify IR'); michael@0: cfg.verify(); michael@0: Timer.stop(); michael@0: Timer.start('Allocate Variables'); michael@0: cfg.allocateVariables(); michael@0: Timer.stop(); michael@0: Timer.start('Generate Source'); michael@0: var result = Backend.generate(cfg, enableRegisterAllocator.value); michael@0: Timer.stop(); michael@0: traceSource && writer.writeLn(result.body); michael@0: Node.stopNumbering(); michael@0: Timer.stop(); michael@0: return result; michael@0: } michael@0: exports.buildMethod = buildMethod; michael@0: }(typeof exports === 'undefined' ? Builder = {} : exports)); michael@0: var Compiler = new (function () { michael@0: function constructor() { michael@0: this.verifier = new Verifier(); michael@0: } michael@0: constructor.prototype.compileMethod = function (methodInfo, scope, hasDynamicScope) { michael@0: return Builder.buildMethod(this.verifier, methodInfo, scope, hasDynamicScope); michael@0: }; michael@0: return constructor; michael@0: }())(); michael@0: (function (exports) { michael@0: var Control = function () { michael@0: var SEQ = 1; michael@0: var LOOP = 2; michael@0: var IF = 3; michael@0: var CASE = 4; michael@0: var SWITCH = 5; michael@0: var LABEL_CASE = 6; michael@0: var LABEL_SWITCH = 7; michael@0: var EXIT = 8; michael@0: var BREAK = 9; michael@0: var CONTINUE = 10; michael@0: var TRY = 11; michael@0: var CATCH = 12; michael@0: function Seq(body) { michael@0: this.kind = SEQ; michael@0: this.body = body; michael@0: } michael@0: Seq.prototype = { michael@0: trace: function (writer) { michael@0: var body = this.body; michael@0: for (var i = 0, j = body.length; i < j; i++) { michael@0: body[i].trace(writer); michael@0: } michael@0: }, michael@0: first: function () { michael@0: return this.body[0]; michael@0: }, michael@0: slice: function (begin, end) { michael@0: return new Seq(this.body.slice(begin, end)); michael@0: } michael@0: }; michael@0: function Loop(body) { michael@0: this.kind = LOOP; michael@0: this.body = body; michael@0: } michael@0: Loop.prototype = { michael@0: trace: function (writer) { michael@0: writer.enter('loop {'); michael@0: this.body.trace(writer); michael@0: writer.leave('}'); michael@0: } michael@0: }; michael@0: function If(cond, then, els, nothingThrownLabel) { michael@0: this.kind = IF; michael@0: this.cond = cond; michael@0: this.then = then; michael@0: this.else = els; michael@0: this.negated = false; michael@0: this.nothingThrownLabel = nothingThrownLabel; michael@0: } michael@0: If.prototype = { michael@0: trace: function (writer) { michael@0: this.cond.trace(writer); michael@0: if (this.nothingThrownLabel) { michael@0: writer.enter('if (label is ' + this.nothingThrownLabel + ') {'); michael@0: } michael@0: writer.enter('if' + (this.negated ? ' not' : '') + ' {'); michael@0: this.then && this.then.trace(writer); michael@0: if (this.else) { michael@0: writer.outdent(); michael@0: writer.enter('} else {'); michael@0: this.else.trace(writer); michael@0: } michael@0: writer.leave('}'); michael@0: if (this.nothingThrownLabel) { michael@0: writer.leave('}'); michael@0: } michael@0: } michael@0: }; michael@0: function Case(index, body) { michael@0: this.kind = CASE; michael@0: this.index = index; michael@0: this.body = body; michael@0: } michael@0: Case.prototype = { michael@0: trace: function (writer) { michael@0: if (this.index >= 0) { michael@0: writer.writeLn('case ' + this.index + ':'); michael@0: } else { michael@0: writer.writeLn('default:'); michael@0: } michael@0: writer.indent(); michael@0: this.body && this.body.trace(writer); michael@0: writer.outdent(); michael@0: } michael@0: }; michael@0: function Switch(determinant, cases, nothingThrownLabel) { michael@0: this.kind = SWITCH; michael@0: this.determinant = determinant; michael@0: this.cases = cases; michael@0: this.nothingThrownLabel = nothingThrownLabel; michael@0: } michael@0: Switch.prototype = { michael@0: trace: function (writer) { michael@0: if (this.nothingThrownLabel) { michael@0: writer.enter('if (label is ' + this.nothingThrownLabel + ') {'); michael@0: } michael@0: this.determinant.trace(writer); michael@0: writer.writeLn('switch {'); michael@0: for (var i = 0, j = this.cases.length; i < j; i++) { michael@0: this.cases[i].trace(writer); michael@0: } michael@0: writer.writeLn('}'); michael@0: if (this.nothingThrownLabel) { michael@0: writer.leave('}'); michael@0: } michael@0: } michael@0: }; michael@0: function LabelCase(labels, body) { michael@0: this.kind = LABEL_CASE; michael@0: this.labels = labels; michael@0: this.body = body; michael@0: } michael@0: LabelCase.prototype = { michael@0: trace: function (writer) { michael@0: writer.enter('if (label is ' + this.labels.join(' or ') + ') {'); michael@0: this.body && this.body.trace(writer); michael@0: writer.leave('}'); michael@0: } michael@0: }; michael@0: function LabelSwitch(cases) { michael@0: var labelMap = {}; michael@0: for (var i = 0, j = cases.length; i < j; i++) { michael@0: var c = cases[i]; michael@0: if (!c.labels) { michael@0: print(c.toSource()); michael@0: } michael@0: for (var k = 0, l = c.labels.length; k < l; k++) { michael@0: labelMap[c.labels[k]] = c; michael@0: } michael@0: } michael@0: this.kind = LABEL_SWITCH; michael@0: this.cases = cases; michael@0: this.labelMap = labelMap; michael@0: } michael@0: LabelSwitch.prototype = { michael@0: trace: function (writer) { michael@0: for (var i = 0, j = this.cases.length; i < j; i++) { michael@0: this.cases[i].trace(writer); michael@0: } michael@0: } michael@0: }; michael@0: function Exit(label) { michael@0: this.kind = EXIT; michael@0: this.label = label; michael@0: } michael@0: Exit.prototype = { michael@0: trace: function (writer) { michael@0: writer.writeLn('label = ' + this.label); michael@0: } michael@0: }; michael@0: function Break(label, head) { michael@0: this.kind = BREAK; michael@0: this.label = label; michael@0: this.head = head; michael@0: } michael@0: Break.prototype = { michael@0: trace: function (writer) { michael@0: this.label && writer.writeLn('label = ' + this.label); michael@0: writer.writeLn('break'); michael@0: } michael@0: }; michael@0: function Continue(label, head) { michael@0: this.kind = CONTINUE; michael@0: this.label = label; michael@0: this.head = head; michael@0: this.necessary = true; michael@0: } michael@0: Continue.prototype = { michael@0: trace: function (writer) { michael@0: this.label && writer.writeLn('label = ' + this.label); michael@0: this.necessary && writer.writeLn('continue'); michael@0: } michael@0: }; michael@0: function Try(body, catches) { michael@0: this.kind = TRY; michael@0: this.body = body; michael@0: this.catches = catches; michael@0: } michael@0: Try.prototype = { michael@0: trace: function (writer) { michael@0: writer.enter('try {'); michael@0: this.body.trace(writer); michael@0: writer.writeLn('label = ' + this.nothingThrownLabel); michael@0: for (var i = 0, j = this.catches.length; i < j; i++) { michael@0: this.catches[i].trace(writer); michael@0: } michael@0: writer.leave('}'); michael@0: } michael@0: }; michael@0: function Catch(varName, typeName, body) { michael@0: this.kind = CATCH; michael@0: this.varName = varName; michael@0: this.typeName = typeName; michael@0: this.body = body; michael@0: } michael@0: Catch.prototype = { michael@0: trace: function (writer) { michael@0: writer.outdent(); michael@0: writer.enter('} catch (' + (this.varName || 'e') + (this.typeName ? ' : ' + this.typeName : '') + ') {'); michael@0: this.body.trace(writer); michael@0: } michael@0: }; michael@0: return { michael@0: SEQ: SEQ, michael@0: LOOP: LOOP, michael@0: IF: IF, michael@0: CASE: CASE, michael@0: SWITCH: SWITCH, michael@0: LABEL_CASE: LABEL_CASE, michael@0: LABEL_SWITCH: LABEL_SWITCH, michael@0: EXIT: EXIT, michael@0: BREAK: BREAK, michael@0: CONTINUE: CONTINUE, michael@0: TRY: TRY, michael@0: CATCH: CATCH, michael@0: Seq: Seq, michael@0: Loop: Loop, michael@0: If: If, michael@0: Case: Case, michael@0: Switch: Switch, michael@0: LabelCase: LabelCase, michael@0: LabelSwitch: LabelSwitch, michael@0: Exit: Exit, michael@0: Break: Break, michael@0: Continue: Continue, michael@0: Try: Try, michael@0: Catch: Catch michael@0: }; michael@0: }(); michael@0: var Analysis = function () { michael@0: function blockSetClass(length, blockById) { michael@0: var BlockSet = BitSetFunctor(length); michael@0: var ADDRESS_BITS_PER_WORD = BlockSet.ADDRESS_BITS_PER_WORD; michael@0: var BITS_PER_WORD = BlockSet.BITS_PER_WORD; michael@0: var BIT_INDEX_MASK = BlockSet.BIT_INDEX_MASK; michael@0: BlockSet.singleton = function singleton(b) { michael@0: var bs = new BlockSet(); michael@0: bs.set(b.id); michael@0: bs.count = 1; michael@0: bs.dirty = 0; michael@0: return bs; michael@0: }; michael@0: BlockSet.fromBlocks = function fromArray(other) { michael@0: var bs = new BlockSet(); michael@0: bs.setBlocks(other); michael@0: return bs; michael@0: }; michael@0: var Bsp = BlockSet.prototype; michael@0: if (BlockSet.singleword) { michael@0: Bsp.forEachBlock = function forEach(fn) { michael@0: true; michael@0: var byId = blockById; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(byId[k]); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.choose = function choose() { michael@0: var byId = blockById; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: return byId[k]; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.members = function members() { michael@0: var byId = blockById; michael@0: var set = []; michael@0: var word = this.bits; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(byId[k]); michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }; michael@0: Bsp.setBlocks = function setBlocks(bs) { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bs.length; i < j; i++) { michael@0: var id = bs[i].id; michael@0: bits |= 1 << (id & BIT_INDEX_MASK); michael@0: } michael@0: this.bits = bits; michael@0: }; michael@0: } else { michael@0: Bsp.forEachBlock = function forEach(fn) { michael@0: true; michael@0: var byId = blockById; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: fn(byId[i * BITS_PER_WORD + k]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.choose = function choose() { michael@0: var byId = blockById; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: return byId[i * BITS_PER_WORD + k]; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Bsp.members = function members() { michael@0: var byId = blockById; michael@0: var set = []; michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bits.length; i < j; i++) { michael@0: var word = bits[i]; michael@0: if (word) { michael@0: for (var k = 0; k < BITS_PER_WORD; k++) { michael@0: if (word & 1 << k) { michael@0: set.push(byId[i * BITS_PER_WORD + k]); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return set; michael@0: }; michael@0: Bsp.setBlocks = function setBlocks(bs) { michael@0: var bits = this.bits; michael@0: for (var i = 0, j = bs.length; i < j; i++) { michael@0: var id = bs[i].id; michael@0: bits[id >> ADDRESS_BITS_PER_WORD] |= 1 << (id & BIT_INDEX_MASK); michael@0: } michael@0: }; michael@0: } michael@0: return BlockSet; michael@0: } michael@0: function Analysis(cfg, options) { michael@0: this.options = options || {}; michael@0: this.BlockSet = blockSetClass(cfg.blocks.length, cfg.blocks); michael@0: this.hasExceptions = false; michael@0: this.normalizeReachableBlocks(cfg.root); michael@0: } michael@0: Analysis.prototype = { michael@0: normalizeReachableBlocks: function normalizeReachableBlocks(root) { michael@0: true; michael@0: var ONCE = 1; michael@0: var BUNCH_OF_TIMES = 2; michael@0: var BlockSet = this.BlockSet; michael@0: var blocks = []; michael@0: var visited = {}; michael@0: var ancestors = {}; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var node; michael@0: ancestors[root.id] = true; michael@0: while (node = worklist.top()) { michael@0: if (visited[node.id]) { michael@0: if (visited[node.id] === ONCE) { michael@0: visited[node.id] = BUNCH_OF_TIMES; michael@0: blocks.push(node); michael@0: } michael@0: ancestors[node.id] = false; michael@0: worklist.pop(); michael@0: continue; michael@0: } michael@0: visited[node.id] = ONCE; michael@0: ancestors[node.id] = true; michael@0: var successors = node.successors; michael@0: for (var i = 0, j = successors.length; i < j; i++) { michael@0: var s = successors[i]; michael@0: if (ancestors[s.id]) { michael@0: if (!node.spbacks) { michael@0: node.spbacks = new BlockSet(); michael@0: } michael@0: node.spbacks.set(s.id); michael@0: } michael@0: !visited[s.id] && worklist.push(s); michael@0: } michael@0: } michael@0: this.blocks = blocks.reverse(); michael@0: }, michael@0: computeDominance: function computeDominance() { michael@0: function intersectDominators(doms, b1, b2) { michael@0: var finger1 = b1; michael@0: var finger2 = b2; michael@0: while (finger1 !== finger2) { michael@0: while (finger1 > finger2) { michael@0: finger1 = doms[finger1]; michael@0: } michael@0: while (finger2 > finger1) { michael@0: finger2 = doms[finger2]; michael@0: } michael@0: } michael@0: return finger1; michael@0: } michael@0: var blocks = this.blocks; michael@0: var n = blocks.length; michael@0: var doms = new Array(n); michael@0: doms[0] = 0; michael@0: var rpo = []; michael@0: for (var b = 0; b < n; b++) { michael@0: rpo[blocks[b].id] = b; michael@0: blocks[b].dominatees = []; michael@0: } michael@0: var changed = true; michael@0: while (changed) { michael@0: changed = false; michael@0: for (var b = 1; b < n; b++) { michael@0: var predecessors = blocks[b].predecessors; michael@0: var j = predecessors.length; michael@0: var newIdom = rpo[predecessors[0].id]; michael@0: if (!(newIdom in doms)) { michael@0: for (var i = 1; i < j; i++) { michael@0: newIdom = rpo[predecessors[i].id]; michael@0: if (newIdom in doms) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: true; michael@0: for (var i = 0; i < j; i++) { michael@0: var p = rpo[predecessors[i].id]; michael@0: if (p === newIdom) { michael@0: continue; michael@0: } michael@0: if (p in doms) { michael@0: newIdom = intersectDominators(doms, p, newIdom); michael@0: } michael@0: } michael@0: if (doms[b] !== newIdom) { michael@0: doms[b] = newIdom; michael@0: changed = true; michael@0: } michael@0: } michael@0: } michael@0: blocks[0].dominator = blocks[0]; michael@0: var block; michael@0: for (var b = 1; b < n; b++) { michael@0: block = blocks[b]; michael@0: var idom = blocks[doms[b]]; michael@0: block.dominator = idom; michael@0: idom.dominatees.push(block); michael@0: block.npredecessors = block.predecessors.length; michael@0: } michael@0: var worklist = [ michael@0: blocks[0] michael@0: ]; michael@0: blocks[0].level || (blocks[0].level = 0); michael@0: while (block = worklist.shift()) { michael@0: var dominatees = block.dominatees; michael@0: for (var i = 0, j = dominatees.length; i < j; i++) { michael@0: dominatees[i].level = block.level + 1; michael@0: } michael@0: worklist.push.apply(worklist, dominatees); michael@0: } michael@0: }, michael@0: computeFrontiers: function computeFrontiers() { michael@0: var BlockSet = this.BlockSet; michael@0: var blocks = this.blocks; michael@0: for (var b = 0, n = blocks.length; b < n; b++) { michael@0: blocks[b].frontier = new BlockSet(); michael@0: } michael@0: for (var b = 1, n = blocks.length; b < n; b++) { michael@0: var block = blocks[b]; michael@0: var predecessors = block.predecessors; michael@0: if (predecessors.length >= 2) { michael@0: var idom = block.dominator; michael@0: for (var i = 0, j = predecessors.length; i < j; i++) { michael@0: var runner = predecessors[i]; michael@0: while (runner !== idom) { michael@0: runner.frontier.set(block.id); michael@0: runner = runner.dominator; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: analyzeControlFlow: function analyzeControlFlow() { michael@0: this.computeDominance(); michael@0: this.analyzedControlFlow = true; michael@0: return true; michael@0: }, michael@0: markLoops: function markLoops() { michael@0: if (!this.analyzedControlFlow && !this.analyzeControlFlow()) { michael@0: return false; michael@0: } michael@0: var BlockSet = this.BlockSet; michael@0: function findSCCs(root) { michael@0: var preorderId = 1; michael@0: var preorder = {}; michael@0: var assigned = {}; michael@0: var unconnectedNodes = []; michael@0: var pendingNodes = []; michael@0: var sccs = []; michael@0: var level = root.level + 1; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var node; michael@0: var u, s; michael@0: while (node = worklist.top()) { michael@0: if (preorder[node.id]) { michael@0: if (pendingNodes.peek() === node) { michael@0: pendingNodes.pop(); michael@0: var scc = []; michael@0: do { michael@0: u = unconnectedNodes.pop(); michael@0: assigned[u.id] = true; michael@0: scc.push(u); michael@0: } while (u !== node); michael@0: if (scc.length > 1 || u.spbacks && u.spbacks.get(u.id)) { michael@0: sccs.push(scc); michael@0: } michael@0: } michael@0: worklist.pop(); michael@0: continue; michael@0: } michael@0: preorder[node.id] = preorderId++; michael@0: unconnectedNodes.push(node); michael@0: pendingNodes.push(node); michael@0: var successors = node.successors; michael@0: for (var i = 0, j = successors.length; i < j; i++) { michael@0: s = successors[i]; michael@0: if (s.level < level) { michael@0: continue; michael@0: } michael@0: var sid = s.id; michael@0: if (!preorder[sid]) { michael@0: worklist.push(s); michael@0: } else if (!assigned[sid]) { michael@0: while (preorder[pendingNodes.peek().id] > preorder[sid]) { michael@0: pendingNodes.pop(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return sccs; michael@0: } michael@0: function findLoopHeads(blocks) { michael@0: var heads = new BlockSet(); michael@0: for (var i = 0, j = blocks.length; i < j; i++) { michael@0: var block = blocks[i]; michael@0: var spbacks = block.spbacks; michael@0: if (!spbacks) { michael@0: continue; michael@0: } michael@0: var successors = block.successors; michael@0: for (var k = 0, l = successors.length; k < l; k++) { michael@0: var s = successors[k]; michael@0: if (spbacks.get(s.id)) { michael@0: heads.set(s.dominator.id); michael@0: } michael@0: } michael@0: } michael@0: return heads.members(); michael@0: } michael@0: function LoopInfo(scc, loopId) { michael@0: var body = new BlockSet(); michael@0: body.setBlocks(scc); michael@0: body.recount(); michael@0: this.id = loopId; michael@0: this.body = body; michael@0: this.exit = new BlockSet(); michael@0: this.save = {}; michael@0: this.head = new BlockSet(); michael@0: this.npredecessors = 0; michael@0: } michael@0: var heads = findLoopHeads(this.blocks); michael@0: if (heads.length <= 0) { michael@0: this.markedLoops = true; michael@0: return true; michael@0: } michael@0: var worklist = heads.sort(function (a, b) { michael@0: return a.level - b.level; michael@0: }); michael@0: var loopId = 0; michael@0: for (var n = worklist.length - 1; n >= 0; n--) { michael@0: var top = worklist[n]; michael@0: var sccs = findSCCs(top); michael@0: if (sccs.length === 0) { michael@0: continue; michael@0: } michael@0: for (var i = 0, j = sccs.length; i < j; i++) { michael@0: var scc = sccs[i]; michael@0: var loop = new LoopInfo(scc, loopId++); michael@0: for (var k = 0, l = scc.length; k < l; k++) { michael@0: var h = scc[k]; michael@0: if (h.level === top.level + 1 && !h.loop) { michael@0: h.loop = loop; michael@0: loop.head.set(h.id); michael@0: var predecessors = h.predecessors; michael@0: for (var pi = 0, pj = predecessors.length; pi < pj; pi++) { michael@0: loop.body.get(predecessors[pi].id) && h.npredecessors--; michael@0: } michael@0: loop.npredecessors += h.npredecessors; michael@0: } michael@0: } michael@0: for (var k = 0, l = scc.length; k < l; k++) { michael@0: var h = scc[k]; michael@0: if (h.level === top.level + 1) { michael@0: h.npredecessors = loop.npredecessors; michael@0: } michael@0: } michael@0: loop.head.recount(); michael@0: } michael@0: } michael@0: this.markedLoops = true; michael@0: return true; michael@0: }, michael@0: induceControlTree: function induceControlTree() { michael@0: var hasExceptions = this.hasExceptions; michael@0: var BlockSet = this.BlockSet; michael@0: function maybe(exit, save) { michael@0: exit.recount(); michael@0: if (exit.count === 0) { michael@0: return null; michael@0: } michael@0: exit.save = save; michael@0: return exit; michael@0: } michael@0: var exceptionId = this.blocks.length; michael@0: function induce(head, exit, save, loop, inLoopHead, lookupSwitch, fallthrough) { michael@0: var v = []; michael@0: while (head) { michael@0: if (head.count > 1) { michael@0: var exit2 = new BlockSet(); michael@0: var save2 = {}; michael@0: var cases = []; michael@0: var heads = head.members(); michael@0: for (var i = 0, j = heads.length; i < j; i++) { michael@0: var h = heads[i]; michael@0: var bid = h.id; michael@0: var c; michael@0: if (h.loop && head.contains(h.loop.head)) { michael@0: var loop2 = h.loop; michael@0: if (!loop2.induced) { michael@0: var lheads = loop2.head.members(); michael@0: var lheadsave = 0; michael@0: for (k = 0, l = lheads.length; k < l; k++) { michael@0: lheadsave += head.save[lheads[k].id]; michael@0: } michael@0: if (h.npredecessors - lheadsave > 0) { michael@0: h.npredecessors -= head.save[bid]; michael@0: h.save = head.save[bid]; michael@0: c = induce(h, exit2, save2, loop); michael@0: cases.push(new Control.LabelCase([ michael@0: bid michael@0: ], c)); michael@0: } else { michael@0: for (k = 0, l = lheads.length; k < l; k++) { michael@0: var lh = lheads[k]; michael@0: lh.npredecessors -= lheadsave; michael@0: lh.save = lheadsave; michael@0: } michael@0: c = induce(h, exit2, save2, loop); michael@0: cases.push(new Control.LabelCase(loop2.head.toArray(), c)); michael@0: loop2.induced = true; michael@0: } michael@0: } michael@0: } else { michael@0: h.npredecessors -= head.save[bid]; michael@0: h.save = head.save[bid]; michael@0: c = induce(h, exit2, save2, loop); michael@0: cases.push(new Control.LabelCase([ michael@0: bid michael@0: ], c)); michael@0: } michael@0: } michael@0: var pruned = []; michael@0: var k = 0; michael@0: var c; michael@0: for (var i = 0, j = cases.length; i < j; i++) { michael@0: c = cases[i]; michael@0: var labels = c.labels; michael@0: var lk = 0; michael@0: for (var ln = 0, nlabels = labels.length; ln < nlabels; ln++) { michael@0: var bid = labels[ln]; michael@0: if (exit2.get(bid) && heads[i].npredecessors - head.save[bid] > 0) { michael@0: pruned.push(bid); michael@0: } else { michael@0: labels[lk++] = bid; michael@0: } michael@0: } michael@0: labels.length = lk; michael@0: if (labels.length > 0) { michael@0: cases[k++] = c; michael@0: } michael@0: } michael@0: cases.length = k; michael@0: if (cases.length === 0) { michael@0: for (var i = 0, j = pruned.length; i < j; i++) { michael@0: var bid = pruned[i]; michael@0: save[bid] = (save[bid] || 0) + head.save[bid]; michael@0: exit.set(bid); michael@0: } michael@0: break; michael@0: } michael@0: v.push(new Control.LabelSwitch(cases)); michael@0: head = maybe(exit2, save2); michael@0: continue; michael@0: } michael@0: var h, bid, c; michael@0: if (head.count === 1) { michael@0: h = head.choose(); michael@0: bid = h.id; michael@0: h.npredecessors -= head.save[bid]; michael@0: h.save = head.save[bid]; michael@0: } else { michael@0: h = head; michael@0: bid = h.id; michael@0: } michael@0: if (inLoopHead) { michael@0: inLoopHead = false; michael@0: } else { michael@0: if (loop && !loop.body.get(bid)) { michael@0: h.npredecessors += h.save; michael@0: loop.exit.set(bid); michael@0: loop.save[bid] = (loop.save[bid] || 0) + h.save; michael@0: v.push(new Control.Break(bid, loop)); michael@0: break; michael@0: } michael@0: if (loop && h.loop === loop) { michael@0: h.npredecessors += h.save; michael@0: v.push(new Control.Continue(bid, loop)); michael@0: break; michael@0: } michael@0: if (h === fallthrough) { michael@0: break; michael@0: } michael@0: if (h.npredecessors > 0) { michael@0: h.npredecessors += h.save; michael@0: save[bid] = (save[bid] || 0) + h.save; michael@0: exit.set(bid); michael@0: v.push(lookupSwitch ? new Control.Break(bid, lookupSwitch) : new Control.Exit(bid)); michael@0: break; michael@0: } michael@0: if (h.loop) { michael@0: var l = h.loop; michael@0: var body; michael@0: if (l.head.count === 1) { michael@0: body = induce(l.head.choose(), null, null, l, true); michael@0: } else { michael@0: var lcases = []; michael@0: var lheads = l.head.members(); michael@0: for (var i = 0, j = lheads.length; i < j; i++) { michael@0: var lh = lheads[i]; michael@0: var lbid = lh.id; michael@0: var c = induce(lh, null, null, l, true); michael@0: lcases.push(new Control.LabelCase([ michael@0: lbid michael@0: ], c)); michael@0: } michael@0: body = new Control.LabelSwitch(lcases); michael@0: } michael@0: v.push(new Control.Loop(body)); michael@0: head = maybe(l.exit, l.save); michael@0: continue; michael@0: } michael@0: } michael@0: var sv; michael@0: var successors; michael@0: var exit2 = new BlockSet(); michael@0: var save2 = {}; michael@0: if (hasExceptions && h.hasCatches) { michael@0: var allsuccessors = h.successors; michael@0: var catchsuccessors = []; michael@0: successors = []; michael@0: for (var i = 0, j = allsuccessors.length; i < j; i++) { michael@0: var s = allsuccessors[i]; michael@0: (s.exception ? catchsuccessors : successors).push(s); michael@0: } michael@0: var catches = []; michael@0: for (var i = 0, j = catchsuccessors.length; i < j; i++) { michael@0: var t = catchsuccessors[i]; michael@0: t.npredecessors -= 1; michael@0: t.save = 1; michael@0: var c = induce(t, exit2, save2, loop); michael@0: var ex = t.exception; michael@0: catches.push(new Control.Catch(ex.varName, ex.typeName, c)); michael@0: } michael@0: sv = new Control.Try(h, catches); michael@0: } else { michael@0: successors = h.successors; michael@0: sv = h; michael@0: } michael@0: if (successors.length > 2) { michael@0: var cases = []; michael@0: var targets = successors; michael@0: for (var i = targets.length - 1; i >= 0; i--) { michael@0: var t = targets[i]; michael@0: t.npredecessors -= 1; michael@0: t.save = 1; michael@0: c = induce(t, exit2, save2, loop, null, h, targets[i + 1]); michael@0: cases.unshift(new Control.Case(i, c)); michael@0: } michael@0: cases.top().index = undefined; michael@0: if (hasExceptions && h.hasCatches) { michael@0: sv.nothingThrownLabel = exceptionId; michael@0: sv = new Control.Switch(sv, cases, exceptionId++); michael@0: } else { michael@0: sv = new Control.Switch(sv, cases); michael@0: } michael@0: head = maybe(exit2, save2); michael@0: } else if (successors.length === 2) { michael@0: var branch1 = h.hasFlippedSuccessors ? successors[1] : successors[0]; michael@0: var branch2 = h.hasFlippedSuccessors ? successors[0] : successors[1]; michael@0: branch1.npredecessors -= 1; michael@0: branch1.save = 1; michael@0: var c1 = induce(branch1, exit2, save2, loop); michael@0: branch2.npredecessors -= 1; michael@0: branch2.save = 1; michael@0: var c2 = induce(branch2, exit2, save2, loop); michael@0: if (hasExceptions && h.hasCatches) { michael@0: sv.nothingThrownLabel = exceptionId; michael@0: sv = new Control.If(sv, c1, c2, exceptionId++); michael@0: } else { michael@0: sv = new Control.If(sv, c1, c2); michael@0: } michael@0: head = maybe(exit2, save2); michael@0: } else { michael@0: c = successors[0]; michael@0: if (c) { michael@0: if (hasExceptions && h.hasCatches) { michael@0: sv.nothingThrownLabel = c.id; michael@0: save2[c.id] = (save2[c.id] || 0) + 1; michael@0: exit2.set(c.id); michael@0: head = maybe(exit2, save2); michael@0: } else { michael@0: c.npredecessors -= 1; michael@0: c.save = 1; michael@0: head = c; michael@0: } michael@0: } else { michael@0: if (hasExceptions && h.hasCatches) { michael@0: sv.nothingThrownLabel = -1; michael@0: head = maybe(exit2, save2); michael@0: } else { michael@0: head = c; michael@0: } michael@0: } michael@0: } michael@0: v.push(sv); michael@0: } michael@0: if (v.length > 1) { michael@0: return new Control.Seq(v); michael@0: } michael@0: return v[0]; michael@0: } michael@0: var root = this.blocks[0]; michael@0: this.controlTree = induce(root, new BlockSet(), {}); michael@0: }, michael@0: restructureControlFlow: function restructureControlFlow() { michael@0: Timer.start('Restructure Control Flow'); michael@0: if (!this.markedLoops && !this.markLoops()) { michael@0: Timer.stop(); michael@0: return false; michael@0: } michael@0: this.induceControlTree(); michael@0: this.restructuredControlFlow = true; michael@0: Timer.stop(); michael@0: return true; michael@0: }, michael@0: trace: function (writer) { michael@0: function bid(node) { michael@0: return node.id; michael@0: } michael@0: function traceBlock(block) { michael@0: if (!block.dominator) { michael@0: writer.enter('block unreachable {'); michael@0: } else { michael@0: writer.enter('block ' + block.id + (block.successors.length > 0 ? ' -> ' + block.successors.map(bid).join(',') : '') + ' {'); michael@0: writer.writeLn('npredecessors'.padRight(' ', 10) + block.npredecessors); michael@0: writer.writeLn('idom'.padRight(' ', 10) + block.dominator.id); michael@0: writer.writeLn('domcs'.padRight(' ', 10) + block.dominatees.map(bid).join(',')); michael@0: if (block.frontier) { michael@0: writer.writeLn('frontier'.padRight(' ', 10) + '{' + block.frontier.toArray().join(',') + '}'); michael@0: } michael@0: writer.writeLn('level'.padRight(' ', 10) + block.level); michael@0: } michael@0: if (block.loop) { michael@0: writer.writeLn('loop'.padRight(' ', 10) + '{' + block.loop.body.toArray().join(',') + '}'); michael@0: writer.writeLn(' id'.padRight(' ', 10) + block.loop.id); michael@0: writer.writeLn(' head'.padRight(' ', 10) + '{' + block.loop.head.toArray().join(',') + '}'); michael@0: writer.writeLn(' exit'.padRight(' ', 10) + '{' + block.loop.exit.toArray().join(',') + '}'); michael@0: writer.writeLn(' npredecessors'.padRight(' ', 10) + block.loop.npredecessors); michael@0: } michael@0: writer.writeLn(''); michael@0: if (block.position >= 0) { michael@0: for (var bci = block.position; bci <= block.end.position; bci++) { michael@0: writer.writeLn(('' + bci).padRight(' ', 5) + bytecodes[bci]); michael@0: } michael@0: } else { michael@0: writer.writeLn('abstract'); michael@0: } michael@0: writer.leave('}'); michael@0: } michael@0: var bytecodes = this.bytecodes; michael@0: writer.enter('analysis {'); michael@0: writer.enter('cfg {'); michael@0: this.blocks.forEach(traceBlock); michael@0: writer.leave('}'); michael@0: if (this.controlTree) { michael@0: writer.enter('control-tree {'); michael@0: this.controlTree.trace(writer); michael@0: writer.leave('}'); michael@0: } michael@0: writer.leave('}'); michael@0: }, michael@0: traceCFG: makeVizTrace([ michael@0: { michael@0: fn: function (n) { michael@0: return n.successors || []; michael@0: }, michael@0: style: '' michael@0: } michael@0: ], [ michael@0: { michael@0: fn: function (n) { michael@0: return n.predecessors || []; michael@0: }, michael@0: style: '' michael@0: } michael@0: ]), michael@0: traceDJ: makeVizTrace([ michael@0: { michael@0: fn: function (n) { michael@0: return n.dominatees || []; michael@0: }, michael@0: style: 'style=dashed' michael@0: }, michael@0: { michael@0: fn: function (n) { michael@0: var crosses = new this.BlockSet(); michael@0: crosses.setBlocks(n.successors); michael@0: crosses.subtract(this.BlockSet.fromBlocks(n.dominatees)); michael@0: n.spbacks && crosses.subtract(n.spbacks); michael@0: return crosses.members(); michael@0: }, michael@0: style: '' michael@0: }, michael@0: { michael@0: fn: function (n) { michael@0: return n.spbacks ? n.spbacks.members() : []; michael@0: }, michael@0: style: 'style=bold' michael@0: } michael@0: ], [ michael@0: { michael@0: fn: function (n) { michael@0: return n.predecessors || []; michael@0: }, michael@0: style: '' michael@0: } michael@0: ], function (idFn, writer) { michael@0: var root = this.bytecodes[0]; michael@0: var worklist = [ michael@0: root michael@0: ]; michael@0: var n; michael@0: var level = root.level; michael@0: var currentLevel = []; michael@0: while (n = worklist.shift()) { michael@0: if (level != n.level) { michael@0: writer.writeLn('{rank=same; ' + currentLevel.map(function (n) { michael@0: return 'block_' + idFn(n); michael@0: }).join(' ') + '}'); michael@0: currentLevel.length = 0; michael@0: level = n.level; michael@0: } michael@0: currentLevel.push(n); michael@0: worklist.push.apply(worklist, n.dominatees); michael@0: } michael@0: }) michael@0: }; michael@0: function makeVizTrace(successorFns, predecessorFns, postHook) { michael@0: return function (writer, name, prefix) { michael@0: function idFn(n) { michael@0: return prefix + n.id; michael@0: } michael@0: var analysis = this; michael@0: function bindToThis(x) { michael@0: x.fn = x.fn.bind(analysis); michael@0: } michael@0: prefix = prefix || ''; michael@0: var bytecodes = this.bytecodes; michael@0: if (!bytecodes) { michael@0: return; michael@0: } michael@0: successorFns.forEach(bindToThis); michael@0: predecessorFns.forEach(bindToThis); michael@0: writeGraphViz(writer, name.toString(), bytecodes[0], idFn, function (n) { michael@0: return n.successors || []; michael@0: }, successorFns, predecessorFns, function (n) { michael@0: var str = 'Block: ' + n.id + '\\l'; michael@0: return str; michael@0: }, postHook && postHook.bind(this, idFn)); michael@0: }; michael@0: } michael@0: return Analysis; michael@0: }(); michael@0: exports.Control = Control; michael@0: exports.analyze = function (cfg) { michael@0: var analysis = new Analysis(cfg); michael@0: analysis.restructureControlFlow(); michael@0: return analysis.controlTree; michael@0: }; michael@0: }(typeof exports === 'undefined' ? Looper = {} : exports)); michael@0: (function (exports) { michael@0: var TRACE_REGISTER_ALLOCATOR = false; michael@0: var T = estransform; michael@0: var Node = T.Node; michael@0: var Identifier = T.Identifier; michael@0: var VariableDeclaration = T.VariableDeclaration; michael@0: var VariableDeclarator = T.VariableDeclarator; michael@0: var AssignmentExpression = T.AssignmentExpression; michael@0: var MemberExpression = T.MemberExpression; michael@0: var IfStatement = T.IfStatement; michael@0: var WhileStatement = T.WhileStatement; michael@0: var FunctionDeclaration = T.FunctionDeclaration; michael@0: var writer = new IndentingWriter(); michael@0: var LinearScan = function () { michael@0: function Interval(id, start, end) { michael@0: this.id = id; michael@0: this.start = start; michael@0: this.end = end; michael@0: } michael@0: Interval.prototype.toString = function () { michael@0: return '[' + this.start + ',' + this.end + ']'; michael@0: }; michael@0: function linearScan(intervals, maxRegisters) { michael@0: this.intervals = intervals.slice(0); michael@0: this.maxRegisters = maxRegisters; michael@0: } michael@0: linearScan.prototype.allocate = function () { michael@0: var intervals = this.intervals; michael@0: this.intervals.sort(function (a, b) { michael@0: return a.start - b.start; michael@0: }); michael@0: var active = new SortedList(function (a, b) { michael@0: return a.end - b.end; michael@0: }); michael@0: var maxRegisters = this.maxRegisters; michael@0: var freeRegisters = []; michael@0: for (var i = maxRegisters - 1; i >= 0; i--) { michael@0: freeRegisters.push('R' + i); michael@0: } michael@0: intervals.forEach(function (i) { michael@0: expireOldIntervals(i); michael@0: if (active.length === maxRegisters) { michael@0: notImplemented('Cannot Spill'); michael@0: } else { michael@0: i.register = freeRegisters.pop(); michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('Allocate: ' + i + ' ' + i.id + ' -> ' + i.register); michael@0: active.push(i); michael@0: } michael@0: }); michael@0: function expireOldIntervals(i) { michael@0: active.forEach(function (j) { michael@0: if (j.end >= i.start) { michael@0: return SortedList.RETURN; michael@0: } michael@0: freeRegisters.push(j.register); michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('Release: ' + j + ' -> ' + j.register); michael@0: return SortedList.DELETE; michael@0: }); michael@0: } michael@0: }; michael@0: linearScan.Interval = Interval; michael@0: return linearScan; michael@0: }(); michael@0: function allocateRegisters(program) { michael@0: var scan = T.makePass('scan', 'scanNode'); michael@0: var label = 0; michael@0: Node.prototype.scan = function (o) { michael@0: this.position = label++; michael@0: return scan.apply(this, o); michael@0: }; michael@0: var variables = []; michael@0: var variableIndexMap = {}; michael@0: var identifiers = []; michael@0: FunctionDeclaration.prototype.scan = function () { michael@0: this.params.forEach(function (identifier) { michael@0: if (!(identifier.name in variableIndexMap)) { michael@0: variableIndexMap[identifier.name] = variables.length; michael@0: variables.push(identifier.name); michael@0: } michael@0: }); michael@0: this.body.scan(); michael@0: return this; michael@0: }; michael@0: VariableDeclarator.prototype.scan = function () { michael@0: this.position = label++; michael@0: if (!(this.id.name in variableIndexMap)) { michael@0: variableIndexMap[this.id.name] = variables.length; michael@0: variables.push(this.id.name); michael@0: } michael@0: return this; michael@0: }; michael@0: AssignmentExpression.prototype.scan = function (o) { michael@0: this.left.scan(o); michael@0: this.right.scan(o); michael@0: this.position = label++; michael@0: return this; michael@0: }; michael@0: WhileStatement.prototype.scan = function (o) { michael@0: this.position = label++; michael@0: this.test.scan(o); michael@0: this.body.scan(o); michael@0: this.afterPosition = label++; michael@0: return this; michael@0: }; michael@0: program.scan(); michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('Local Variables: ' + variables); michael@0: var Set = BitSetFunctor(variables.length); michael@0: var Range = BitSetFunctor(label); michael@0: var ranges = []; michael@0: for (var i = 0; i < variables.length; i++) { michael@0: ranges.push(new Range()); michael@0: } michael@0: function fill(range) { michael@0: var start = -1; michael@0: for (var i = 0; i < range.length; i++) { michael@0: if (range.get(i)) { michael@0: start = i; michael@0: break; michael@0: } michael@0: } michael@0: for (var i = range.length - 1; i >= 0; i--) { michael@0: if (range.get(i)) { michael@0: end = i; michael@0: break; michael@0: } michael@0: } michael@0: for (var i = start; i < end; i++) { michael@0: range.set(i); michael@0: } michael@0: } michael@0: function getRange(range) { michael@0: var start = -1, end = -1; michael@0: for (var i = 0; i < range.length; i++) { michael@0: if (range.get(i)) { michael@0: start = i; michael@0: break; michael@0: } michael@0: } michael@0: for (var i = range.length - 1; i >= 0; i--) { michael@0: if (range.get(i)) { michael@0: end = i; michael@0: break; michael@0: } michael@0: } michael@0: return [ michael@0: start, michael@0: end michael@0: ]; michael@0: } michael@0: function use(set, name, position) { michael@0: var index = variableIndexMap[name]; michael@0: ranges[index].set(position); michael@0: set.set(index); michael@0: } michael@0: function def(set, name, position) { michael@0: var index = variableIndexMap[name]; michael@0: ranges[index].set(position); michael@0: set.clear(index); michael@0: } michael@0: Node.prototype.markLiveness = T.makePass('markLiveness', 'markLivenessNode', true); michael@0: Identifier.prototype.markLiveness = function (o) { michael@0: var name = this.name; michael@0: if (name === 'undefined') { michael@0: return this; michael@0: } michael@0: if (o && o.isProperty) { michael@0: return this; michael@0: } michael@0: if (!(name in variableIndexMap)) { michael@0: return this; michael@0: } michael@0: identifiers.push(this); michael@0: var live = o.live; michael@0: use(live, name, this.position); michael@0: return this; michael@0: }; michael@0: VariableDeclarator.prototype.markLiveness = function (o) { michael@0: var live = o.live; michael@0: identifiers.push(this.id); michael@0: return this; michael@0: }; michael@0: IfStatement.prototype.markLiveness = function (o) { michael@0: var a = o.live.clone(); michael@0: var b = o.live.clone(); michael@0: this.alternate && this.alternate.markLiveness({ michael@0: live: a michael@0: }); michael@0: this.consequent && this.consequent.markLiveness({ michael@0: live: b michael@0: }); michael@0: o.live.assign(a); michael@0: o.live._union(b); michael@0: this.test.markLiveness(o); michael@0: return this; michael@0: }; michael@0: WhileStatement.prototype.markLiveness = function (o) { michael@0: var a = o.live.clone(); michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('END OF LOOP: ' + a); michael@0: var afterPosition = this.afterPosition; michael@0: do { michael@0: var b = a.clone(); michael@0: this.body.markLiveness({ michael@0: live: a michael@0: }); michael@0: this.test.markLiveness({ michael@0: live: a michael@0: }); michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('TOP OF LOOP: ' + a); michael@0: var iterate = !b.equals(a); michael@0: if (iterate) { michael@0: TRACE_REGISTER_ALLOCATOR && writer.writeLn('ITERATE'); michael@0: a.forEach(function (i) { michael@0: ranges[i].set(afterPosition); michael@0: }); michael@0: } michael@0: } while (iterate); michael@0: o.live.assign(a); michael@0: return this; michael@0: }; michael@0: AssignmentExpression.prototype.markLiveness = function (o) { michael@0: this.right.markLiveness(o); michael@0: if (this.left instanceof Identifier) { michael@0: def(o.live, this.left.name, this.position); michael@0: identifiers.push(this.left); michael@0: } else { michael@0: this.left.markLiveness(o); michael@0: } michael@0: return this; michael@0: }; michael@0: MemberExpression.prototype.markLiveness = function (o) { michael@0: if (this.computed || !(this.property instanceof Identifier)) { michael@0: this.property.markLiveness(o); michael@0: } michael@0: this.object.markLiveness(o); michael@0: return this; michael@0: }; michael@0: program.markLiveness({ michael@0: live: new Set() michael@0: }); michael@0: var intervals = []; michael@0: for (var i = 0; i < ranges.length; i++) { michael@0: var r = getRange(ranges[i]); michael@0: intervals.push(new LinearScan.Interval(i, r[0], r[1])); michael@0: } michael@0: var allocator = new LinearScan(intervals, 1024); michael@0: allocator.allocate(); michael@0: var map = createEmptyObject(); michael@0: for (var i = 0; i < variables.length; i++) { michael@0: map[variables[i]] = intervals[i].register; michael@0: } michael@0: if (true) { michael@0: for (var i = 0; i < identifiers.length; i++) { michael@0: if (identifiers[i].patched) { michael@0: continue; michael@0: } michael@0: identifiers[i].name = map[identifiers[i].name]; michael@0: identifiers[i].patched = true; michael@0: } michael@0: } michael@0: if (TRACE_REGISTER_ALLOCATOR) { michael@0: for (var i = 0; i < ranges.length; i++) { michael@0: fill(ranges[i]); michael@0: writer.writeLn(String(i).padLeft(' ', 3) + ' ' + variables[i].padRight(' ', 5) + ': ' + ranges[i].toBitString('=', ' ') + ' ' + intervals[i].register); michael@0: } michael@0: } michael@0: return program; michael@0: } michael@0: Transform.transform = function (program) { michael@0: allocateRegisters(program); michael@0: }; michael@0: }(typeof exports === 'undefined' ? Transform = {} : exports)); michael@0: (function (exports) { michael@0: var T = estransform; michael@0: var Literal = T.Literal; michael@0: var Identifier = T.Identifier; michael@0: var VariableDeclaration = T.VariableDeclaration; michael@0: var VariableDeclarator = T.VariableDeclarator; michael@0: var MemberExpression = T.MemberExpression; michael@0: var BinaryExpression = T.BinaryExpression; michael@0: var CallExpression = T.CallExpression; michael@0: var AssignmentExpression = T.AssignmentExpression; michael@0: var ExpressionStatement = T.ExpressionStatement; michael@0: var ReturnStatement = T.ReturnStatement; michael@0: var FunctionDeclaration = T.FunctionDeclaration; michael@0: var ConditionalExpression = T.ConditionalExpression; michael@0: var ObjectExpression = T.ObjectExpression; michael@0: var ArrayExpression = T.ArrayExpression; michael@0: var UnaryExpression = T.UnaryExpression; michael@0: var NewExpression = T.NewExpression; michael@0: var Property = T.Property; michael@0: var BlockStatement = T.BlockStatement; michael@0: var ThisExpression = T.ThisExpression; michael@0: var ThrowStatement = T.ThrowStatement; michael@0: var IfStatement = T.IfStatement; michael@0: var WhileStatement = T.WhileStatement; michael@0: var BreakStatement = T.BreakStatement; michael@0: var ContinueStatement = T.ContinueStatement; michael@0: var SwitchStatement = T.SwitchStatement; michael@0: var SwitchCase = T.SwitchCase; michael@0: var Block = IR.Block; michael@0: var Operator = IR.Operator; michael@0: var Projection = IR.Projection; michael@0: var Start = IR.Start; michael@0: var Control = Looper.Control; michael@0: var Variable = IR.Variable; michael@0: Control.Break.prototype.compile = function (cx, state) { michael@0: return cx.compileBreak(this, state); michael@0: }; michael@0: Control.Continue.prototype.compile = function (cx, state) { michael@0: return cx.compileContinue(this, state); michael@0: }; michael@0: Control.Exit.prototype.compile = function (cx, state) { michael@0: return cx.compileExit(this, state); michael@0: }; michael@0: Control.LabelSwitch.prototype.compile = function (cx, state) { michael@0: return cx.compileLabelSwitch(this, state); michael@0: }; michael@0: Control.Seq.prototype.compile = function (cx, state) { michael@0: return cx.compileSequence(this, state); michael@0: }; michael@0: Block.prototype.compile = function (cx, state) { michael@0: return cx.compileBlock(this, state); michael@0: }; michael@0: Control.Loop.prototype.compile = function (cx, state) { michael@0: return cx.compileLoop(this, state); michael@0: }; michael@0: Control.Switch.prototype.compile = function (cx, state) { michael@0: return cx.compileSwitch(this, state); michael@0: }; michael@0: Control.If.prototype.compile = function (cx, state) { michael@0: return cx.compileIf(this, state); michael@0: }; michael@0: Control.Try.prototype.compile = function (cx, state) { michael@0: return cx.compileTry(this, state); michael@0: }; michael@0: function constant(value) { michael@0: if (typeof value === 'string' || value === null || value === true || value === false) { michael@0: return new Literal(value); michael@0: } else if (value === undefined) { michael@0: return new Identifier('undefined'); michael@0: } else if (typeof value === 'object' || typeof value === 'function') { michael@0: return new Identifier(objectConstantName(value)); michael@0: } else if (typeof value === 'number' && isNaN(value)) { michael@0: return new Identifier('NaN'); michael@0: } else if (value === Infinity) { michael@0: return new Identifier('Infinity'); michael@0: } else if (value === -Infinity) { michael@0: return new UnaryExpression('-', new Identifier('Infinity')); michael@0: } else if (typeof value === 'number' && 1 / value < 0) { michael@0: return new UnaryExpression('-', new Literal(Math.abs(value))); michael@0: } else if (typeof value === 'number') { michael@0: return new Literal(value); michael@0: } else { michael@0: unexpected('Cannot emit constant for value: ', value); michael@0: } michael@0: } michael@0: function id(name) { michael@0: true; michael@0: return new Identifier(name); michael@0: } michael@0: function isIdentifierStart(c) { michael@0: return c === '$' || c === '_' || c === '\\' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; michael@0: } michael@0: function isIdentifierPart(c) { michael@0: return c === '$' || c === '_' || c === '\\' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'; michael@0: } michael@0: function isIdentifierName(s) { michael@0: if (!isIdentifierStart(s[0])) { michael@0: return false; michael@0: } michael@0: for (var i = 1; i < s.length; i++) { michael@0: if (!isIdentifierPart(s[i])) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: function property(obj) { michael@0: for (var i = 1; i < arguments.length; i++) { michael@0: var x = arguments[i]; michael@0: if (typeof x === 'string') { michael@0: if (isIdentifierName(x)) { michael@0: obj = new MemberExpression(obj, new Identifier(x), false); michael@0: } else { michael@0: obj = new MemberExpression(obj, new Literal(x), true); michael@0: } michael@0: } else if (x instanceof Literal && isIdentifierName(x.value)) { michael@0: obj = new MemberExpression(obj, new Identifier(x.value), false); michael@0: } else { michael@0: obj = new MemberExpression(obj, x, true); michael@0: } michael@0: } michael@0: return obj; michael@0: } michael@0: function call(callee, args) { michael@0: true; michael@0: true; michael@0: return new CallExpression(callee, args); michael@0: } michael@0: function callCall(callee, object, args) { michael@0: return call(property(callee, 'call'), [ michael@0: object michael@0: ].concat(args)); michael@0: } michael@0: function assignment(left, right) { michael@0: true; michael@0: return new AssignmentExpression(left, '=', right); michael@0: } michael@0: function variableDeclaration(declarations) { michael@0: return new VariableDeclaration('var', declarations); michael@0: } michael@0: function negate(node) { michael@0: if (node instanceof Constant) { michael@0: if (node.value === true || node.value === false) { michael@0: return constant(!node.value); michael@0: } michael@0: } else if (node instanceof Identifier) { michael@0: return new UnaryExpression(Operator.FALSE.name, node); michael@0: } michael@0: true; michael@0: var left = node instanceof BinaryExpression ? node.left : node.argument; michael@0: var right = node.right; michael@0: var operator = Operator.fromName(node.operator); michael@0: if (operator === Operator.EQ && right instanceof Literal && right.value === false) { michael@0: return left; michael@0: } michael@0: if (operator === Operator.FALSE) { michael@0: return left; michael@0: } michael@0: if (operator.not) { michael@0: if (node instanceof BinaryExpression) { michael@0: return new BinaryExpression(operator.not.name, left, right); michael@0: } else { michael@0: return new UnaryExpression(operator.not.name, left); michael@0: } michael@0: } michael@0: return new UnaryExpression(Operator.FALSE.name, node); michael@0: } michael@0: function Context() { michael@0: this.label = new Variable('$L'); michael@0: this.variables = []; michael@0: this.parameters = []; michael@0: } michael@0: Context.prototype.useVariable = function (variable) { michael@0: true; michael@0: return this.variables.pushUnique(variable); michael@0: }; michael@0: Context.prototype.useParameter = function (parameter) { michael@0: return this.parameters[parameter.index] = parameter; michael@0: }; michael@0: Context.prototype.compileLabelBody = function compileLabelBody(node) { michael@0: var body = []; michael@0: if (node.label !== undefined) { michael@0: this.useVariable(this.label); michael@0: body.push(new ExpressionStatement(assignment(id(this.label.name), new Literal(node.label)))); michael@0: } michael@0: return body; michael@0: }; michael@0: Context.prototype.compileBreak = function compileBreak(node) { michael@0: var body = this.compileLabelBody(node); michael@0: body.push(new BreakStatement(null)); michael@0: return new BlockStatement(body); michael@0: }; michael@0: Context.prototype.compileContinue = function compileContinue(node) { michael@0: var body = this.compileLabelBody(node); michael@0: body.push(new ContinueStatement(null)); michael@0: return new BlockStatement(body); michael@0: }; michael@0: Context.prototype.compileExit = function compileExit(node) { michael@0: return new BlockStatement(this.compileLabelBody(node)); michael@0: }; michael@0: Context.prototype.compileIf = function compileIf(node) { michael@0: var cr = node.cond.compile(this); michael@0: var tr = null, er = null; michael@0: if (node.then) { michael@0: tr = node.then.compile(this); michael@0: } michael@0: if (node.else) { michael@0: er = node.else.compile(this); michael@0: } michael@0: var condition = compileValue(cr.end.predicate, this); michael@0: condition = node.negated ? negate(condition) : condition; michael@0: cr.body.push(new IfStatement(condition, tr || new BlockStatement([]), er || null)); michael@0: return cr; michael@0: }; michael@0: Context.prototype.compileSwitch = function compileSwitch(node) { michael@0: var dr = node.determinant.compile(this); michael@0: var cases = []; michael@0: node.cases.forEach(function (x) { michael@0: var br; michael@0: if (x.body) { michael@0: br = x.body.compile(this); michael@0: } michael@0: var test = typeof x.index === 'number' ? new Literal(x.index) : undefined; michael@0: cases.push(new SwitchCase(test, br ? [ michael@0: br michael@0: ] : [])); michael@0: }, this); michael@0: var determinant = compileValue(dr.end.determinant, this); michael@0: dr.body.push(new SwitchStatement(determinant, cases, false)); michael@0: return dr; michael@0: }; michael@0: Context.prototype.compileLabelSwitch = function compileLabelSwitch(node) { michael@0: var statement = null; michael@0: var labelName = id(this.label.name); michael@0: function compileLabelTest(labelID) { michael@0: true; michael@0: return new BinaryExpression('===', labelName, new Literal(labelID)); michael@0: } michael@0: for (var i = node.cases.length - 1; i >= 0; i--) { michael@0: var c = node.cases[i]; michael@0: var labels = c.labels; michael@0: var labelTest = compileLabelTest(labels[0]); michael@0: for (var j = 1; j < labels.length; j++) { michael@0: labelTest = new BinaryExpression('||', labelTest, compileLabelTest(labels[j])); michael@0: } michael@0: statement = new IfStatement(labelTest, c.body ? c.body.compile(this) : new BlockStatement(), statement); michael@0: } michael@0: return statement; michael@0: }; michael@0: Context.prototype.compileLoop = function compileLoop(node) { michael@0: var br = node.body.compile(this); michael@0: return new WhileStatement(constant(true), br); michael@0: }; michael@0: Context.prototype.compileSequence = function compileSequence(node) { michael@0: var cx = this; michael@0: var body = []; michael@0: node.body.forEach(function (x) { michael@0: var result = x.compile(cx); michael@0: if (result instanceof BlockStatement) { michael@0: body = body.concat(result.body); michael@0: } else { michael@0: body.push(result); michael@0: } michael@0: }); michael@0: return new BlockStatement(body); michael@0: }; michael@0: Context.prototype.compileBlock = function compileBlock(block) { michael@0: var body = []; michael@0: for (var i = 1; i < block.nodes.length - 1; i++) { michael@0: var node = block.nodes[i]; michael@0: var statement; michael@0: var to; michael@0: var from; michael@0: if (node instanceof IR.Throw) { michael@0: statement = compileValue(node, this, true); michael@0: } else { michael@0: if (node instanceof IR.Move) { michael@0: to = id(node.to.name); michael@0: this.useVariable(node.to); michael@0: from = compileValue(node.from, this); michael@0: } else { michael@0: if (node.variable) { michael@0: to = id(node.variable.name); michael@0: this.useVariable(node.variable); michael@0: } else { michael@0: to = null; michael@0: } michael@0: from = compileValue(node, this, true); michael@0: } michael@0: if (to) { michael@0: statement = new ExpressionStatement(assignment(to, from)); michael@0: } else { michael@0: statement = new ExpressionStatement(from); michael@0: } michael@0: } michael@0: body.push(statement); michael@0: } michael@0: var end = block.nodes.last(); michael@0: if (end instanceof IR.Stop) { michael@0: body.push(new ReturnStatement(compileValue(end.argument, this))); michael@0: } michael@0: var result = new BlockStatement(body); michael@0: result.end = block.nodes.last(); michael@0: true; michael@0: return result; michael@0: }; michael@0: function compileValue(value, cx, noVariable) { michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: if (noVariable || !value.variable) { michael@0: var node = value.compile(cx); michael@0: return node; michael@0: } michael@0: true; michael@0: return id(value.variable.name); michael@0: } michael@0: function compileMultiname(name, cx) { michael@0: return [ michael@0: compileValue(name.namespaces, cx), michael@0: compileValue(name.name, cx), michael@0: constant(name.flags) michael@0: ]; michael@0: } michael@0: function isArray(array) { michael@0: return array instanceof Array; michael@0: } michael@0: function compileValues(values, cx) { michael@0: true; michael@0: return values.map(function (value) { michael@0: return compileValue(value, cx); michael@0: }); michael@0: } michael@0: IR.Parameter.prototype.compile = function (cx) { michael@0: cx.useParameter(this); michael@0: return id(this.name); michael@0: }; michael@0: IR.Constant.prototype.compile = function (cx) { michael@0: return constant(this.value); michael@0: }; michael@0: IR.Variable.prototype.compile = function (cx) { michael@0: return id(this.name); michael@0: }; michael@0: IR.Phi.prototype.compile = function (cx) { michael@0: true; michael@0: return compileValue(this.variable, cx); michael@0: }; michael@0: IR.ASScope.prototype.compile = function (cx) { michael@0: var parent = compileValue(this.parent, cx); michael@0: var object = compileValue(this.object, cx); michael@0: var isWith = new Literal(this.isWith); michael@0: return new NewExpression(id('Scope'), [ michael@0: parent, michael@0: object, michael@0: isWith michael@0: ]); michael@0: }; michael@0: IR.ASFindProperty.prototype.compile = function (cx) { michael@0: var scope = compileValue(this.scope, cx); michael@0: var name = compileMultiname(this.name, cx); michael@0: var domain = compileValue(this.domain, cx); michael@0: var strict = new Literal(this.strict); michael@0: return call(property(scope, 'findScopeProperty'), name.concat([ michael@0: domain, michael@0: strict michael@0: ])); michael@0: }; michael@0: IR.ASGetProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: if (this.flags & IR.Flags.INDEXED) { michael@0: true; michael@0: return call(property(object, 'asGetNumericProperty'), [ michael@0: compileValue(this.name.name, cx) michael@0: ]); michael@0: } else if (this.flags & IR.Flags.RESOLVED) { michael@0: return call(property(object, 'asGetResolvedStringProperty'), [ michael@0: compileValue(this.name, cx) michael@0: ]); michael@0: } michael@0: var name = compileMultiname(this.name, cx); michael@0: var isMethod = new Literal(this.flags & IR.Flags.IS_METHOD); michael@0: return call(property(object, 'asGetProperty'), name.concat(isMethod)); michael@0: }; michael@0: IR.ASGetSuper.prototype.compile = function (cx) { michael@0: var scope = compileValue(this.scope, cx); michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asGetSuper'), [ michael@0: scope michael@0: ].concat(name)); michael@0: }; michael@0: IR.Latch.prototype.compile = function (cx) { michael@0: return new ConditionalExpression(compileValue(this.condition, cx), compileValue(this.left, cx), compileValue(this.right, cx)); michael@0: }; michael@0: IR.Unary.prototype.compile = function (cx) { michael@0: return new UnaryExpression(this.operator.name, compileValue(this.argument, cx)); michael@0: }; michael@0: IR.Copy.prototype.compile = function (cx) { michael@0: return compileValue(this.argument, cx); michael@0: }; michael@0: IR.Binary.prototype.compile = function (cx) { michael@0: var left = compileValue(this.left, cx); michael@0: var right = compileValue(this.right, cx); michael@0: if (this.operator === Operator.AS_ADD) { michael@0: return call(id('asAdd'), [ michael@0: left, michael@0: right michael@0: ]); michael@0: } michael@0: return new BinaryExpression(this.operator.name, left, right); michael@0: }; michael@0: IR.CallProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: var callee = property(object, name); michael@0: var args = this.args.map(function (arg) { michael@0: return compileValue(arg, cx); michael@0: }); michael@0: if (this.flags & IR.Flags.PRISTINE) { michael@0: return call(callee, args); michael@0: } else { michael@0: return callCall(callee, object, args); michael@0: } michael@0: }; michael@0: IR.ASCallProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var args = this.args.map(function (arg) { michael@0: return compileValue(arg, cx); michael@0: }); michael@0: if (this.flags & IR.Flags.RESOLVED) { michael@0: return call(property(object, 'asCallResolvedStringProperty'), [ michael@0: compileValue(this.name, cx), michael@0: new Literal(this.isLex), michael@0: new ArrayExpression(args) michael@0: ]); michael@0: } michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asCallProperty'), name.concat([ michael@0: new Literal(this.isLex), michael@0: new ArrayExpression(args) michael@0: ])); michael@0: }; michael@0: IR.ASCallSuper.prototype.compile = function (cx) { michael@0: var scope = compileValue(this.scope, cx); michael@0: var object = compileValue(this.object, cx); michael@0: var args = this.args.map(function (arg) { michael@0: return compileValue(arg, cx); michael@0: }); michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asCallSuper'), [ michael@0: scope michael@0: ].concat(name).concat(new ArrayExpression(args))); michael@0: }; michael@0: IR.Call.prototype.compile = function (cx) { michael@0: var args = this.args.map(function (arg) { michael@0: return compileValue(arg, cx); michael@0: }); michael@0: var callee = compileValue(this.callee, cx); michael@0: var object; michael@0: if (this.object) { michael@0: object = compileValue(this.object, cx); michael@0: } else { michael@0: object = new Literal(null); michael@0: } michael@0: if (false && this.pristine && (this.callee instanceof IR.GetProperty && this.callee.object === this.object) || this.object === null) { michael@0: return call(callee, args); michael@0: } else { michael@0: return callCall(callee, object, args); michael@0: } michael@0: }; michael@0: IR.ASNew.prototype.compile = function (cx) { michael@0: var args = this.args.map(function (arg) { michael@0: return compileValue(arg, cx); michael@0: }); michael@0: var callee = compileValue(this.callee, cx); michael@0: callee = property(callee, 'instanceConstructor'); michael@0: return new NewExpression(callee, args); michael@0: }; michael@0: IR.This.prototype.compile = function (cx) { michael@0: return new ThisExpression(); michael@0: }; michael@0: IR.Throw.prototype.compile = function (cx) { michael@0: var argument = compileValue(this.argument, cx); michael@0: return new ThrowStatement(argument); michael@0: }; michael@0: IR.Arguments.prototype.compile = function (cx) { michael@0: return id('arguments'); michael@0: }; michael@0: IR.ASGlobal.prototype.compile = function (cx) { michael@0: var scope = compileValue(this.scope, cx); michael@0: return property(scope, 'global', 'object'); michael@0: }; michael@0: IR.ASSetProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var value = compileValue(this.value, cx); michael@0: if (this.flags & IR.Flags.INDEXED) { michael@0: return call(property(object, 'asSetNumericProperty'), [ michael@0: compileValue(this.name.name, cx), michael@0: value michael@0: ]); michael@0: } michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asSetProperty'), name.concat(value)); michael@0: }; michael@0: IR.ASSetSuper.prototype.compile = function (cx) { michael@0: var scope = compileValue(this.scope, cx); michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileMultiname(this.name, cx); michael@0: var value = compileValue(this.value, cx); michael@0: return call(property(object, 'asSetSuper'), [ michael@0: scope michael@0: ].concat(name).concat([ michael@0: value michael@0: ])); michael@0: }; michael@0: IR.ASDeleteProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asDeleteProperty'), name); michael@0: }; michael@0: IR.ASHasProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileMultiname(this.name, cx); michael@0: return call(property(object, 'asHasProperty'), name); michael@0: }; michael@0: IR.GlobalProperty.prototype.compile = function (cx) { michael@0: return id(this.name); michael@0: }; michael@0: IR.GetProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: return property(object, name); michael@0: }; michael@0: IR.SetProperty.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: var value = compileValue(this.value, cx); michael@0: return assignment(property(object, name), value); michael@0: }; michael@0: IR.ASGetDescendants.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: return call(id('getDescendants'), [ michael@0: object, michael@0: name michael@0: ]); michael@0: }; michael@0: IR.ASSetSlot.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: var value = compileValue(this.value, cx); michael@0: return call(id('asSetSlot'), [ michael@0: object, michael@0: name, michael@0: value michael@0: ]); michael@0: }; michael@0: IR.ASGetSlot.prototype.compile = function (cx) { michael@0: var object = compileValue(this.object, cx); michael@0: var name = compileValue(this.name, cx); michael@0: return call(id('asGetSlot'), [ michael@0: object, michael@0: name michael@0: ]); michael@0: }; michael@0: IR.Projection.prototype.compile = function (cx) { michael@0: true; michael@0: true; michael@0: return compileValue(this.argument.scope, cx); michael@0: }; michael@0: IR.NewArray.prototype.compile = function (cx) { michael@0: return new ArrayExpression(compileValues(this.elements, cx)); michael@0: }; michael@0: IR.NewObject.prototype.compile = function (cx) { michael@0: var properties = this.properties.map(function (property) { michael@0: var key = compileValue(property.key, cx); michael@0: var value = compileValue(property.value, cx); michael@0: return new Property(key, value, 'init'); michael@0: }); michael@0: return new ObjectExpression(properties); michael@0: }; michael@0: IR.ASNewActivation.prototype.compile = function (cx) { michael@0: var methodInfo = compileValue(this.methodInfo, cx); michael@0: return call(id('asCreateActivation'), [ michael@0: methodInfo michael@0: ]); michael@0: }; michael@0: IR.ASMultiname.prototype.compile = function (cx) { michael@0: var namespaces = compileValue(this.namespaces, cx); michael@0: var name = compileValue(this.name, cx); michael@0: return call(id('createName'), [ michael@0: namespaces, michael@0: name michael@0: ]); michael@0: }; michael@0: function generateSource(node) { michael@0: return escodegen.generate(node, { michael@0: base: '', michael@0: indent: ' ', michael@0: comment: true, michael@0: format: { michael@0: compact: false michael@0: } michael@0: }); michael@0: } michael@0: function generate(cfg, useRegisterAllocator) { michael@0: Timer.start('Looper'); michael@0: var root = Looper.analyze(cfg); michael@0: Timer.stop(); michael@0: var writer = new IndentingWriter(); michael@0: var cx = new Context(); michael@0: Timer.start('Construct AST'); michael@0: var code = root.compile(cx); michael@0: Timer.stop(); michael@0: var parameters = []; michael@0: for (var i = 0; i < cx.parameters.length; i++) { michael@0: var name = cx.parameters[i] ? cx.parameters[i].name : '_' + i; michael@0: parameters.push(id(name)); michael@0: } michael@0: if (cx.variables.length) { michael@0: Counter.count('Backend: Locals', cx.variables.length); michael@0: var variables = variableDeclaration(cx.variables.map(function (variable) { michael@0: return new VariableDeclarator(id(variable.name)); michael@0: })); michael@0: code.body.unshift(variables); michael@0: } michael@0: var node = new FunctionDeclaration(id('fn'), parameters, code); michael@0: if (useRegisterAllocator) { michael@0: if (c4TraceLevel.value > 0) { michael@0: writer.writeLn('=== BEFORE ==============================='); michael@0: writer.writeLn(generateSource(node)); michael@0: writer.writeLn('=== TRANSFORMING ========================='); michael@0: } michael@0: Transform.transform(node); michael@0: if (c4TraceLevel.value > 0) { michael@0: writer.writeLn('=== AFTER ================================'); michael@0: writer.writeLn(generateSource(node)); michael@0: writer.writeLn('=========================================='); michael@0: } michael@0: var body = generateSource(code); michael@0: return { michael@0: parameters: parameters.map(function (p) { michael@0: return p.name; michael@0: }), michael@0: body: body michael@0: }; michael@0: } michael@0: Timer.start('Serialize AST'); michael@0: var source = generateSource(code); michael@0: Timer.stop(); michael@0: return { michael@0: parameters: parameters.map(function (p) { michael@0: return p.name; michael@0: }), michael@0: body: source michael@0: }; michael@0: } michael@0: Backend.generate = generate; michael@0: }(typeof exports === 'undefined' ? Backend = {} : exports)); michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var Trait = Shumway.AVM2.ABC.Trait; michael@0: var IndentingWriter = Shumway.IndentingWriter; michael@0: var createMap = Shumway.ObjectUtilities.createMap; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var bindSafely = Shumway.FunctionUtilities.bindSafely; michael@0: var vmNextTrampolineId = 1; michael@0: var vmNextMemoizerId = 1; michael@0: function getMethodOverrideKey(methodInfo) { michael@0: var key; michael@0: if (methodInfo.holder instanceof ClassInfo) { michael@0: key = 'static ' + methodInfo.holder.instanceInfo.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); michael@0: } else if (methodInfo.holder instanceof InstanceInfo) { michael@0: key = methodInfo.holder.name.getOriginalName() + '::' + methodInfo.name.getOriginalName(); michael@0: } else { michael@0: key = methodInfo.name.getOriginalName(); michael@0: } michael@0: return key; michael@0: } michael@0: Runtime.getMethodOverrideKey = getMethodOverrideKey; michael@0: function checkMethodOverrides(methodInfo) { michael@0: if (methodInfo.name) { michael@0: var key = getMethodOverrideKey(methodInfo); michael@0: if (key in Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES) { michael@0: Shumway.Debug.warning('Overriding Method: ' + key); michael@0: return Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES[key]; michael@0: } michael@0: } michael@0: } michael@0: Runtime.checkMethodOverrides = checkMethodOverrides; michael@0: function makeTrampoline(forward, parameterLength, description) { michael@0: true; michael@0: return function trampolineContext() { michael@0: var target = null; michael@0: var trampoline = function execute() { michael@0: if (Shumway.AVM2.Runtime.traceExecution.value >= 3) { michael@0: log('Trampolining'); michael@0: } michael@0: Counter.count('Executing Trampoline'); michael@0: Shumway.AVM2.Runtime.traceCallExecution.value > 1 && callWriter.writeLn('Trampoline: ' + description); michael@0: if (!target) { michael@0: target = forward(trampoline); michael@0: true; michael@0: } michael@0: return target.apply(this, arguments); michael@0: }; michael@0: trampoline.trigger = function trigger() { michael@0: Counter.count('Triggering Trampoline'); michael@0: if (!target) { michael@0: target = forward(trampoline); michael@0: true; michael@0: } michael@0: }; michael@0: trampoline.isTrampoline = true; michael@0: trampoline.debugName = 'Trampoline #' + vmNextTrampolineId++; michael@0: defineReadOnlyProperty(trampoline, Shumway.AVM2.Runtime.VM_LENGTH, parameterLength); michael@0: return trampoline; michael@0: }(); michael@0: } michael@0: Runtime.makeTrampoline = makeTrampoline; michael@0: function makeMemoizer(qn, target) { michael@0: function memoizer() { michael@0: Counter.count('Runtime: Memoizing'); michael@0: if (Shumway.AVM2.Runtime.traceExecution.value >= 3) { michael@0: log('Memoizing: ' + qn); michael@0: } michael@0: Shumway.AVM2.Runtime.traceCallExecution.value > 1 && callWriter.writeLn('Memoizing: ' + qn); michael@0: if (Shumway.AVM2.Runtime.isNativePrototype(this)) { michael@0: Counter.count('Runtime: Method Closures'); michael@0: return bindSafely(target.value, this); michael@0: } michael@0: if (isTrampoline(target.value)) { michael@0: target.value.trigger(); michael@0: } michael@0: true; michael@0: var mc = null; michael@0: if (Shumway.AVM2.Runtime.isClass(this)) { michael@0: Counter.count('Runtime: Static Method Closures'); michael@0: mc = bindSafely(target.value, this); michael@0: defineReadOnlyProperty(this, qn, mc); michael@0: return mc; michael@0: } michael@0: if (Object.prototype.hasOwnProperty.call(this, qn)) { michael@0: var pd = Object.getOwnPropertyDescriptor(this, qn); michael@0: if (pd.get) { michael@0: Counter.count('Runtime: Method Closures'); michael@0: return bindSafely(target.value, this); michael@0: } michael@0: Counter.count('Runtime: Unpatched Memoizer'); michael@0: return this[qn]; michael@0: } michael@0: mc = bindSafely(target.value, this); michael@0: mc.methodInfo = target.value.methodInfo; michael@0: defineReadOnlyProperty(mc, Multiname.getPublicQualifiedName('prototype'), null); michael@0: defineReadOnlyProperty(this, qn, mc); michael@0: return mc; michael@0: } michael@0: var m = memoizer; michael@0: Counter.count('Runtime: Memoizers'); michael@0: m.isMemoizer = true; michael@0: m.debugName = 'Memoizer #' + vmNextMemoizerId++; michael@0: return m; michael@0: } michael@0: Runtime.makeMemoizer = makeMemoizer; michael@0: function isTrampoline(fn) { michael@0: true; michael@0: return fn.isTrampoline; michael@0: } michael@0: Runtime.isTrampoline = isTrampoline; michael@0: function isMemoizer(fn) { michael@0: true; michael@0: return fn.isMemoizer; michael@0: } michael@0: Runtime.isMemoizer = isMemoizer; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var __extends = this.__extends || function (d, b) { michael@0: for (var p in b) michael@0: if (b.hasOwnProperty(p)) michael@0: d[p] = b[p]; michael@0: function __() { michael@0: this.constructor = d; michael@0: } michael@0: __.prototype = b.prototype; michael@0: d.prototype = new __(); michael@0: }; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo; michael@0: var Trait = Shumway.AVM2.ABC.Trait; michael@0: var IndentingWriter = Shumway.IndentingWriter; michael@0: var hasOwnProperty = Shumway.ObjectUtilities.hasOwnProperty; michael@0: var createMap = Shumway.ObjectUtilities.createMap; michael@0: var cloneObject = Shumway.ObjectUtilities.cloneObject; michael@0: var copyProperties = Shumway.ObjectUtilities.copyProperties; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var bindSafely = Shumway.FunctionUtilities.bindSafely; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter; michael@0: var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter; michael@0: var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter; michael@0: var Binding = function () { michael@0: function Binding(trait) { michael@0: this.trait = trait; michael@0: } michael@0: Binding.getKey = function (qn, trait) { michael@0: var key = qn; michael@0: if (trait.isGetter()) { michael@0: key = Binding.GET_PREFIX + qn; michael@0: } else if (trait.isSetter()) { michael@0: key = Binding.SET_PREFIX + qn; michael@0: } michael@0: return key; michael@0: }; michael@0: Binding.prototype.toString = function () { michael@0: return String(this.trait); michael@0: }; michael@0: Binding.SET_PREFIX = 'set '; michael@0: Binding.GET_PREFIX = 'get '; michael@0: Binding.KEY_PREFIX_LENGTH = 4; michael@0: return Binding; michael@0: }(); michael@0: Runtime.Binding = Binding; michael@0: var SlotInfo = function () { michael@0: function SlotInfo(name, isConst, type, trait) { michael@0: this.name = name; michael@0: this.isConst = isConst; michael@0: this.type = type; michael@0: this.trait = trait; michael@0: } michael@0: return SlotInfo; michael@0: }(); michael@0: Runtime.SlotInfo = SlotInfo; michael@0: var SlotInfoMap = function () { michael@0: function SlotInfoMap() { michael@0: this.byID = createMap(); michael@0: this.byQN = createMap(); michael@0: } michael@0: return SlotInfoMap; michael@0: }(); michael@0: Runtime.SlotInfoMap = SlotInfoMap; michael@0: var Bindings = function () { michael@0: function Bindings() { michael@0: this.map = createMap(); michael@0: this.slots = []; michael@0: this.nextSlotId = 1; michael@0: } michael@0: Bindings.prototype.assignNextSlot = function (trait) { michael@0: true; michael@0: true; michael@0: if (!trait.slotId) { michael@0: trait.slotId = this.nextSlotId++; michael@0: } else { michael@0: this.nextSlotId = trait.slotId + 1; michael@0: } michael@0: true; michael@0: this.slots[trait.slotId] = trait; michael@0: }; michael@0: Bindings.prototype.trace = function (writer) { michael@0: writer.enter('Bindings'); michael@0: for (var key in this.map) { michael@0: var binding = this.map[key]; michael@0: writer.writeLn(binding.trait.kindName() + ': ' + key + ' -> ' + binding); michael@0: } michael@0: writer.leaveAndEnter('Slots'); michael@0: writer.writeArray(this.slots); michael@0: writer.outdent(); michael@0: }; michael@0: Bindings.prototype.applyTo = function (domain, object) { michael@0: true; michael@0: true; michael@0: true; michael@0: defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_SLOTS, new SlotInfoMap()); michael@0: defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_BINDINGS, []); michael@0: defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_OPEN_METHODS, createMap()); michael@0: defineNonEnumerableProperty(object, 'bindings', this); michael@0: defineNonEnumerableProperty(object, 'resolutionMap', []); michael@0: traitsWriter && traitsWriter.greenLn('Applying Traits'); michael@0: for (var key in this.map) { michael@0: var binding = this.map[key]; michael@0: var trait = binding.trait; michael@0: var qn = Multiname.getQualifiedName(trait.name); michael@0: if (trait.isSlot() || trait.isConst() || trait.isClass()) { michael@0: var defaultValue = undefined; michael@0: if (trait.isSlot() || trait.isConst()) { michael@0: if (trait.hasDefaultValue) { michael@0: defaultValue = trait.value; michael@0: } else if (trait.typeName) { michael@0: defaultValue = domain.findClassInfo(trait.typeName).defaultValue; michael@0: } michael@0: } michael@0: if (key !== qn) { michael@0: traitsWriter && traitsWriter.yellowLn('Binding Trait: ' + key + ' -> ' + qn); michael@0: defineNonEnumerableGetter(object, key, makeForwardingGetter(qn)); michael@0: object.asBindings.pushUnique(key); michael@0: } else { michael@0: traitsWriter && traitsWriter.greenLn('Applying Trait ' + trait.kindName() + ': ' + trait); michael@0: defineNonEnumerableProperty(object, qn, defaultValue); michael@0: object.asBindings.pushUnique(qn); michael@0: var slotInfo = new SlotInfo(qn, trait.isConst(), trait.typeName ? domain.getProperty(trait.typeName, false, false) : null, trait); michael@0: object.asSlots.byID[trait.slotId] = slotInfo; michael@0: object.asSlots.byQN[qn] = slotInfo; michael@0: } michael@0: } else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: if (trait.isGetter() || trait.isSetter()) { michael@0: key = key.substring(Binding.KEY_PREFIX_LENGTH); michael@0: } michael@0: if (key !== qn) { michael@0: traitsWriter && traitsWriter.yellowLn('Binding Trait: ' + key + ' -> ' + qn); michael@0: } else { michael@0: traitsWriter && traitsWriter.greenLn('Applying Trait ' + trait.kindName() + ': ' + trait); michael@0: } michael@0: object.asBindings.pushUnique(key); michael@0: if (this instanceof ScriptBindings) { michael@0: Shumway.AVM2.Runtime.applyNonMemoizedMethodTrait(key, trait, object, binding.scope, binding.natives); michael@0: } else { michael@0: Shumway.AVM2.Runtime.applyMemoizedMethodTrait(key, trait, object, binding.scope, binding.natives); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return Bindings; michael@0: }(); michael@0: Runtime.Bindings = Bindings; michael@0: var ActivationBindings = function (_super) { michael@0: __extends(ActivationBindings, _super); michael@0: function ActivationBindings(methodInfo) { michael@0: _super.call(this); michael@0: true; michael@0: this.methodInfo = methodInfo; michael@0: var traits = methodInfo.traits; michael@0: for (var i = 0; i < traits.length; i++) { michael@0: var trait = traits[i]; michael@0: true; michael@0: var key = Multiname.getQualifiedName(trait.name); michael@0: this.map[key] = new Binding(trait); michael@0: this.assignNextSlot(trait); michael@0: } michael@0: } michael@0: return ActivationBindings; michael@0: }(Bindings); michael@0: Runtime.ActivationBindings = ActivationBindings; michael@0: var CatchBindings = function (_super) { michael@0: __extends(CatchBindings, _super); michael@0: function CatchBindings(scope, trait) { michael@0: _super.call(this); michael@0: var key = Multiname.getQualifiedName(trait.name); michael@0: this.map[key] = new Binding(trait); michael@0: true; michael@0: this.assignNextSlot(trait); michael@0: } michael@0: return CatchBindings; michael@0: }(Bindings); michael@0: Runtime.CatchBindings = CatchBindings; michael@0: var ScriptBindings = function (_super) { michael@0: __extends(ScriptBindings, _super); michael@0: function ScriptBindings(scriptInfo, scope) { michael@0: _super.call(this); michael@0: this.scope = scope; michael@0: this.scriptInfo = scriptInfo; michael@0: var traits = scriptInfo.traits; michael@0: for (var i = 0; i < traits.length; i++) { michael@0: var trait = traits[i]; michael@0: var name = Multiname.getQualifiedName(trait.name); michael@0: var key = Binding.getKey(name, trait); michael@0: var binding = this.map[key] = new Binding(trait); michael@0: if (trait.isSlot() || trait.isConst() || trait.isClass()) { michael@0: this.assignNextSlot(trait); michael@0: } michael@0: if (trait.isClass()) { michael@0: if (trait.metadata && trait.metadata.native) { michael@0: trait.classInfo.native = trait.metadata.native; michael@0: } michael@0: } michael@0: if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: binding.scope = this.scope; michael@0: } michael@0: } michael@0: } michael@0: return ScriptBindings; michael@0: }(Bindings); michael@0: Runtime.ScriptBindings = ScriptBindings; michael@0: var ClassBindings = function (_super) { michael@0: __extends(ClassBindings, _super); michael@0: function ClassBindings(classInfo, scope, natives) { michael@0: _super.call(this); michael@0: this.scope = scope; michael@0: this.natives = natives; michael@0: this.classInfo = classInfo; michael@0: var traits = classInfo.traits; michael@0: for (var i = 0; i < traits.length; i++) { michael@0: var trait = traits[i]; michael@0: var name = Multiname.getQualifiedName(trait.name); michael@0: var key = Binding.getKey(name, trait); michael@0: var binding = this.map[key] = new Binding(trait); michael@0: if (trait.isSlot() || trait.isConst()) { michael@0: this.assignNextSlot(trait); michael@0: } michael@0: if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: binding.scope = this.scope; michael@0: binding.natives = this.natives; michael@0: } michael@0: } michael@0: } michael@0: return ClassBindings; michael@0: }(Bindings); michael@0: Runtime.ClassBindings = ClassBindings; michael@0: var InstanceBindings = function (_super) { michael@0: __extends(InstanceBindings, _super); michael@0: function InstanceBindings(parent, instanceInfo, scope, natives) { michael@0: _super.call(this); michael@0: this.scope = scope; michael@0: this.natives = natives; michael@0: this.parent = parent; michael@0: this.instanceInfo = instanceInfo; michael@0: this.implementedInterfaces = parent ? cloneObject(parent.implementedInterfaces) : createEmptyObject(); michael@0: if (parent) { michael@0: this.slots = parent.slots.slice(); michael@0: this.nextSlotId = parent.nextSlotId; michael@0: } michael@0: this.extend(parent); michael@0: } michael@0: InstanceBindings.prototype.extend = function (parent) { michael@0: var ii = this.instanceInfo, ib; michael@0: var map = this.map; michael@0: var name, key, trait, binding, protectedName, protectedKey; michael@0: if (parent) { michael@0: for (key in parent.map) { michael@0: binding = parent.map[key]; michael@0: trait = binding.trait; michael@0: map[key] = binding; michael@0: if (trait.isProtected()) { michael@0: protectedName = Multiname.getQualifiedName(new Multiname([ michael@0: ii.protectedNs michael@0: ], trait.name.getName())); michael@0: protectedKey = Binding.getKey(protectedName, trait); michael@0: map[protectedKey] = binding; michael@0: } michael@0: } michael@0: } michael@0: function writeOrOverwriteBinding(object, key, binding) { michael@0: var trait = binding.trait; michael@0: var oldBinding = object[key]; michael@0: if (oldBinding) { michael@0: var oldTrait = oldBinding.trait; michael@0: true; michael@0: true; michael@0: } else { michael@0: true; michael@0: } michael@0: object[key] = binding; michael@0: } michael@0: function overwriteProtectedBinding(object, key, binding) { michael@0: if (key in object) { michael@0: object[key] = binding; michael@0: } michael@0: } michael@0: var traits = ii.traits; michael@0: for (var i = 0; i < traits.length; i++) { michael@0: trait = traits[i]; michael@0: name = Multiname.getQualifiedName(trait.name); michael@0: key = Binding.getKey(name, trait); michael@0: binding = new Binding(trait); michael@0: writeOrOverwriteBinding(map, key, binding); michael@0: if (trait.isProtected()) { michael@0: ib = this.parent; michael@0: while (ib) { michael@0: protectedName = Multiname.getQualifiedName(new Multiname([ michael@0: ib.instanceInfo.protectedNs michael@0: ], trait.name.getName())); michael@0: protectedKey = Binding.getKey(protectedName, trait); michael@0: overwriteProtectedBinding(map, protectedKey, binding); michael@0: ib = ib.parent; michael@0: } michael@0: } michael@0: if (trait.isSlot() || trait.isConst()) { michael@0: this.assignNextSlot(trait); michael@0: } michael@0: if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: binding.scope = this.scope; michael@0: binding.natives = this.natives; michael@0: } michael@0: } michael@0: var domain = ii.abc.applicationDomain; michael@0: var interfaces = ii.interfaces; michael@0: for (var i = 0; i < interfaces.length; i++) { michael@0: var interface = domain.getProperty(interfaces[i], true, true); michael@0: true; michael@0: copyProperties(this.implementedInterfaces, interface.interfaceBindings.implementedInterfaces); michael@0: this.implementedInterfaces[Multiname.getQualifiedName(interface.name)] = interface; michael@0: } michael@0: for (var interfaceName in this.implementedInterfaces) { michael@0: var interface = this.implementedInterfaces[interfaceName]; michael@0: ib = interface.interfaceBindings; michael@0: for (var interfaceKey in ib.map) { michael@0: var interfaceBinding = ib.map[interfaceKey]; michael@0: if (ii.isInterface()) { michael@0: map[interfaceKey] = interfaceBinding; michael@0: } else { michael@0: name = Multiname.getPublicQualifiedName(interfaceBinding.trait.name.getName()); michael@0: key = Binding.getKey(name, interfaceBinding.trait); michael@0: map[interfaceKey] = map[key]; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: InstanceBindings.prototype.toString = function () { michael@0: return this.instanceInfo.toString(); michael@0: }; michael@0: return InstanceBindings; michael@0: }(Bindings); michael@0: Runtime.InstanceBindings = InstanceBindings; michael@0: var traitsWriter = null; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var Binding = Shumway.AVM2.Runtime.Binding; michael@0: var Bindings = Shumway.AVM2.Runtime.Bindings; michael@0: var ActivationBindings = Shumway.AVM2.Runtime.ActivationBindings; michael@0: var CatchBindings = Shumway.AVM2.Runtime.CatchBindings; michael@0: var ScriptBindings = Shumway.AVM2.Runtime.ScriptBindings; michael@0: var ClassBindings = Shumway.AVM2.Runtime.ClassBindings; michael@0: var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings; michael@0: var ClassBindings = Shumway.AVM2.Runtime.ClassBindings; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray; michael@0: var boxValue = Shumway.ObjectUtilities.boxValue; michael@0: function makeCacheKey(namespaces, name, flags) { michael@0: if (!namespaces) { michael@0: return name; michael@0: } else if (namespaces.length > 1) { michael@0: return namespaces.runtimeId + '$' + name; michael@0: } else { michael@0: return namespaces[0].qualifiedName + '$' + name; michael@0: } michael@0: } michael@0: var Scope = function () { michael@0: function Scope(parent, object, isWith) { michael@0: if (typeof isWith === 'undefined') { michael@0: isWith = false; michael@0: } michael@0: this.parent = parent; michael@0: this.object = boxValue(object); michael@0: true; michael@0: this.global = parent ? parent.global : this; michael@0: this.isWith = isWith; michael@0: this.cache = createEmptyObject(); michael@0: } michael@0: Scope.prototype.findDepth = function (object) { michael@0: var current = this; michael@0: var depth = 0; michael@0: while (current) { michael@0: if (current.object === object) { michael@0: return depth; michael@0: } michael@0: depth++; michael@0: current = current.parent; michael@0: } michael@0: return -1; michael@0: }; michael@0: Scope.prototype.getScopeObjects = function () { michael@0: var objects = []; michael@0: var current = this; michael@0: while (current) { michael@0: objects.unshift(current.object); michael@0: current = current.parent; michael@0: } michael@0: return objects; michael@0: }; michael@0: Scope.prototype.findScopeProperty = function (namespaces, name, flags, domain, strict, scopeOnly) { michael@0: Counter.count('findScopeProperty'); michael@0: var object; michael@0: var key = makeCacheKey(namespaces, name, flags); michael@0: if (!scopeOnly && (object = this.cache[key])) { michael@0: return object; michael@0: } michael@0: if (this.object.asHasProperty(namespaces, name, flags, true)) { michael@0: return this.isWith ? this.object : this.cache[key] = this.object; michael@0: } michael@0: if (this.parent) { michael@0: return this.cache[key] = this.parent.findScopeProperty(namespaces, name, flags, domain, strict, scopeOnly); michael@0: } michael@0: if (scopeOnly) michael@0: return null; michael@0: if (object = domain.findDomainProperty(new Multiname(namespaces, name, flags), strict, true)) { michael@0: return object; michael@0: } michael@0: if (strict) { michael@0: Shumway.Debug.unexpected('Cannot find property ' + name); michael@0: } michael@0: return this.global.object; michael@0: }; michael@0: return Scope; michael@0: }(); michael@0: Runtime.Scope = Scope; michael@0: function bindFreeMethodScope(methodInfo, scope) { michael@0: var fn = methodInfo.freeMethod; michael@0: if (methodInfo.lastBoundMethod && methodInfo.lastBoundMethod.scope === scope) { michael@0: return methodInfo.lastBoundMethod.boundMethod; michael@0: } michael@0: true; michael@0: var boundMethod; michael@0: var asGlobal = scope.global.object; michael@0: if (!methodInfo.hasOptional() && !methodInfo.needsArguments() && !methodInfo.needsRest()) { michael@0: switch (methodInfo.parameters.length) { michael@0: case 0: michael@0: boundMethod = function () { michael@0: return fn.call(this === jsGlobal ? asGlobal : this, scope); michael@0: }; michael@0: break; michael@0: case 1: michael@0: boundMethod = function (x) { michael@0: return fn.call(this === jsGlobal ? asGlobal : this, scope, x); michael@0: }; michael@0: break; michael@0: case 2: michael@0: boundMethod = function (x, y) { michael@0: return fn.call(this === jsGlobal ? asGlobal : this, scope, x, y); michael@0: }; michael@0: break; michael@0: case 3: michael@0: boundMethod = function (x, y, z) { michael@0: return fn.call(this === jsGlobal ? asGlobal : this, scope, x, y, z); michael@0: }; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: if (!boundMethod) { michael@0: Counter.count('Bind Scope - Slow Path'); michael@0: boundMethod = function () { michael@0: Array.prototype.unshift.call(arguments, scope); michael@0: var global = this === jsGlobal ? scope.global.object : this; michael@0: return fn.apply(global, arguments); michael@0: }; michael@0: } michael@0: boundMethod.methodInfo = methodInfo; michael@0: boundMethod.instanceConstructor = boundMethod; michael@0: methodInfo.lastBoundMethod = { michael@0: scope: scope, michael@0: boundMethod: boundMethod michael@0: }; michael@0: return boundMethod; michael@0: } michael@0: Runtime.bindFreeMethodScope = bindFreeMethodScope; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var playerglobalLoadedPromise; michael@0: var playerglobal; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var AbcFile = Shumway.AVM2.ABC.AbcFile; michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var IndentingWriter = Shumway.IndentingWriter; michael@0: (function (EXECUTION_MODE) { michael@0: EXECUTION_MODE[EXECUTION_MODE['INTERPRET'] = 1] = 'INTERPRET'; michael@0: EXECUTION_MODE[EXECUTION_MODE['COMPILE'] = 2] = 'COMPILE'; michael@0: }(Runtime.EXECUTION_MODE || (Runtime.EXECUTION_MODE = {}))); michael@0: var EXECUTION_MODE = Runtime.EXECUTION_MODE; michael@0: function createNewCompartment() { michael@0: return newGlobal('new-compartment'); michael@0: } michael@0: function executeScript(script) { michael@0: var abc = script.abc; michael@0: true; michael@0: var global = new Shumway.AVM2.Runtime.Global(script); michael@0: if (abc.applicationDomain.allowNatives) { michael@0: global[Multiname.getPublicQualifiedName('unsafeJSNative')] = getNative; michael@0: } michael@0: script.executing = true; michael@0: var scope = new Shumway.AVM2.Runtime.Scope(null, script.global); michael@0: createFunction(script.init, scope).call(script.global, false); michael@0: script.executed = true; michael@0: } michael@0: Runtime.executeScript = executeScript; michael@0: function ensureScriptIsExecuted(script, reason) { michael@0: if (typeof reason === 'undefined') { michael@0: reason = ''; michael@0: } michael@0: if (!script.executed && !script.executing) { michael@0: if (Shumway.AVM2.Runtime.traceExecution.value >= 2) { michael@0: log('Executing Script For: ' + reason); michael@0: } michael@0: executeScript(script); michael@0: } michael@0: } michael@0: Runtime.ensureScriptIsExecuted = ensureScriptIsExecuted; michael@0: (function (Glue) { michael@0: Glue[Glue['PUBLIC_PROPERTIES'] = 1] = 'PUBLIC_PROPERTIES'; michael@0: Glue[Glue['PUBLIC_METHODS'] = 2] = 'PUBLIC_METHODS'; michael@0: Glue[Glue['ALL'] = 1 | 2] = 'ALL'; michael@0: }(Runtime.Glue || (Runtime.Glue = {}))); michael@0: var Glue = Runtime.Glue; michael@0: function grabAbc(abcName) { michael@0: var entry = playerglobal.scripts[abcName]; michael@0: if (!entry) { michael@0: return null; michael@0: } michael@0: var offset = entry.offset; michael@0: var length = entry.length; michael@0: return new AbcFile(new Uint8Array(playerglobal.abcs, offset, length), abcName); michael@0: } michael@0: function findDefiningAbc(mn) { michael@0: if (!playerglobal) { michael@0: return null; michael@0: } michael@0: for (var i = 0; i < mn.namespaces.length; i++) { michael@0: var name = mn.namespaces[i].uri + ':' + mn.name; michael@0: var abcName = playerglobal.map[name]; michael@0: if (abcName) { michael@0: break; michael@0: } michael@0: } michael@0: if (abcName) { michael@0: return grabAbc(abcName); michael@0: } michael@0: return null; michael@0: } michael@0: function promiseFile(path, responseType) { michael@0: return new Promise(function (resolve, reject) { michael@0: var xhr = new XMLHttpRequest(); michael@0: xhr.open('GET', path); michael@0: xhr.responseType = responseType; michael@0: xhr.onload = function () { michael@0: if (xhr.response) { michael@0: resolve(xhr.response); michael@0: } else { michael@0: reject('Unable to load ' + path + ': ' + xhr.statusText); michael@0: } michael@0: }; michael@0: xhr.send(); michael@0: }); michael@0: } michael@0: var AVM2 = function () { michael@0: function AVM2(sysMode, appMode, loadAVM1) { michael@0: this.systemDomain = new ApplicationDomain(this, null, sysMode, true); michael@0: this.applicationDomain = new ApplicationDomain(this, this.systemDomain, appMode, false); michael@0: this.findDefiningAbc = findDefiningAbc; michael@0: this.loadAVM1 = loadAVM1; michael@0: this.isAVM1Loaded = false; michael@0: this.exception = { michael@0: value: undefined michael@0: }; michael@0: this.exceptions = []; michael@0: } michael@0: AVM2.initialize = function (sysMode, appMode, loadAVM1) { michael@0: AVM2.instance = new AVM2(sysMode, appMode, loadAVM1); michael@0: }; michael@0: AVM2.currentAbc = function () { michael@0: var caller = arguments.callee; michael@0: var maxDepth = 20; michael@0: var abc = null; michael@0: for (var i = 0; i < maxDepth && caller; i++) { michael@0: var mi = caller.methodInfo; michael@0: if (mi) { michael@0: abc = mi.abc; michael@0: break; michael@0: } michael@0: caller = caller.caller; michael@0: } michael@0: return abc; michael@0: }; michael@0: AVM2.currentDomain = function () { michael@0: var abc = AVM2.currentAbc(); michael@0: return abc.applicationDomain; michael@0: }; michael@0: AVM2.isPlayerglobalLoaded = function () { michael@0: return !(!playerglobal); michael@0: }; michael@0: AVM2.loadPlayerglobal = function (abcsPath, catalogPath) { michael@0: if (playerglobalLoadedPromise) { michael@0: return Promise.reject('Playerglobal is already loaded'); michael@0: } michael@0: playerglobalLoadedPromise = Promise.all([ michael@0: promiseFile(abcsPath, 'arraybuffer'), michael@0: promiseFile(catalogPath, 'json') michael@0: ]).then(function (result) { michael@0: playerglobal = { michael@0: abcs: result[0], michael@0: map: Object.create(null), michael@0: scripts: Object.create(null) michael@0: }; michael@0: var catalog = result[1]; michael@0: for (var i = 0; i < catalog.length; i++) { michael@0: var abc = catalog[i]; michael@0: playerglobal.scripts[abc.name] = abc; michael@0: if (typeof abc.defs === 'string') { michael@0: playerglobal.map[abc.defs] = abc.name; michael@0: } else { michael@0: for (var j = 0; j < abc.defs.length; j++) { michael@0: var def = abc.defs[j]; michael@0: playerglobal.map[def] = abc.name; michael@0: } michael@0: } michael@0: } michael@0: }, function (e) { michael@0: console.error(e); michael@0: }); michael@0: return playerglobalLoadedPromise; michael@0: }; michael@0: AVM2.prototype.notifyConstruct = function (instanceConstructor, args) { michael@0: }; michael@0: AVM2.getStackTrace = function () { michael@0: Shumway.Debug.notImplemented('getStackTrace'); michael@0: }; michael@0: return AVM2; michael@0: }(); michael@0: Runtime.AVM2 = AVM2; michael@0: var ApplicationDomain = function () { michael@0: function ApplicationDomain(vm, base, mode, allowNatives) { michael@0: true; michael@0: true; michael@0: this.vm = vm; michael@0: this.abcs = []; michael@0: this.loadedAbcs = {}; michael@0: this.loadedClasses = []; michael@0: this.classCache = createEmptyObject(); michael@0: this.scriptCache = createEmptyObject(); michael@0: this.classInfoCache = createEmptyObject(); michael@0: this.base = base; michael@0: this.allowNatives = allowNatives; michael@0: this.mode = mode; michael@0: this.onMessage = new Callback(); michael@0: if (base) { michael@0: this.system = base.system; michael@0: } else { michael@0: this.system = this; michael@0: } michael@0: } michael@0: ApplicationDomain.passthroughCallable = function (f) { michael@0: return { michael@0: call: function ($this) { michael@0: Array.prototype.shift.call(arguments); michael@0: return f.apply($this, arguments); michael@0: }, michael@0: apply: function ($this, args) { michael@0: return f.apply($this, args); michael@0: } michael@0: }; michael@0: }; michael@0: ApplicationDomain.coerceCallable = function (type) { michael@0: return { michael@0: call: function ($this, value) { michael@0: return Shumway.AVM2.Runtime.asCoerce(type, value); michael@0: }, michael@0: apply: function ($this, args) { michael@0: return Shumway.AVM2.Runtime.asCoerce(type, args[0]); michael@0: } michael@0: }; michael@0: }; michael@0: ApplicationDomain.constructingCallable = function (instanceConstructor) { michael@0: return { michael@0: call: function (self) { michael@0: return new (Function.bind.apply(instanceConstructor, arguments))(); michael@0: }, michael@0: apply: function (self, args) { michael@0: return new (Function.bind.apply(instanceConstructor, [ michael@0: self michael@0: ].concat(args)))(); michael@0: } michael@0: }; michael@0: }; michael@0: ApplicationDomain.prototype.getType = function (multiname) { michael@0: return this.getProperty(multiname, true, true); michael@0: }; michael@0: ApplicationDomain.prototype.getProperty = function (multiname, strict, execute) { michael@0: var resolved = this.findDefiningScript(multiname, execute); michael@0: if (resolved) { michael@0: if (!resolved.script.executing) { michael@0: return undefined; michael@0: } michael@0: return resolved.script.global[Multiname.getQualifiedName(resolved.trait.name)]; michael@0: } michael@0: if (strict) { michael@0: return Shumway.Debug.unexpected('Cannot find property ' + multiname); michael@0: } michael@0: return undefined; michael@0: }; michael@0: ApplicationDomain.prototype.getClass = function (simpleName) { michael@0: var cache = this.classCache; michael@0: var c = cache[simpleName]; michael@0: if (!c) { michael@0: c = cache[simpleName] = this.getProperty(Multiname.fromSimpleName(simpleName), true, true); michael@0: } michael@0: true; michael@0: return c; michael@0: }; michael@0: ApplicationDomain.prototype.findClass = function (simpleName) { michael@0: if (simpleName in this.classCache) { michael@0: return true; michael@0: } michael@0: return this.findDomainProperty(Multiname.fromSimpleName(simpleName), false, true); michael@0: }; michael@0: ApplicationDomain.prototype.findDomainProperty = function (multiname, strict, execute) { michael@0: if (Shumway.AVM2.Runtime.traceDomain.value) { michael@0: log('ApplicationDomain.findDomainProperty: ' + multiname); michael@0: } michael@0: var resolved = this.findDefiningScript(multiname, execute); michael@0: if (resolved) { michael@0: return resolved.script.global; michael@0: } michael@0: if (strict) { michael@0: return Shumway.Debug.unexpected('Cannot find property ' + multiname); michael@0: } else { michael@0: return undefined; michael@0: } michael@0: return undefined; michael@0: }; michael@0: ApplicationDomain.prototype.findClassInfo = function (mn) { michael@0: var originalQn; michael@0: if (Multiname.isQName(mn)) { michael@0: originalQn = Multiname.getQualifiedName(mn); michael@0: var ci = this.classInfoCache[originalQn]; michael@0: if (ci) { michael@0: return ci; michael@0: } michael@0: } else { michael@0: var ci = this.classInfoCache[mn.runtimeId]; michael@0: if (ci) { michael@0: return ci; michael@0: } michael@0: } michael@0: if (this.base) { michael@0: ci = this.base.findClassInfo(mn); michael@0: if (ci) { michael@0: return ci; michael@0: } michael@0: } michael@0: var abcs = this.abcs; michael@0: for (var i = 0; i < abcs.length; i++) { michael@0: var abc = abcs[i]; michael@0: var scripts = abc.scripts; michael@0: for (var j = 0; j < scripts.length; j++) { michael@0: var script = scripts[j]; michael@0: var traits = script.traits; michael@0: for (var k = 0; k < traits.length; k++) { michael@0: var trait = traits[k]; michael@0: if (trait.isClass()) { michael@0: var traitName = Multiname.getQualifiedName(trait.name); michael@0: if (originalQn) { michael@0: if (traitName === originalQn) { michael@0: return this.classInfoCache[originalQn] = trait.classInfo; michael@0: } michael@0: } else { michael@0: for (var m = 0, n = mn.namespaces.length; m < n; m++) { michael@0: var qn = mn.getQName(m); michael@0: if (traitName === Multiname.getQualifiedName(qn)) { michael@0: return this.classInfoCache[qn] = trait.classInfo; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if (!this.base && this.vm.findDefiningAbc) { michael@0: var abc = this.vm.findDefiningAbc(mn); michael@0: if (abc !== null && !this.loadedAbcs[abc.name]) { michael@0: this.loadedAbcs[abc.name] = true; michael@0: this.loadAbc(abc); michael@0: return this.findClassInfo(mn); michael@0: } michael@0: } michael@0: return undefined; michael@0: }; michael@0: ApplicationDomain.prototype.installNative = function (name, func) { michael@0: natives[name] = function () { michael@0: return func; michael@0: }; michael@0: }; michael@0: ApplicationDomain.prototype.findDefiningScript = function (mn, execute) { michael@0: var resolved = this.scriptCache[mn.runtimeId]; michael@0: if (resolved && (resolved.script.executed || !execute)) { michael@0: return resolved; michael@0: } michael@0: if (this.base) { michael@0: resolved = this.base.findDefiningScript(mn, execute); michael@0: if (resolved) { michael@0: return resolved; michael@0: } michael@0: } michael@0: Counter.count('ApplicationDomain: findDefiningScript'); michael@0: var abcs = this.abcs; michael@0: for (var i = 0; i < abcs.length; i++) { michael@0: var abc = abcs[i]; michael@0: var scripts = abc.scripts; michael@0: for (var j = 0; j < scripts.length; j++) { michael@0: var script = scripts[j]; michael@0: var traits = script.traits; michael@0: if (mn instanceof Multiname) { michael@0: for (var k = 0; k < traits.length; k++) { michael@0: var trait = traits[k]; michael@0: if (mn.hasQName(trait.name)) { michael@0: if (execute) { michael@0: ensureScriptIsExecuted(script, String(trait.name)); michael@0: } michael@0: return this.scriptCache[mn.runtimeId] = { michael@0: script: script, michael@0: trait: trait michael@0: }; michael@0: } michael@0: } michael@0: } else { michael@0: Shumway.Debug.unexpected(); michael@0: } michael@0: } michael@0: } michael@0: if (!this.base && this.vm.findDefiningAbc) { michael@0: var abc = this.vm.findDefiningAbc(mn); michael@0: if (abc !== null && !this.loadedAbcs[abc.name]) { michael@0: this.loadedAbcs[abc.name] = true; michael@0: this.loadAbc(abc); michael@0: return this.findDefiningScript(mn, execute); michael@0: } michael@0: } michael@0: return undefined; michael@0: }; michael@0: ApplicationDomain.prototype.compileAbc = function (abc, writer) { michael@0: compileAbc(abc, writer); michael@0: }; michael@0: ApplicationDomain.prototype.executeAbc = function (abc) { michael@0: this.loadAbc(abc); michael@0: executeScript(abc.lastScript); michael@0: }; michael@0: ApplicationDomain.prototype.loadAbc = function (abc) { michael@0: if (Shumway.AVM2.Runtime.traceExecution.value) { michael@0: log('Loading: ' + abc.name); michael@0: } michael@0: abc.applicationDomain = this; michael@0: GlobalMultinameResolver.loadAbc(abc); michael@0: this.abcs.push(abc); michael@0: if (!this.base) { michael@0: Type.initializeTypes(this); michael@0: } michael@0: }; michael@0: ApplicationDomain.prototype.broadcastMessage = function (type, message, origin) { michael@0: if (debug) { michael@0: Timer.start('broadcast: ' + type); michael@0: } michael@0: try { michael@0: this.onMessage.notify1(type, { michael@0: data: message, michael@0: origin: origin, michael@0: source: this michael@0: }); michael@0: } catch (e) { michael@0: avm2.exceptions.push({ michael@0: source: type, michael@0: message: e.message, michael@0: stack: e.stack michael@0: }); michael@0: throw e; michael@0: } michael@0: if (debug) { michael@0: Timer.stop(); michael@0: } michael@0: }; michael@0: ApplicationDomain.prototype.traceLoadedClasses = function (lastOnly) { michael@0: var writer = new IndentingWriter(); michael@0: lastOnly || writer.enter('Loaded Classes And Interfaces'); michael@0: var classes = lastOnly ? [ michael@0: this.loadedClasses.last() michael@0: ] : this.loadedClasses; michael@0: classes.forEach(function (cls) { michael@0: if (cls !== Shumway.AVM2.Runtime.Class) { michael@0: cls.trace(writer); michael@0: } michael@0: }); michael@0: lastOnly || writer.leave(''); michael@0: }; michael@0: return ApplicationDomain; michael@0: }(); michael@0: Runtime.ApplicationDomain = ApplicationDomain; michael@0: var SecurityDomain = function () { michael@0: function SecurityDomain() { michael@0: this.compartment = createNewCompartment(); michael@0: this.compartment.homePath = homePath; michael@0: this.compartment.release = true; michael@0: this.compartment.eval(snarf('compartment.js')); michael@0: } michael@0: SecurityDomain.prototype.initializeShell = function (sysMode, appMode) { michael@0: var compartment = this.compartment; michael@0: compartment.AVM2.initialize(sysMode, appMode); michael@0: compartment.AVM2.instance.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/builtin/builtin.abc')); michael@0: compartment.AVM2.instance.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/shell/shell.abc')); michael@0: this.systemDomain = compartment.AVM2.instance.systemDomain; michael@0: this.applicationDomain = compartment.AVM2.instance.applicationDomain; michael@0: }; michael@0: return SecurityDomain; michael@0: }(); michael@0: Runtime.SecurityDomain = SecurityDomain; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var Glue = Shumway.AVM2.Runtime.Glue; michael@0: var ApplicationDomain = Shumway.AVM2.Runtime.ApplicationDomain; michael@0: var AVM2 = Shumway.AVM2.Runtime.AVM2; michael@0: var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE; michael@0: var ApplicationDomain = Shumway.AVM2.Runtime.ApplicationDomain; michael@0: var AVM2 = Shumway.AVM2.Runtime.AVM2; michael@0: var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings; michael@0: var ClassBindings = Shumway.AVM2.Runtime.ClassBindings; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray; michael@0: var Interface = function () { michael@0: function Interface(classInfo) { michael@0: var ii = classInfo.instanceInfo; michael@0: true; michael@0: this.name = ii.name; michael@0: this.classInfo = classInfo; michael@0: } michael@0: Interface.createInterface = function (classInfo) { michael@0: var ii = classInfo.instanceInfo; michael@0: true; michael@0: if (Shumway.AVM2.Runtime.traceExecution.value) { michael@0: var str = 'Creating Interface ' + ii.name; michael@0: if (ii.interfaces.length) { michael@0: str += ' implements ' + ii.interfaces.map(function (name) { michael@0: return name.getName(); michael@0: }).join(', '); michael@0: } michael@0: log(str); michael@0: } michael@0: var cls = new Interface(classInfo); michael@0: cls.interfaceBindings = new InstanceBindings(null, ii, null, null); michael@0: return cls; michael@0: }; michael@0: Interface.prototype.toString = function () { michael@0: return '[interface ' + this.name + ']'; michael@0: }; michael@0: Interface.prototype.isInstance = function (value) { michael@0: if (value === null || typeof value !== 'object') { michael@0: return false; michael@0: } michael@0: true; michael@0: var qualifiedName = Multiname.getQualifiedName(this.name); michael@0: return value.class.implementedInterfaces[qualifiedName] !== undefined; michael@0: }; michael@0: Interface.prototype.trace = function (writer) { michael@0: writer.enter('interface ' + this.name.getName()); michael@0: writer.enter('interfaceBindings: '); michael@0: this.interfaceBindings.trace(writer); michael@0: writer.outdent(); michael@0: writer.outdent(); michael@0: writer.leave('}'); michael@0: }; michael@0: Interface.prototype.call = function (self, x) { michael@0: return x; michael@0: }; michael@0: Interface.prototype.apply = function (self, args) { michael@0: return args[0]; michael@0: }; michael@0: return Interface; michael@0: }(); michael@0: Runtime.Interface = Interface; michael@0: function setDefaultProperties(cls) { michael@0: defineNonEnumerableProperty(cls.dynamicPrototype, Multiname.getPublicQualifiedName('constructor'), cls); michael@0: defineReadOnlyProperty(cls.traitsPrototype, 'class', cls); michael@0: defineReadOnlyProperty(cls.instanceConstructor, 'class', cls); michael@0: } michael@0: Runtime.setDefaultProperties = setDefaultProperties; michael@0: var Class = function () { michael@0: function Class(name, instanceConstructor, callable) { michael@0: this.debugName = name; michael@0: if (instanceConstructor) { michael@0: true; michael@0: this.instanceConstructor = instanceConstructor; michael@0: this.instanceConstructorNoInitialize = instanceConstructor; michael@0: this.hasInitialize = 0; michael@0: this.instanceConstructor.class = this; michael@0: } michael@0: if (!callable) { michael@0: callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(this); michael@0: } else if (callable === Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable) { michael@0: callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(this); michael@0: } michael@0: defineNonEnumerableProperty(this, 'call', callable.call); michael@0: defineNonEnumerableProperty(this, 'apply', callable.apply); michael@0: } michael@0: Class.createClass = function (classInfo, baseClass, scope) { michael@0: var ci = classInfo; michael@0: var ii = ci.instanceInfo; michael@0: var domain = ci.abc.applicationDomain; michael@0: var className = Multiname.getName(ii.name); michael@0: var isNativeClass = ci.native; michael@0: if (isNativeClass) { michael@0: var buildClass = getNative(ci.native.cls); michael@0: if (!buildClass) { michael@0: Shumway.Debug.unexpected('No native for ' + ci.native.cls); michael@0: } michael@0: if (!baseClass) { michael@0: scope = new Scope(scope, Class); michael@0: } michael@0: } michael@0: var classScope = new Scope(scope, null); michael@0: var instanceConstructor = createFunction(ii.init, classScope, false); michael@0: var cls; michael@0: if (isNativeClass) { michael@0: cls = buildClass(domain, classScope, instanceConstructor, baseClass); michael@0: } else { michael@0: cls = new Class(className, instanceConstructor); michael@0: } michael@0: cls.className = className; michael@0: cls.classInfo = classInfo; michael@0: cls.scope = classScope; michael@0: classScope.object = cls; michael@0: var classNatives; michael@0: var instanceNatives; michael@0: if (isNativeClass) { michael@0: if (cls.native) { michael@0: classNatives = cls.native.static; michael@0: instanceNatives = cls.native.instance; michael@0: } michael@0: } else { michael@0: cls.extend(baseClass); michael@0: } michael@0: cls.classBindings = new ClassBindings(classInfo, classScope, classNatives); michael@0: cls.classBindings.applyTo(domain, cls); michael@0: defineReadOnlyProperty(cls, Shumway.AVM2.Runtime.VM_IS_CLASS, true); michael@0: cls.instanceBindings = new InstanceBindings(baseClass ? baseClass.instanceBindings : null, ii, classScope, instanceNatives); michael@0: if (cls.instanceConstructor) { michael@0: cls.instanceBindings.applyTo(domain, cls.traitsPrototype); michael@0: } michael@0: cls.implementedInterfaces = cls.instanceBindings.implementedInterfaces; michael@0: return cls; michael@0: }; michael@0: Class.prototype.setSymbol = function (props) { michael@0: this.instanceConstructor.prototype.symbol = props; michael@0: }; michael@0: Class.prototype.getSymbol = function () { michael@0: return this.instanceConstructor.prototype.symbol; michael@0: }; michael@0: Class.prototype.initializeInstance = function (obj) { michael@0: var c = this; michael@0: var initializes = []; michael@0: while (c) { michael@0: if (c.hasInitialize & Class.OWN_INITIALIZE) { michael@0: initializes.push(c.instanceConstructor.prototype.initialize); michael@0: } michael@0: c = c.baseClass; michael@0: } michael@0: var s; michael@0: while (s = initializes.pop()) { michael@0: s.call(obj); michael@0: } michael@0: Counter.count('Initialize Instance ' + obj.class); michael@0: }; michael@0: Class.prototype.createInstance = function (args) { michael@0: var o = Object.create(this.instanceConstructor.prototype); michael@0: this.instanceConstructor.apply(o, args); michael@0: return o; michael@0: }; michael@0: Class.prototype.createAsSymbol = function (props) { michael@0: var o = Object.create(this.instanceConstructor.prototype); michael@0: if (o.symbol) { michael@0: var symbol = Object.create(o.symbol); michael@0: for (var prop in props) { michael@0: symbol[prop] = props[prop]; michael@0: } michael@0: o.symbol = symbol; michael@0: } else { michael@0: o.symbol = props; michael@0: } michael@0: return o; michael@0: }; michael@0: Class.prototype.extendNative = function (baseClass, native) { michael@0: this.baseClass = baseClass; michael@0: this.dynamicPrototype = Object.getPrototypeOf(native.prototype); michael@0: this.instanceConstructor.prototype = this.traitsPrototype = native.prototype; michael@0: setDefaultProperties(this); michael@0: }; michael@0: Class.prototype.extendWrapper = function (baseClass, wrapper) { michael@0: true; michael@0: this.baseClass = baseClass; michael@0: this.dynamicPrototype = Object.create(baseClass.dynamicPrototype); michael@0: var traitsPrototype = Object.create(this.dynamicPrototype, Shumway.ObjectUtilities.getOwnPropertyDescriptors(wrapper.prototype)); michael@0: this.instanceConstructor.prototype = this.traitsPrototype = traitsPrototype; michael@0: setDefaultProperties(this); michael@0: }; michael@0: Class.prototype.extendBuiltin = function (baseClass) { michael@0: true; michael@0: this.baseClass = baseClass; michael@0: this.dynamicPrototype = this.traitsPrototype = this.instanceConstructor.prototype; michael@0: setDefaultProperties(this); michael@0: }; michael@0: Class.prototype.extend = function (baseClass) { michael@0: true; michael@0: this.baseClass = baseClass; michael@0: this.dynamicPrototype = Object.create(baseClass.dynamicPrototype); michael@0: if (baseClass.hasInitialize) { michael@0: var instanceConstructorNoInitialize = this.instanceConstructor; michael@0: var self = this; michael@0: this.instanceConstructor = function () { michael@0: self.initializeInstance(this); michael@0: instanceConstructorNoInitialize.apply(this, arguments); michael@0: }; michael@0: defineReadOnlyProperty(this.instanceConstructor, 'class', instanceConstructorNoInitialize.class); michael@0: this.hasInitialize |= Class.SUPER_INITIALIZE; michael@0: } michael@0: this.instanceConstructor.prototype = this.traitsPrototype = Object.create(this.dynamicPrototype); michael@0: setDefaultProperties(this); michael@0: }; michael@0: Class.prototype.setDefaultProperties = function () { michael@0: setDefaultProperties(this); michael@0: }; michael@0: Class.prototype.link = function (definition) { michael@0: true; michael@0: true; michael@0: if (definition.initialize) { michael@0: if (!this.hasInitialize) { michael@0: var instanceConstructorNoInitialize = this.instanceConstructor; michael@0: var self = this; michael@0: this.instanceConstructor = function () { michael@0: self.initializeInstance(this); michael@0: instanceConstructorNoInitialize.apply(this, arguments); michael@0: }; michael@0: defineReadOnlyProperty(this.instanceConstructor, 'class', instanceConstructorNoInitialize.class); michael@0: this.instanceConstructor.prototype = instanceConstructorNoInitialize.prototype; michael@0: } michael@0: this.hasInitialize |= Class.OWN_INITIALIZE; michael@0: } michael@0: var dynamicPrototype = this.dynamicPrototype; michael@0: var keys = Object.keys(definition); michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var propertyName = keys[i]; michael@0: Object.defineProperty(dynamicPrototype, propertyName, Object.getOwnPropertyDescriptor(definition, propertyName)); michael@0: } michael@0: function glueProperties(obj, properties) { michael@0: var keys = Object.keys(properties); michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var propertyName = keys[i]; michael@0: var propertyGlue = properties[propertyName]; michael@0: var propertySimpleName; michael@0: var glueOpenMethod = false; michael@0: if (propertyGlue.indexOf('open ') >= 0) { michael@0: propertySimpleName = propertyGlue.substring(5); michael@0: glueOpenMethod = true; michael@0: } else { michael@0: propertySimpleName = propertyGlue; michael@0: } michael@0: true; michael@0: var qn = Multiname.getQualifiedName(Multiname.fromSimpleName(propertySimpleName)); michael@0: if (glueOpenMethod) { michael@0: qn = Shumway.AVM2.Runtime.VM_OPEN_METHOD_PREFIX + qn; michael@0: } michael@0: true; michael@0: var descriptor = Object.getOwnPropertyDescriptor(obj, qn); michael@0: if (descriptor && descriptor.get) { michael@0: Object.defineProperty(obj, propertyName, descriptor); michael@0: } else { michael@0: Object.defineProperty(obj, propertyName, { michael@0: get: new Function('', 'return this.' + qn), michael@0: set: new Function('v', 'this.' + qn + ' = v') michael@0: }); michael@0: } michael@0: } michael@0: } michael@0: function generatePropertiesFromTraits(traits) { michael@0: var properties = createEmptyObject(); michael@0: traits.forEach(function (trait) { michael@0: var ns = trait.name.getNamespace(); michael@0: if (!ns.isPublic()) { michael@0: return; michael@0: } michael@0: properties[trait.name.getName()] = (trait.isMethod() ? 'open ' : '') + 'public ' + trait.name.getName(); michael@0: }); michael@0: return properties; michael@0: } michael@0: var glue = definition.__glue__; michael@0: if (!glue) { michael@0: return; michael@0: } michael@0: if (glue.script) { michael@0: if (glue.script.instance) { michael@0: if (Shumway.isNumber(glue.script.instance)) { michael@0: true; michael@0: glueProperties(dynamicPrototype, generatePropertiesFromTraits(this.classInfo.instanceInfo.traits)); michael@0: } else { michael@0: glueProperties(dynamicPrototype, glue.script.instance); michael@0: } michael@0: } michael@0: if (glue.script.static) { michael@0: if (Shumway.isNumber(glue.script.static)) { michael@0: true; michael@0: glueProperties(this, generatePropertiesFromTraits(this.classInfo.traits)); michael@0: } else { michael@0: glueProperties(this, glue.script.static); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: Class.prototype.linkNatives = function (definition) { michael@0: var glue = definition.__glue__; michael@0: this.native = glue.native; michael@0: }; michael@0: Class.prototype.verify = function () { michael@0: var instanceConstructor = this.instanceConstructor; michael@0: var tP = this.traitsPrototype; michael@0: var dP = this.dynamicPrototype; michael@0: true; michael@0: true; michael@0: true; michael@0: true; michael@0: if (tP !== Object.prototype) { michael@0: } michael@0: true; michael@0: }; michael@0: Class.prototype.coerce = function (value) { michael@0: return value; michael@0: }; michael@0: Class.prototype.isInstanceOf = function (value) { michael@0: return this.isInstance(value); michael@0: }; michael@0: Class.prototype.isInstance = function (value) { michael@0: if (value === null || typeof value !== 'object') { michael@0: return false; michael@0: } michael@0: return this.dynamicPrototype.isPrototypeOf(value); michael@0: }; michael@0: Class.prototype.trace = function (writer) { michael@0: var description = this.debugName + (this.baseClass ? ' extends ' + this.baseClass.debugName : ''); michael@0: writer.enter('class ' + description + ' {'); michael@0: writer.writeLn('scope: ' + this.scope); michael@0: writer.writeLn('baseClass: ' + this.baseClass); michael@0: writer.writeLn('classInfo: ' + this.classInfo); michael@0: writer.writeLn('dynamicPrototype: ' + this.dynamicPrototype); michael@0: writer.writeLn('traitsPrototype: ' + this.traitsPrototype); michael@0: writer.writeLn('dynamicPrototype === traitsPrototype: ' + (this.dynamicPrototype === this.traitsPrototype)); michael@0: writer.writeLn('instanceConstructor: ' + this.instanceConstructor); michael@0: writer.writeLn('instanceConstructorNoInitialize: ' + this.instanceConstructorNoInitialize); michael@0: writer.writeLn('instanceConstructor === instanceConstructorNoInitialize: ' + (this.instanceConstructor === this.instanceConstructorNoInitialize)); michael@0: var traitsPrototype = this.traitsPrototype; michael@0: writer.enter('traitsPrototype: '); michael@0: if (traitsPrototype) { michael@0: writer.enter('VM_SLOTS: '); michael@0: writer.writeArray(traitsPrototype.asSlots.byID.map(function (slot) { michael@0: return slot.trait; michael@0: })); michael@0: writer.outdent(); michael@0: writer.enter('VM_BINDINGS: '); michael@0: writer.writeArray(traitsPrototype.asBindings.map(function (binding) { michael@0: var pd = Object.getOwnPropertyDescriptor(traitsPrototype, binding); michael@0: var str = binding; michael@0: if (pd.get || pd.set) { michael@0: if (pd.get) { michael@0: str += ' getter: ' + debugName(pd.get); michael@0: } michael@0: if (pd.set) { michael@0: str += ' setter: ' + debugName(pd.set); michael@0: } michael@0: } else { michael@0: str += ' value: ' + debugName(pd.value); michael@0: } michael@0: return str; michael@0: })); michael@0: writer.outdent(); michael@0: writer.enter('VM_OPEN_METHODS: '); michael@0: writer.writeArray(toKeyValueArray(traitsPrototype.asOpenMethods).map(function (pair) { michael@0: return pair[0] + ': ' + debugName(pair[1]); michael@0: })); michael@0: writer.outdent(); michael@0: } michael@0: writer.enter('classBindings: '); michael@0: this.classBindings.trace(writer); michael@0: writer.outdent(); michael@0: writer.enter('instanceBindings: '); michael@0: this.instanceBindings.trace(writer); michael@0: writer.outdent(); michael@0: writer.outdent(); michael@0: writer.writeLn('call: ' + this.call); michael@0: writer.writeLn('apply: ' + this.apply); michael@0: writer.leave('}'); michael@0: }; michael@0: Class.prototype.toString = function () { michael@0: return '[class ' + this.classInfo.instanceInfo.name.name + ']'; michael@0: }; michael@0: Class.OWN_INITIALIZE = 1; michael@0: Class.SUPER_INITIALIZE = 2; michael@0: return Class; michael@0: }(); michael@0: Runtime.Class = Class; michael@0: var callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(Class); michael@0: defineNonEnumerableProperty(Class, 'call', callable.call); michael@0: defineNonEnumerableProperty(Class, 'apply', callable.apply); michael@0: Class.instanceConstructor = Class; michael@0: Class.toString = Class.prototype.toString; michael@0: Class.native = { michael@0: instance: { michael@0: prototype: { michael@0: get: function () { michael@0: return this.dynamicPrototype; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var Interface = Shumway.AVM2.Runtime.Interface; michael@0: var Class = Shumway.AVM2.Runtime.Class; michael@0: var Binding = Shumway.AVM2.Runtime.Binding; michael@0: var Bindings = Shumway.AVM2.Runtime.Bindings; michael@0: var ActivationBindings = Shumway.AVM2.Runtime.ActivationBindings; michael@0: var CatchBindings = Shumway.AVM2.Runtime.CatchBindings; michael@0: var ScriptBindings = Shumway.AVM2.Runtime.ScriptBindings; michael@0: var ClassBindings = Shumway.AVM2.Runtime.ClassBindings; michael@0: var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings; michael@0: var Interface = Shumway.AVM2.Runtime.Interface; michael@0: var Class = Shumway.AVM2.Runtime.Class; michael@0: var XRegExp = function (undefined) { michael@0: var REGEX_DATA = 'xregexp', self, features = { michael@0: astral: false, michael@0: natives: false michael@0: }, nativ = { michael@0: exec: RegExp.prototype.exec, michael@0: test: RegExp.prototype.test, michael@0: match: String.prototype.match, michael@0: replace: String.prototype.replace, michael@0: split: String.prototype.split michael@0: }, fixed = {}, cache = {}, patternCache = {}, tokens = [], defaultScope = 'default', classScope = 'class', nativeTokens = { michael@0: 'default': /\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??|[\s\S]/, michael@0: 'class': /\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|[\s\S]/ michael@0: }, replacementToken = /\$(?:{([\w$]+)}|([\d$&`']))/g, correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined, hasNativeY = RegExp.prototype.sticky !== undefined, registeredFlags = { michael@0: g: true, michael@0: i: true, michael@0: m: true, michael@0: y: hasNativeY michael@0: }, toString = {}.toString, add; michael@0: function augment(regex, captureNames, addProto) { michael@0: var p; michael@0: if (addProto) { michael@0: if (regex.__proto__) { michael@0: regex.__proto__ = self.prototype; michael@0: } else { michael@0: for (p in self.prototype) { michael@0: regex[p] = self.prototype[p]; michael@0: } michael@0: } michael@0: } michael@0: regex[REGEX_DATA] = { michael@0: captureNames: captureNames michael@0: }; michael@0: return regex; michael@0: } michael@0: function clipDuplicates(str) { michael@0: return nativ.replace.call(str, /([\s\S])(?=[\s\S]*\1)/g, ''); michael@0: } michael@0: function copy(regex, options) { michael@0: if (!self.isRegExp(regex)) { michael@0: throw new TypeError('Type RegExp expected'); michael@0: } michael@0: var flags = nativ.exec.call(/\/([a-z]*)$/i, String(regex))[1]; michael@0: options = options || {}; michael@0: if (options.add) { michael@0: flags = clipDuplicates(flags + options.add); michael@0: } michael@0: if (options.remove) { michael@0: flags = nativ.replace.call(flags, new RegExp('[' + options.remove + ']+', 'g'), ''); michael@0: } michael@0: regex = augment(new RegExp(regex.source, flags), hasNamedCapture(regex) ? regex[REGEX_DATA].captureNames.slice(0) : null, options.addProto); michael@0: return regex; michael@0: } michael@0: function getBaseProps() { michael@0: return { michael@0: captureNames: null michael@0: }; michael@0: } michael@0: function hasNamedCapture(regex) { michael@0: return !(!(regex[REGEX_DATA] && regex[REGEX_DATA].captureNames)); michael@0: } michael@0: function indexOf(array, value) { michael@0: if (Array.prototype.indexOf) { michael@0: return array.indexOf(value); michael@0: } michael@0: var len = array.length, i; michael@0: for (i = 0; i < len; ++i) { michael@0: if (array[i] === value) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: function isType(value, type) { michael@0: return toString.call(value) === '[object ' + type + ']'; michael@0: } michael@0: function isQuantifierNext(pattern, pos, flags) { michael@0: return nativ.test.call(flags.indexOf('x') > -1 ? /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ : /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/, pattern.slice(pos)); michael@0: } michael@0: function prepareFlags(pattern, flags) { michael@0: var i; michael@0: if (clipDuplicates(flags) !== flags) { michael@0: throw new SyntaxError('Invalid duplicate regex flag ' + flags); michael@0: } michael@0: pattern = nativ.replace.call(pattern, /^\(\?([\w$]+)\)/, function ($0, $1) { michael@0: if (nativ.test.call(/[gy]/, $1)) { michael@0: throw new SyntaxError('Cannot use flag g or y in mode modifier ' + $0); michael@0: } michael@0: flags = clipDuplicates(flags + $1); michael@0: return ''; michael@0: }); michael@0: for (i = 0; i < flags.length; ++i) { michael@0: if (!registeredFlags[flags.charAt(i)]) { michael@0: throw new SyntaxError('Unknown regex flag ' + flags.charAt(i)); michael@0: } michael@0: } michael@0: return { michael@0: pattern: pattern, michael@0: flags: flags michael@0: }; michael@0: } michael@0: function prepareOptions(value) { michael@0: value = value || {}; michael@0: if (isType(value, 'String')) { michael@0: value = self.forEach(value, /[^\s,]+/, function (match) { michael@0: this[match] = true; michael@0: }, {}); michael@0: } michael@0: return value; michael@0: } michael@0: function registerFlag(flag) { michael@0: if (!/^[\w$]$/.test(flag)) { michael@0: throw new Error('Flag must be a single character A-Za-z0-9_$'); michael@0: } michael@0: registeredFlags[flag] = true; michael@0: } michael@0: function runTokens(pattern, flags, pos, scope, context) { michael@0: var i = tokens.length, result = null, match, t; michael@0: while (i--) { michael@0: t = tokens[i]; michael@0: if ((t.scope === scope || t.scope === 'all') && (!t.flag || flags.indexOf(t.flag) > -1)) { michael@0: match = self.exec(pattern, t.regex, pos, 'sticky'); michael@0: if (match) { michael@0: result = { michael@0: matchLength: match[0].length, michael@0: output: t.handler.call(context, match, scope, flags), michael@0: reparse: t.reparse michael@0: }; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: function setAstral(on) { michael@0: self.cache.flush('patterns'); michael@0: features.astral = on; michael@0: } michael@0: function setNatives(on) { michael@0: RegExp.prototype.exec = (on ? fixed : nativ).exec; michael@0: RegExp.prototype.test = (on ? fixed : nativ).test; michael@0: String.prototype.match = (on ? fixed : nativ).match; michael@0: String.prototype.replace = (on ? fixed : nativ).replace; michael@0: String.prototype.split = (on ? fixed : nativ).split; michael@0: features.natives = on; michael@0: } michael@0: function toObject(value) { michael@0: if (value == null) { michael@0: throw new TypeError('Cannot convert null or undefined to object'); michael@0: } michael@0: return value; michael@0: } michael@0: self = function (pattern, flags) { michael@0: var context = { michael@0: hasNamedCapture: false, michael@0: captureNames: [] michael@0: }, scope = defaultScope, output = '', pos = 0, result, token, key; michael@0: if (self.isRegExp(pattern)) { michael@0: if (flags !== undefined) { michael@0: throw new TypeError('Cannot supply flags when copying a RegExp'); michael@0: } michael@0: return copy(pattern, { michael@0: addProto: true michael@0: }); michael@0: } michael@0: pattern = pattern === undefined ? '' : String(pattern); michael@0: flags = flags === undefined ? '' : String(flags); michael@0: key = pattern + '***' + flags; michael@0: if (!patternCache[key]) { michael@0: result = prepareFlags(pattern, flags); michael@0: pattern = result.pattern; michael@0: flags = result.flags; michael@0: while (pos < pattern.length) { michael@0: do { michael@0: result = runTokens(pattern, flags, pos, scope, context); michael@0: if (result && result.reparse) { michael@0: pattern = pattern.slice(0, pos) + result.output + pattern.slice(pos + result.matchLength); michael@0: } michael@0: } while (result && result.reparse); michael@0: if (result) { michael@0: output += result.output; michael@0: pos += result.matchLength || 1; michael@0: } else { michael@0: token = self.exec(pattern, nativeTokens[scope], pos, 'sticky')[0]; michael@0: output += token; michael@0: pos += token.length; michael@0: if (token === '[' && scope === defaultScope) { michael@0: scope = classScope; michael@0: } else if (token === ']' && scope === classScope) { michael@0: scope = defaultScope; michael@0: } michael@0: } michael@0: } michael@0: patternCache[key] = { michael@0: pattern: nativ.replace.call(output, /\(\?:\)(?=\(\?:\))|^\(\?:\)|\(\?:\)$/g, ''), michael@0: flags: nativ.replace.call(flags, /[^gimy]+/g, ''), michael@0: captures: context.hasNamedCapture ? context.captureNames : null michael@0: }; michael@0: } michael@0: key = patternCache[key]; michael@0: return augment(new RegExp(key.pattern, key.flags), key.captures, true); michael@0: }; michael@0: self.prototype = new RegExp(); michael@0: self.version = '3.0.0-pre'; michael@0: self.addToken = function (regex, handler, options) { michael@0: options = options || {}; michael@0: var optionalFlags = options.optionalFlags, i; michael@0: if (options.flag) { michael@0: registerFlag(options.flag); michael@0: } michael@0: if (optionalFlags) { michael@0: optionalFlags = nativ.split.call(optionalFlags, ''); michael@0: for (i = 0; i < optionalFlags.length; ++i) { michael@0: registerFlag(optionalFlags[i]); michael@0: } michael@0: } michael@0: tokens.push({ michael@0: regex: copy(regex, { michael@0: add: 'g' + (hasNativeY ? 'y' : '') michael@0: }), michael@0: handler: handler, michael@0: scope: options.scope || defaultScope, michael@0: flag: options.flag, michael@0: reparse: options.reparse michael@0: }); michael@0: self.cache.flush('patterns'); michael@0: }; michael@0: self.cache = function (pattern, flags) { michael@0: var key = pattern + '***' + (flags || ''); michael@0: return cache[key] || (cache[key] = self(pattern, flags)); michael@0: }; michael@0: self.cache.flush = function (cacheName) { michael@0: if (cacheName === 'patterns') { michael@0: patternCache = {}; michael@0: } else { michael@0: cache = {}; michael@0: } michael@0: }; michael@0: self.escape = function (str) { michael@0: return nativ.replace.call(toObject(str), /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); michael@0: }; michael@0: self.exec = function (str, regex, pos, sticky) { michael@0: var cacheFlags = 'g', match, r2; michael@0: if (hasNativeY && (sticky || regex.sticky && sticky !== false)) { michael@0: cacheFlags += 'y'; michael@0: } michael@0: regex[REGEX_DATA] = regex[REGEX_DATA] || getBaseProps(); michael@0: r2 = regex[REGEX_DATA][cacheFlags] || (regex[REGEX_DATA][cacheFlags] = copy(regex, { michael@0: add: cacheFlags, michael@0: remove: sticky === false ? 'y' : '' michael@0: })); michael@0: r2.lastIndex = pos = pos || 0; michael@0: match = fixed.exec.call(r2, str); michael@0: if (sticky && match && match.index !== pos) { michael@0: match = null; michael@0: } michael@0: if (regex.global) { michael@0: regex.lastIndex = match ? r2.lastIndex : 0; michael@0: } michael@0: return match; michael@0: }; michael@0: self.forEach = function (str, regex, callback, context) { michael@0: var pos = 0, i = -1, match; michael@0: while (match = self.exec(str, regex, pos)) { michael@0: callback.call(context, match, ++i, str, regex); michael@0: pos = match.index + (match[0].length || 1); michael@0: } michael@0: return context; michael@0: }; michael@0: self.globalize = function (regex) { michael@0: return copy(regex, { michael@0: add: 'g', michael@0: addProto: true michael@0: }); michael@0: }; michael@0: self.install = function (options) { michael@0: options = prepareOptions(options); michael@0: if (!features.astral && options.astral) { michael@0: setAstral(true); michael@0: } michael@0: if (!features.natives && options.natives) { michael@0: setNatives(true); michael@0: } michael@0: }; michael@0: self.isInstalled = function (feature) { michael@0: return !(!features[feature]); michael@0: }; michael@0: self.isRegExp = function (value) { michael@0: return toString.call(value) === '[object RegExp]'; michael@0: }; michael@0: self.match = function (str, regex, scope) { michael@0: var global = regex.global && scope !== 'one' || scope === 'all', cacheFlags = (global ? 'g' : '') + (regex.sticky ? 'y' : ''), result, r2; michael@0: regex[REGEX_DATA] = regex[REGEX_DATA] || getBaseProps(); michael@0: r2 = regex[REGEX_DATA][cacheFlags || 'noGY'] || (regex[REGEX_DATA][cacheFlags || 'noGY'] = copy(regex, { michael@0: add: cacheFlags, michael@0: remove: scope === 'one' ? 'g' : '' michael@0: })); michael@0: result = nativ.match.call(toObject(str), r2); michael@0: if (regex.global) { michael@0: regex.lastIndex = scope === 'one' && result ? result.index + result[0].length : 0; michael@0: } michael@0: return global ? result || [] : result && result[0]; michael@0: }; michael@0: self.matchChain = function (str, chain) { michael@0: return function recurseChain(values, level) { michael@0: var item = chain[level].regex ? chain[level] : { michael@0: regex: chain[level] michael@0: }, matches = [], addMatch = function (match) { michael@0: if (item.backref) { michael@0: if (!(match.hasOwnProperty(item.backref) || +item.backref < match.length)) { michael@0: throw new ReferenceError('Backreference to undefined group: ' + item.backref); michael@0: } michael@0: matches.push(match[item.backref] || ''); michael@0: } else { michael@0: matches.push(match[0]); michael@0: } michael@0: }, i; michael@0: for (i = 0; i < values.length; ++i) { michael@0: self.forEach(values[i], item.regex, addMatch); michael@0: } michael@0: return level === chain.length - 1 || !matches.length ? matches : recurseChain(matches, level + 1); michael@0: }([ michael@0: str michael@0: ], 0); michael@0: }; michael@0: self.replace = function (str, search, replacement, scope) { michael@0: var isRegex = self.isRegExp(search), global = search.global && scope !== 'one' || scope === 'all', cacheFlags = (global ? 'g' : '') + (search.sticky ? 'y' : ''), s2 = search, result; michael@0: if (isRegex) { michael@0: search[REGEX_DATA] = search[REGEX_DATA] || getBaseProps(); michael@0: s2 = search[REGEX_DATA][cacheFlags || 'noGY'] || (search[REGEX_DATA][cacheFlags || 'noGY'] = copy(search, { michael@0: add: cacheFlags, michael@0: remove: scope === 'one' ? 'g' : '' michael@0: })); michael@0: } else if (global) { michael@0: s2 = new RegExp(self.escape(String(search)), 'g'); michael@0: } michael@0: result = fixed.replace.call(toObject(str), s2, replacement); michael@0: if (isRegex && search.global) { michael@0: search.lastIndex = 0; michael@0: } michael@0: return result; michael@0: }; michael@0: self.replaceEach = function (str, replacements) { michael@0: var i, r; michael@0: for (i = 0; i < replacements.length; ++i) { michael@0: r = replacements[i]; michael@0: str = self.replace(str, r[0], r[1], r[2]); michael@0: } michael@0: return str; michael@0: }; michael@0: self.split = function (str, separator, limit) { michael@0: return fixed.split.call(toObject(str), separator, limit); michael@0: }; michael@0: self.test = function (str, regex, pos, sticky) { michael@0: return !(!self.exec(str, regex, pos, sticky)); michael@0: }; michael@0: self.uninstall = function (options) { michael@0: options = prepareOptions(options); michael@0: if (features.astral && options.astral) { michael@0: setAstral(false); michael@0: } michael@0: if (features.natives && options.natives) { michael@0: setNatives(false); michael@0: } michael@0: }; michael@0: self.union = function (patterns, flags) { michael@0: var parts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g, output = [], numCaptures = 0, numPriorCaptures, captureNames, pattern, rewrite = function (match, paren, backref) { michael@0: var name = captureNames[numCaptures - numPriorCaptures]; michael@0: if (paren) { michael@0: ++numCaptures; michael@0: if (name) { michael@0: return '(?<' + name + '>'; michael@0: } michael@0: } else if (backref) { michael@0: return '\\' + (+backref + numPriorCaptures); michael@0: } michael@0: return match; michael@0: }, i; michael@0: if (!(isType(patterns, 'Array') && patterns.length)) { michael@0: throw new TypeError('Must provide a nonempty array of patterns to merge'); michael@0: } michael@0: for (i = 0; i < patterns.length; ++i) { michael@0: pattern = patterns[i]; michael@0: if (self.isRegExp(pattern)) { michael@0: numPriorCaptures = numCaptures; michael@0: captureNames = pattern[REGEX_DATA] && pattern[REGEX_DATA].captureNames || []; michael@0: output.push(nativ.replace.call(self(pattern.source).source, parts, rewrite)); michael@0: } else { michael@0: output.push(self.escape(pattern)); michael@0: } michael@0: } michael@0: return self(output.join('|'), flags); michael@0: }; michael@0: fixed.exec = function (str) { michael@0: var origLastIndex = this.lastIndex, match = nativ.exec.apply(this, arguments), name, r2, i; michael@0: if (match) { michael@0: if (!correctExecNpcg && match.length > 1 && indexOf(match, '') > -1) { michael@0: r2 = copy(this, { michael@0: remove: 'g' michael@0: }); michael@0: nativ.replace.call(String(str).slice(match.index), r2, function () { michael@0: var len = arguments.length, i; michael@0: for (i = 1; i < len - 2; ++i) { michael@0: if (arguments[i] === undefined) { michael@0: match[i] = undefined; michael@0: } michael@0: } michael@0: }); michael@0: } michael@0: if (this[REGEX_DATA] && this[REGEX_DATA].captureNames) { michael@0: for (i = 1; i < match.length; ++i) { michael@0: name = this[REGEX_DATA].captureNames[i - 1]; michael@0: if (name) { michael@0: match[name] = match[i]; michael@0: } michael@0: } michael@0: } michael@0: if (this.global && !match[0].length && this.lastIndex > match.index) { michael@0: this.lastIndex = match.index; michael@0: } michael@0: } michael@0: if (!this.global) { michael@0: this.lastIndex = origLastIndex; michael@0: } michael@0: return match; michael@0: }; michael@0: fixed.test = function (str) { michael@0: return !(!fixed.exec.call(this, str)); michael@0: }; michael@0: fixed.match = function (regex) { michael@0: var result; michael@0: if (!self.isRegExp(regex)) { michael@0: regex = new RegExp(regex); michael@0: } else if (regex.global) { michael@0: result = nativ.match.apply(this, arguments); michael@0: regex.lastIndex = 0; michael@0: return result; michael@0: } michael@0: return fixed.exec.call(regex, toObject(this)); michael@0: }; michael@0: fixed.replace = function (search, replacement) { michael@0: var isRegex = self.isRegExp(search), origLastIndex, captureNames, result; michael@0: if (isRegex) { michael@0: if (search[REGEX_DATA]) { michael@0: captureNames = search[REGEX_DATA].captureNames; michael@0: } michael@0: origLastIndex = search.lastIndex; michael@0: } else { michael@0: search += ''; michael@0: } michael@0: if (isType(replacement, 'Function')) { michael@0: result = nativ.replace.call(String(this), search, function () { michael@0: var args = arguments, i; michael@0: if (captureNames) { michael@0: args[0] = new String(args[0]); michael@0: for (i = 0; i < captureNames.length; ++i) { michael@0: if (captureNames[i]) { michael@0: args[0][captureNames[i]] = args[i + 1]; michael@0: } michael@0: } michael@0: } michael@0: if (isRegex && search.global) { michael@0: search.lastIndex = args[args.length - 2] + args[0].length; michael@0: } michael@0: return replacement.apply(undefined, args); michael@0: }); michael@0: } else { michael@0: result = nativ.replace.call(this == null ? this : String(this), search, function () { michael@0: var args = arguments; michael@0: return nativ.replace.call(String(replacement), replacementToken, function ($0, $1, $2) { michael@0: var n; michael@0: if ($1) { michael@0: n = +$1; michael@0: if (n <= args.length - 3) { michael@0: return args[n] || ''; michael@0: } michael@0: n = captureNames ? indexOf(captureNames, $1) : -1; michael@0: if (n < 0) { michael@0: throw new SyntaxError('Backreference to undefined group ' + $0); michael@0: } michael@0: return args[n + 1] || ''; michael@0: } michael@0: if ($2 === '$') { michael@0: return '$'; michael@0: } michael@0: if ($2 === '&' || +$2 === 0) { michael@0: return args[0]; michael@0: } michael@0: if ($2 === '`') { michael@0: return args[args.length - 1].slice(0, args[args.length - 2]); michael@0: } michael@0: if ($2 === '\'') { michael@0: return args[args.length - 1].slice(args[args.length - 2] + args[0].length); michael@0: } michael@0: $2 = +$2; michael@0: if (!isNaN($2)) { michael@0: if ($2 > args.length - 3) { michael@0: throw new SyntaxError('Backreference to undefined group ' + $0); michael@0: } michael@0: return args[$2] || ''; michael@0: } michael@0: throw new SyntaxError('Invalid token ' + $0); michael@0: }); michael@0: }); michael@0: } michael@0: if (isRegex) { michael@0: if (search.global) { michael@0: search.lastIndex = 0; michael@0: } else { michael@0: search.lastIndex = origLastIndex; michael@0: } michael@0: } michael@0: return result; michael@0: }; michael@0: fixed.split = function (separator, limit) { michael@0: if (!self.isRegExp(separator)) { michael@0: return nativ.split.apply(this, arguments); michael@0: } michael@0: var str = String(this), output = [], origLastIndex = separator.lastIndex, lastLastIndex = 0, lastLength; michael@0: limit = (limit === undefined ? -1 : limit) >>> 0; michael@0: self.forEach(str, separator, function (match) { michael@0: if (match.index + match[0].length > lastLastIndex) { michael@0: output.push(str.slice(lastLastIndex, match.index)); michael@0: if (match.length > 1 && match.index < str.length) { michael@0: Array.prototype.push.apply(output, match.slice(1)); michael@0: } michael@0: lastLength = match[0].length; michael@0: lastLastIndex = match.index + lastLength; michael@0: } michael@0: }); michael@0: if (lastLastIndex === str.length) { michael@0: if (!nativ.test.call(separator, '') || lastLength) { michael@0: output.push(''); michael@0: } michael@0: } else { michael@0: output.push(str.slice(lastLastIndex)); michael@0: } michael@0: separator.lastIndex = origLastIndex; michael@0: return output.length > limit ? output.slice(0, limit) : output; michael@0: }; michael@0: add = self.addToken; michael@0: add(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4})|x(?![\dA-Fa-f]{2}))/, function (match, scope) { michael@0: if (match[1] === 'B' && scope === defaultScope) { michael@0: return match[0]; michael@0: } michael@0: throw new SyntaxError('Invalid escape ' + match[0]); michael@0: }, { michael@0: scope: 'all' michael@0: }); michael@0: add(/\[(\^?)]/, function (match) { michael@0: return match[1] ? '[\\s\\S]' : '\\b\\B'; michael@0: }); michael@0: add(/\(\?#[^)]*\)/, function (match, scope, flags) { michael@0: return isQuantifierNext(match.input, match.index + match[0].length, flags) ? '' : '(?:)'; michael@0: }); michael@0: add(/\s+|#.*/, function (match, scope, flags) { michael@0: return isQuantifierNext(match.input, match.index + match[0].length, flags) ? '' : '(?:)'; michael@0: }, { michael@0: flag: 'x' michael@0: }); michael@0: add(/\./, function () { michael@0: return '[\\s\\S]'; michael@0: }, { michael@0: flag: 's' michael@0: }); michael@0: add(/\\k<([\w$]+)>/, function (match) { michael@0: var index = isNaN(match[1]) ? indexOf(this.captureNames, match[1]) + 1 : +match[1], endIndex = match.index + match[0].length; michael@0: if (!index || index > this.captureNames.length) { michael@0: throw new SyntaxError('Backreference to undefined group ' + match[0]); michael@0: } michael@0: return '\\' + index + (endIndex === match.input.length || isNaN(match.input.charAt(endIndex)) ? '' : '(?:)'); michael@0: }); michael@0: add(/\\(\d+)/, function (match, scope) { michael@0: if (!(scope === defaultScope && /^[1-9]/.test(match[1]) && +match[1] <= this.captureNames.length) && match[1] !== '0') { michael@0: throw new SyntaxError('Cannot use octal escape or backreference to undefined group ' + match[0]); michael@0: } michael@0: return match[0]; michael@0: }, { michael@0: scope: 'all' michael@0: }); michael@0: add(/\(\?P?<([\w$]+)>/, function (match) { michael@0: if (!isNaN(match[1])) { michael@0: throw new SyntaxError('Cannot use integer as capture name ' + match[0]); michael@0: } michael@0: if (match[1] === 'length' || match[1] === '__proto__') { michael@0: throw new SyntaxError('Cannot use reserved word as capture name ' + match[0]); michael@0: } michael@0: if (indexOf(this.captureNames, match[1]) > -1) { michael@0: throw new SyntaxError('Cannot use same name for multiple groups ' + match[0]); michael@0: } michael@0: this.captureNames.push(match[1]); michael@0: this.hasNamedCapture = true; michael@0: return '('; michael@0: }); michael@0: add(/\((?!\?)/, function (match, scope, flags) { michael@0: if (flags.indexOf('n') > -1) { michael@0: return '(?:'; michael@0: } michael@0: this.captureNames.push(null); michael@0: return '('; michael@0: }, { michael@0: optionalFlags: 'n' michael@0: }); michael@0: return self; michael@0: }(); michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: var Option = Shumway.Options.Option; michael@0: var OptionSet = Shumway.Options.OptionSet; michael@0: var runtimeOptions = systemOptions.register(new OptionSet('Runtime Options')); michael@0: var traceScope = runtimeOptions.register(new Option('ts', 'traceScope', 'boolean', false, 'trace scope execution')); michael@0: Runtime.traceExecution = runtimeOptions.register(new Option('tx', 'traceExecution', 'number', 0, 'trace script execution')); michael@0: Runtime.traceCallExecution = runtimeOptions.register(new Option('txc', 'traceCallExecution', 'number', 0, 'trace call execution')); michael@0: var functionBreak = runtimeOptions.register(new Option('fb', 'functionBreak', 'number', -1, 'Inserts a debugBreak at function index #.')); michael@0: var compileOnly = runtimeOptions.register(new Option('co', 'compileOnly', 'number', -1, 'Compiles only function number.')); michael@0: var compileUntil = runtimeOptions.register(new Option('cu', 'compileUntil', 'number', -1, 'Compiles only until a function number.')); michael@0: Runtime.debuggerMode = runtimeOptions.register(new Option('dm', 'debuggerMode', 'boolean', false, 'matches avm2 debugger build semantics')); michael@0: Runtime.enableVerifier = runtimeOptions.register(new Option('verify', 'verify', 'boolean', false, 'Enable verifier.')); michael@0: Runtime.globalMultinameAnalysis = runtimeOptions.register(new Option('ga', 'globalMultinameAnalysis', 'boolean', false, 'Global multiname analysis.')); michael@0: var traceInlineCaching = runtimeOptions.register(new Option('tic', 'traceInlineCaching', 'boolean', false, 'Trace inline caching execution.')); michael@0: Runtime.codeCaching = runtimeOptions.register(new Option('cc', 'codeCaching', 'boolean', false, 'Enable code caching.')); michael@0: var compilerEnableExceptions = runtimeOptions.register(new Option('cex', 'exceptions', 'boolean', false, 'Compile functions with catch blocks.')); michael@0: var compilerMaximumMethodSize = runtimeOptions.register(new Option('cmms', 'maximumMethodSize', 'number', 4 * 1024, 'Compiler maximum method size.')); michael@0: Runtime.traceClasses = runtimeOptions.register(new Option('tc', 'traceClasses', 'boolean', false, 'trace class creation')); michael@0: Runtime.traceDomain = runtimeOptions.register(new Option('td', 'traceDomain', 'boolean', false, 'trace domain property access')); michael@0: Runtime.sealConstTraits = false; michael@0: Runtime.useAsAdd = true; michael@0: var useSurrogates = true; michael@0: var callCounter = new Shumway.Metrics.Counter(true); michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var Namespace = Shumway.AVM2.ABC.Namespace; michael@0: var MethodInfo = Shumway.AVM2.ABC.MethodInfo; michael@0: var ClassInfo = Shumway.AVM2.ABC.ClassInfo; michael@0: var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo; michael@0: var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo; michael@0: var SORT = Shumway.AVM2.ABC.SORT; michael@0: var Trait = Shumway.AVM2.ABC.Trait; michael@0: var IndentingWriter = Shumway.IndentingWriter; michael@0: var hasOwnProperty = Shumway.ObjectUtilities.hasOwnProperty; michael@0: var createMap = Shumway.ObjectUtilities.createMap; michael@0: var cloneObject = Shumway.ObjectUtilities.cloneObject; michael@0: var copyProperties = Shumway.ObjectUtilities.copyProperties; michael@0: var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject; michael@0: var boxValue = Shumway.ObjectUtilities.boxValue; michael@0: var bindSafely = Shumway.FunctionUtilities.bindSafely; michael@0: var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter; michael@0: var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty; michael@0: var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty; michael@0: var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter; michael@0: var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter; michael@0: var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter; michael@0: var toSafeString = Shumway.StringUtilities.toSafeString; michael@0: var toSafeArrayString = Shumway.StringUtilities.toSafeArrayString; michael@0: var TRAIT = Shumway.AVM2.ABC.TRAIT; michael@0: Runtime.VM_SLOTS = 'asSlots'; michael@0: Runtime.VM_LENGTH = 'asLength'; michael@0: Runtime.VM_BINDINGS = 'asBindings'; michael@0: Runtime.VM_NATIVE_PROTOTYPE_FLAG = 'asIsNative'; michael@0: Runtime.VM_OPEN_METHODS = 'asOpenMethods'; michael@0: Runtime.VM_IS_CLASS = 'asIsClass'; michael@0: Runtime.VM_IS_PROXY = 'asIsProxy'; michael@0: Runtime.VM_CALL_PROXY = 'asCallProxy'; michael@0: Runtime.VM_OPEN_METHOD_PREFIX = 'm'; michael@0: Runtime.VM_MEMOIZER_PREFIX = 'z'; michael@0: Runtime.VM_OPEN_SET_METHOD_PREFIX = 's'; michael@0: Runtime.VM_OPEN_GET_METHOD_PREFIX = 'g'; michael@0: Runtime.VM_NATIVE_BUILTIN_ORIGINALS = 'asOriginals'; michael@0: Runtime.VM_METHOD_OVERRIDES = createEmptyObject(); michael@0: var vmNextInterpreterFunctionId = 1; michael@0: var vmNextCompiledFunctionId = 1; michael@0: var totalFunctionCount = 0; michael@0: var compiledFunctionCount = 0; michael@0: var compilationCount = 0; michael@0: function isClass(object) { michael@0: true; michael@0: return Object.hasOwnProperty.call(object, Runtime.VM_IS_CLASS); michael@0: } michael@0: Runtime.isClass = isClass; michael@0: function isNativePrototype(object) { michael@0: return Object.prototype.hasOwnProperty.call(object, Runtime.VM_NATIVE_PROTOTYPE_FLAG); michael@0: } michael@0: Runtime.isNativePrototype = isNativePrototype; michael@0: var traitsWriter = null; michael@0: var callWriter = null; michael@0: function patch(patchTargets, value) { michael@0: true; michael@0: for (var i = 0; i < patchTargets.length; i++) { michael@0: var patchTarget = patchTargets[i]; michael@0: if (Runtime.traceExecution.value >= 3) { michael@0: var str = 'Patching: '; michael@0: if (patchTarget.name) { michael@0: str += patchTarget.name; michael@0: } else if (patchTarget.get) { michael@0: str += 'get ' + patchTarget.get; michael@0: } else if (patchTarget.set) { michael@0: str += 'set ' + patchTarget.set; michael@0: } michael@0: traitsWriter && traitsWriter.redLn(str); michael@0: } michael@0: if (patchTarget.get) { michael@0: defineNonEnumerableGetterOrSetter(patchTarget.object, patchTarget.get, value, true); michael@0: } else if (patchTarget.set) { michael@0: defineNonEnumerableGetterOrSetter(patchTarget.object, patchTarget.set, value, false); michael@0: } else { michael@0: defineNonEnumerableProperty(patchTarget.object, patchTarget.name, value); michael@0: } michael@0: } michael@0: } michael@0: Runtime.patch = patch; michael@0: function applyNonMemoizedMethodTrait(qn, trait, object, scope, natives) { michael@0: true; michael@0: if (trait.isMethod()) { michael@0: var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) { michael@0: var fn = getTraitFunction(trait, scope, natives); michael@0: patch(self.patchTargets, fn); michael@0: return fn; michael@0: }, trait.methodInfo.parameters.length); michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: object, michael@0: name: qn michael@0: }, michael@0: { michael@0: object: object, michael@0: name: Runtime.VM_OPEN_METHOD_PREFIX + qn michael@0: } michael@0: ]; michael@0: var closure = bindSafely(trampoline, object); michael@0: defineReadOnlyProperty(closure, Runtime.VM_LENGTH, trampoline.asLength); michael@0: defineReadOnlyProperty(closure, Multiname.getPublicQualifiedName('prototype'), null); michael@0: defineNonEnumerableProperty(object, qn, closure); michael@0: defineNonEnumerableProperty(object, Runtime.VM_OPEN_METHOD_PREFIX + qn, closure); michael@0: } else if (trait.isGetter() || trait.isSetter()) { michael@0: var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) { michael@0: var fn = getTraitFunction(trait, scope, natives); michael@0: patch(self.patchTargets, fn); michael@0: return fn; michael@0: }, trait.isSetter() ? 1 : 0); michael@0: if (trait.isGetter()) { michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: object, michael@0: get: qn michael@0: } michael@0: ]; michael@0: } else { michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: object, michael@0: set: qn michael@0: } michael@0: ]; michael@0: } michael@0: defineNonEnumerableGetterOrSetter(object, qn, trampoline, trait.isGetter()); michael@0: } else { michael@0: Shumway.Debug.unexpected(trait); michael@0: } michael@0: } michael@0: Runtime.applyNonMemoizedMethodTrait = applyNonMemoizedMethodTrait; michael@0: function applyMemoizedMethodTrait(qn, trait, object, scope, natives) { michael@0: true; michael@0: if (trait.isMethod()) { michael@0: var memoizerTarget = { michael@0: value: null michael@0: }; michael@0: var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) { michael@0: var fn = getTraitFunction(trait, scope, natives); michael@0: patch(self.patchTargets, fn); michael@0: return fn; michael@0: }, trait.methodInfo.parameters.length, String(trait.name)); michael@0: memoizerTarget.value = trampoline; michael@0: var openMethods = object.asOpenMethods; michael@0: openMethods[qn] = trampoline; michael@0: defineNonEnumerableProperty(object, Runtime.VM_OPEN_METHOD_PREFIX + qn, trampoline); michael@0: defineNonEnumerableGetter(object, qn, Shumway.AVM2.Runtime.makeMemoizer(qn, memoizerTarget)); michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: memoizerTarget, michael@0: name: 'value' michael@0: }, michael@0: { michael@0: object: openMethods, michael@0: name: qn michael@0: }, michael@0: { michael@0: object: object, michael@0: name: Runtime.VM_OPEN_METHOD_PREFIX + qn michael@0: } michael@0: ]; michael@0: } else if (trait.isGetter() || trait.isSetter()) { michael@0: var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) { michael@0: var fn = getTraitFunction(trait, scope, natives); michael@0: patch(self.patchTargets, fn); michael@0: return fn; michael@0: }, 0, String(trait.name)); michael@0: if (trait.isGetter()) { michael@0: defineNonEnumerableProperty(object, Runtime.VM_OPEN_GET_METHOD_PREFIX + qn, trampoline); michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: object, michael@0: get: qn michael@0: }, michael@0: { michael@0: object: object, michael@0: name: Runtime.VM_OPEN_GET_METHOD_PREFIX + qn michael@0: } michael@0: ]; michael@0: } else { michael@0: defineNonEnumerableProperty(object, Runtime.VM_OPEN_SET_METHOD_PREFIX + qn, trampoline); michael@0: trampoline.patchTargets = [ michael@0: { michael@0: object: object, michael@0: set: qn michael@0: }, michael@0: { michael@0: object: object, michael@0: name: Runtime.VM_OPEN_SET_METHOD_PREFIX + qn michael@0: } michael@0: ]; michael@0: } michael@0: defineNonEnumerableGetterOrSetter(object, qn, trampoline, trait.isGetter()); michael@0: } michael@0: } michael@0: Runtime.applyMemoizedMethodTrait = applyMemoizedMethodTrait; michael@0: function getNamespaceResolutionMap(namespaces) { michael@0: var self = this; michael@0: var map = self.resolutionMap[namespaces.runtimeId]; michael@0: if (map) michael@0: return map; michael@0: map = self.resolutionMap[namespaces.runtimeId] = Shumway.ObjectUtilities.createMap(); michael@0: var bindings = self.bindings; michael@0: for (var key in bindings.map) { michael@0: var multiname = key; michael@0: var trait = bindings.map[key].trait; michael@0: if (trait.isGetter() || trait.isSetter()) { michael@0: multiname = multiname.substring(Shumway.AVM2.Runtime.Binding.KEY_PREFIX_LENGTH); michael@0: } michael@0: multiname = Multiname.fromQualifiedName(multiname); michael@0: if (multiname.getNamespace().inNamespaceSet(namespaces)) { michael@0: map[multiname.getName()] = Multiname.getQualifiedName(trait.name); michael@0: } michael@0: } michael@0: return map; michael@0: } michael@0: Runtime.getNamespaceResolutionMap = getNamespaceResolutionMap; michael@0: function resolveMultinameProperty(namespaces, name, flags) { michael@0: var self = this; michael@0: if (typeof name === 'object') { michael@0: name = String(name); michael@0: } michael@0: if (Shumway.isNumeric(name)) { michael@0: return Shumway.toNumber(name); michael@0: } michael@0: if (!namespaces) { michael@0: return Multiname.getPublicQualifiedName(name); michael@0: } michael@0: if (namespaces.length > 1) { michael@0: var resolved = self.getNamespaceResolutionMap(namespaces)[name]; michael@0: if (resolved) michael@0: return resolved; michael@0: return Multiname.getPublicQualifiedName(name); michael@0: } else { michael@0: return Multiname.qualifyName(namespaces[0], name); michael@0: } michael@0: } michael@0: Runtime.resolveMultinameProperty = resolveMultinameProperty; michael@0: function asGetPublicProperty(name) { michael@0: var self = this; michael@0: return self.asGetProperty(undefined, name, 0); michael@0: } michael@0: Runtime.asGetPublicProperty = asGetPublicProperty; michael@0: function asGetProperty(namespaces, name, flags) { michael@0: var self = this; michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: if (self.asGetNumericProperty && Multiname.isNumeric(resolved)) { michael@0: return self.asGetNumericProperty(resolved); michael@0: } michael@0: return self[resolved]; michael@0: } michael@0: Runtime.asGetProperty = asGetProperty; michael@0: function asGetPropertyLikelyNumeric(namespaces, name, flags) { michael@0: var self = this; michael@0: if (typeof name === 'number') { michael@0: return self.asGetNumericProperty(name); michael@0: } michael@0: return asGetProperty.call(self, namespaces, name, flags); michael@0: } michael@0: Runtime.asGetPropertyLikelyNumeric = asGetPropertyLikelyNumeric; michael@0: function asGetResolvedStringProperty(resolved) { michael@0: true; michael@0: return this[resolved]; michael@0: } michael@0: Runtime.asGetResolvedStringProperty = asGetResolvedStringProperty; michael@0: function asCallResolvedStringProperty(resolved, isLex, args) { michael@0: var self = this; michael@0: var receiver = isLex ? null : this; michael@0: var openMethods = self.asOpenMethods; michael@0: var method; michael@0: if (receiver && openMethods && openMethods[resolved]) { michael@0: method = openMethods[resolved]; michael@0: } else { michael@0: method = self[resolved]; michael@0: } michael@0: return method.apply(receiver, args); michael@0: } michael@0: Runtime.asCallResolvedStringProperty = asCallResolvedStringProperty; michael@0: function asGetResolvedStringPropertyFallback(resolved) { michael@0: var self = this; michael@0: var name = Multiname.getNameFromPublicQualifiedName(resolved); michael@0: return self.asGetProperty([ michael@0: Namespace.PUBLIC michael@0: ], name, 0); michael@0: } michael@0: Runtime.asGetResolvedStringPropertyFallback = asGetResolvedStringPropertyFallback; michael@0: function asSetPublicProperty(name, value) { michael@0: var self = this; michael@0: return self.asSetProperty(undefined, name, 0, value); michael@0: } michael@0: Runtime.asSetPublicProperty = asSetPublicProperty; michael@0: function asSetProperty(namespaces, name, flags, value) { michael@0: var self = this; michael@0: if (typeof name === 'object') { michael@0: name = String(name); michael@0: } michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: if (self.asSetNumericProperty && Multiname.isNumeric(resolved)) { michael@0: return self.asSetNumericProperty(resolved, value); michael@0: } michael@0: var slotInfo = self.asSlots.byQN[resolved]; michael@0: if (slotInfo) { michael@0: if (slotInfo.isConst) { michael@0: } michael@0: var type = slotInfo.type; michael@0: if (type && type.coerce) { michael@0: value = type.coerce(value); michael@0: } michael@0: } michael@0: self[resolved] = value; michael@0: } michael@0: Runtime.asSetProperty = asSetProperty; michael@0: function asSetPropertyLikelyNumeric(namespaces, name, flags, value) { michael@0: var self = this; michael@0: if (typeof name === 'number') { michael@0: self.asSetNumericProperty(name, value); michael@0: return; michael@0: } michael@0: return asSetProperty.call(self, namespaces, name, flags, value); michael@0: } michael@0: Runtime.asSetPropertyLikelyNumeric = asSetPropertyLikelyNumeric; michael@0: function asDefinePublicProperty(name, descriptor) { michael@0: var self = this; michael@0: return self.asDefineProperty(undefined, name, 0, descriptor); michael@0: } michael@0: Runtime.asDefinePublicProperty = asDefinePublicProperty; michael@0: function asDefineProperty(namespaces, name, flags, descriptor) { michael@0: var self = this; michael@0: if (typeof name === 'object') { michael@0: name = String(name); michael@0: } michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: Object.defineProperty(self, resolved, descriptor); michael@0: } michael@0: Runtime.asDefineProperty = asDefineProperty; michael@0: function asCallPublicProperty(name, args) { michael@0: var self = this; michael@0: return self.asCallProperty(undefined, name, 0, false, args); michael@0: } michael@0: Runtime.asCallPublicProperty = asCallPublicProperty; michael@0: function asCallProperty(namespaces, name, flags, isLex, args) { michael@0: var self = this; michael@0: if (Runtime.traceCallExecution.value) { michael@0: var receiverClassName = self.class ? self.class.className + ' ' : ''; michael@0: callWriter.enter('call ' + receiverClassName + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name)); michael@0: } michael@0: var receiver = isLex ? null : self; michael@0: var result; michael@0: if (isProxyObject(self)) { michael@0: result = self[Runtime.VM_CALL_PROXY](new Multiname(namespaces, name, flags), receiver, args); michael@0: } else { michael@0: var method; michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: if (self.asGetNumericProperty && Multiname.isNumeric(resolved)) { michael@0: method = self.asGetNumericProperty(resolved); michael@0: } else { michael@0: var openMethods = self.asOpenMethods; michael@0: if (receiver && openMethods && openMethods[resolved]) { michael@0: method = openMethods[resolved]; michael@0: } else { michael@0: method = self[resolved]; michael@0: } michael@0: } michael@0: result = method.apply(receiver, args); michael@0: } michael@0: Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); michael@0: return result; michael@0: } michael@0: Runtime.asCallProperty = asCallProperty; michael@0: function asCallSuper(scope, namespaces, name, flags, args) { michael@0: var self = this; michael@0: if (Runtime.traceCallExecution.value) { michael@0: var receiverClassName = self.class ? self.class.className + ' ' : ''; michael@0: callWriter.enter('call super ' + receiverClassName + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name)); michael@0: } michael@0: var baseClass = scope.object.baseClass; michael@0: var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); michael@0: var openMethods = baseClass.traitsPrototype.asOpenMethods; michael@0: var method = openMethods[resolved]; michael@0: var result = method.apply(this, args); michael@0: Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); michael@0: return result; michael@0: } michael@0: Runtime.asCallSuper = asCallSuper; michael@0: function asSetSuper(scope, namespaces, name, flags, value) { michael@0: var self = this; michael@0: if (Runtime.traceCallExecution.value) { michael@0: var receiverClassName = self.class ? self.class.className + ' ' : ''; michael@0: callWriter.enter('set super ' + receiverClassName + name + '(' + toSafeString(value) + ') #' + callCounter.count(name)); michael@0: } michael@0: var baseClass = scope.object.baseClass; michael@0: var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); michael@0: if (self.asSlots.byQN[resolved]) { michael@0: this.asSetProperty(namespaces, name, flags, value); michael@0: } else { michael@0: baseClass.traitsPrototype[Runtime.VM_OPEN_SET_METHOD_PREFIX + resolved].call(this, value); michael@0: } michael@0: Runtime.traceCallExecution.value > 0 && callWriter.leave(''); michael@0: } michael@0: Runtime.asSetSuper = asSetSuper; michael@0: function asGetSuper(scope, namespaces, name, flags) { michael@0: var self = this; michael@0: if (Runtime.traceCallExecution.value) { michael@0: var receiver = self.class ? self.class.className + ' ' : ''; michael@0: callWriter.enter('get super ' + receiver + name + ' #' + callCounter.count(name)); michael@0: } michael@0: var baseClass = scope.object.baseClass; michael@0: var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags); michael@0: var result; michael@0: if (self.asSlots.byQN[resolved]) { michael@0: result = this.asGetProperty(namespaces, name, flags); michael@0: } else { michael@0: result = baseClass.traitsPrototype[Runtime.VM_OPEN_GET_METHOD_PREFIX + resolved].call(this); michael@0: } michael@0: Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); michael@0: return result; michael@0: } michael@0: Runtime.asGetSuper = asGetSuper; michael@0: function construct(cls, args) { michael@0: if (cls.classInfo) { michael@0: var qn = Multiname.getQualifiedName(cls.classInfo.instanceInfo.name); michael@0: if (qn === Multiname.String) { michael@0: return String.apply(null, args); michael@0: } michael@0: if (qn === Multiname.Boolean) { michael@0: return Boolean.apply(null, args); michael@0: } michael@0: if (qn === Multiname.Number) { michael@0: return Number.apply(null, args); michael@0: } michael@0: } michael@0: var c = cls.instanceConstructor; michael@0: var a = args; michael@0: switch (args.length) { michael@0: case 0: michael@0: return new c(); michael@0: case 1: michael@0: return new c(a[0]); michael@0: case 2: michael@0: return new c(a[0], a[1]); michael@0: case 3: michael@0: return new c(a[0], a[1], a[2]); michael@0: case 4: michael@0: return new c(a[0], a[1], a[2], a[3]); michael@0: case 5: michael@0: return new c(a[0], a[1], a[2], a[3], a[4]); michael@0: case 6: michael@0: return new c(a[0], a[1], a[2], a[3], a[4], a[5]); michael@0: case 7: michael@0: return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); michael@0: case 8: michael@0: return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); michael@0: case 9: michael@0: return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); michael@0: case 10: michael@0: return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); michael@0: } michael@0: var applyArguments = []; michael@0: for (var i = 0; i < args.length; i++) { michael@0: applyArguments[i + 1] = args[i]; michael@0: } michael@0: return new (Function.bind.apply(c, applyArguments))(); michael@0: } michael@0: Runtime.construct = construct; michael@0: function asConstructProperty(namespaces, name, flags, args) { michael@0: var self = this; michael@0: var constructor = self.asGetProperty(namespaces, name, flags); michael@0: if (Runtime.traceCallExecution.value) { michael@0: callWriter.enter('construct ' + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name)); michael@0: } michael@0: var result = construct(constructor, args); michael@0: Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result)); michael@0: return result; michael@0: } michael@0: Runtime.asConstructProperty = asConstructProperty; michael@0: function nonProxyingHasProperty(object, name) { michael@0: return name in object; michael@0: } michael@0: Runtime.nonProxyingHasProperty = nonProxyingHasProperty; michael@0: function asHasProperty(namespaces, name, flags, nonProxy) { michael@0: var self = this; michael@0: if (self.hasProperty) { michael@0: return self.hasProperty(namespaces, name, flags); michael@0: } michael@0: if (nonProxy) { michael@0: return nonProxyingHasProperty(self, self.resolveMultinameProperty(namespaces, name, flags)); michael@0: } else { michael@0: return self.resolveMultinameProperty(namespaces, name, flags) in this; michael@0: } michael@0: } michael@0: Runtime.asHasProperty = asHasProperty; michael@0: function asDeleteProperty(namespaces, name, flags) { michael@0: var self = this; michael@0: if (self.asHasTraitProperty(namespaces, name, flags)) { michael@0: return false; michael@0: } michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: return delete self[resolved]; michael@0: } michael@0: Runtime.asDeleteProperty = asDeleteProperty; michael@0: function asHasTraitProperty(namespaces, name, flags) { michael@0: var self = this; michael@0: var resolved = self.resolveMultinameProperty(namespaces, name, flags); michael@0: return self.asBindings.indexOf(resolved) >= 0; michael@0: } michael@0: Runtime.asHasTraitProperty = asHasTraitProperty; michael@0: function asGetNumericProperty(i) { michael@0: return this[i]; michael@0: } michael@0: Runtime.asGetNumericProperty = asGetNumericProperty; michael@0: function asSetNumericProperty(i, v) { michael@0: this[i] = v; michael@0: } michael@0: Runtime.asSetNumericProperty = asSetNumericProperty; michael@0: function asGetDescendants(namespaces, name, flags) { michael@0: Shumway.Debug.notImplemented('asGetDescendants'); michael@0: } michael@0: Runtime.asGetDescendants = asGetDescendants; michael@0: function asNextNameIndex(index) { michael@0: var self = this; michael@0: if (index === 0) { michael@0: defineNonEnumerableProperty(self, 'asEnumerableKeys', self.asGetEnumerableKeys()); michael@0: } michael@0: var asEnumerableKeys = self.asEnumerableKeys; michael@0: while (index < asEnumerableKeys.length) { michael@0: if (self.asHasProperty(undefined, asEnumerableKeys[index], 0)) { michael@0: return index + 1; michael@0: } michael@0: index++; michael@0: } michael@0: return 0; michael@0: } michael@0: Runtime.asNextNameIndex = asNextNameIndex; michael@0: function asNextName(index) { michael@0: var self = this; michael@0: var asEnumerableKeys = self.asEnumerableKeys; michael@0: true; michael@0: return asEnumerableKeys[index - 1]; michael@0: } michael@0: Runtime.asNextName = asNextName; michael@0: function asNextValue(index) { michael@0: return this.asGetPublicProperty(this.asNextName(index)); michael@0: } michael@0: Runtime.asNextValue = asNextValue; michael@0: function asGetEnumerableKeys() { michael@0: var self = this; michael@0: var boxedValue = self.valueOf(); michael@0: if (typeof boxedValue === 'string' || typeof boxedValue === 'number') { michael@0: return []; michael@0: } michael@0: var keys = Object.keys(this); michael@0: var result = []; michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var key = keys[i]; michael@0: if (Shumway.isNumeric(key)) { michael@0: result.push(key); michael@0: } else { michael@0: var name = Multiname.stripPublicQualifier(key); michael@0: if (name !== undefined) { michael@0: result.push(name); michael@0: } michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: Runtime.asGetEnumerableKeys = asGetEnumerableKeys; michael@0: function asTypeOf(x) { michael@0: if (x) { michael@0: if (x.constructor === String) { michael@0: return 'string'; michael@0: } else if (x.constructor === Number) { michael@0: return 'number'; michael@0: } else if (x.constructor === Boolean) { michael@0: return 'boolean'; michael@0: } else if (x instanceof XML || x instanceof XMLList) { michael@0: return 'xml'; michael@0: } michael@0: } michael@0: return typeof x; michael@0: } michael@0: Runtime.asTypeOf = asTypeOf; michael@0: function publicizeProperties(object) { michael@0: var keys = Object.keys(object); michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var k = keys[i]; michael@0: if (!Multiname.isPublicQualifiedName(k)) { michael@0: var v = object[k]; michael@0: object[Multiname.getPublicQualifiedName(k)] = v; michael@0: delete object[k]; michael@0: } michael@0: } michael@0: } michael@0: Runtime.publicizeProperties = publicizeProperties; michael@0: function asGetSlot(object, index) { michael@0: return object[object.asSlots.byID[index].name]; michael@0: } michael@0: Runtime.asGetSlot = asGetSlot; michael@0: function asSetSlot(object, index, value) { michael@0: var slotInfo = object.asSlots.byID[index]; michael@0: if (slotInfo.const) { michael@0: return; michael@0: } michael@0: var name = slotInfo.name; michael@0: var type = slotInfo.type; michael@0: if (type && type.coerce) { michael@0: object[name] = type.coerce(value); michael@0: } else { michael@0: object[name] = value; michael@0: } michael@0: } michael@0: Runtime.asSetSlot = asSetSlot; michael@0: function throwError(name, error) { michael@0: if (true) { michael@0: var message = Shumway.AVM2.formatErrorMessage.apply(null, Array.prototype.slice.call(arguments, 1)); michael@0: throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), name, message, error.code); michael@0: } else { michael@0: throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), name, Shumway.AVM2.getErrorMessage(error.code), error.code); michael@0: } michael@0: } michael@0: Runtime.throwError = throwError; michael@0: function throwErrorFromVM(domain, errorClass, message, id) { michael@0: var error = new (domain.getClass(errorClass)).instanceConstructor(message, id); michael@0: throw error; michael@0: } michael@0: Runtime.throwErrorFromVM = throwErrorFromVM; michael@0: function translateError(domain, error) { michael@0: if (error instanceof Error) { michael@0: var type = domain.getClass(error.name); michael@0: if (type) { michael@0: return new type.instanceConstructor(Shumway.AVM2.translateErrorMessage(error)); michael@0: } michael@0: Shumway.Debug.unexpected('Can\'t translate error: ' + error); michael@0: } michael@0: return error; michael@0: } michael@0: Runtime.translateError = translateError; michael@0: function asIsInstanceOf(type, value) { michael@0: return type.isInstanceOf(value); michael@0: } michael@0: Runtime.asIsInstanceOf = asIsInstanceOf; michael@0: function asIsType(type, value) { michael@0: return type.isInstance(value); michael@0: } michael@0: Runtime.asIsType = asIsType; michael@0: function asAsType(type, value) { michael@0: return asIsType(type, value) ? value : null; michael@0: } michael@0: Runtime.asAsType = asAsType; michael@0: function asCoerceByMultiname(domain, multiname, value) { michael@0: true; michael@0: switch (Multiname.getQualifiedName(multiname)) { michael@0: case Multiname.Int: michael@0: return asCoerceInt(value); michael@0: case Multiname.Uint: michael@0: return asCoerceUint(value); michael@0: case Multiname.String: michael@0: return asCoerceString(value); michael@0: case Multiname.Number: michael@0: return asCoerceNumber(value); michael@0: case Multiname.Boolean: michael@0: return asCoerceBoolean(value); michael@0: case Multiname.Object: michael@0: return asCoerceObject(value); michael@0: } michael@0: return asCoerce(domain.getType(multiname), value); michael@0: } michael@0: Runtime.asCoerceByMultiname = asCoerceByMultiname; michael@0: function asCoerce(type, value) { michael@0: if (type.coerce) { michael@0: return type.coerce(value); michael@0: } michael@0: if (Shumway.isNullOrUndefined(value)) { michael@0: return null; michael@0: } michael@0: if (type.isInstance(value)) { michael@0: return value; michael@0: } else { michael@0: true; michael@0: } michael@0: } michael@0: Runtime.asCoerce = asCoerce; michael@0: function asCoerceString(x) { michael@0: if (typeof x === 'string') { michael@0: return x; michael@0: } else if (x == undefined) { michael@0: return null; michael@0: } michael@0: return x + ''; michael@0: } michael@0: Runtime.asCoerceString = asCoerceString; michael@0: function asCoerceInt(x) { michael@0: return x | 0; michael@0: } michael@0: Runtime.asCoerceInt = asCoerceInt; michael@0: function asCoerceUint(x) { michael@0: return x >>> 0; michael@0: } michael@0: Runtime.asCoerceUint = asCoerceUint; michael@0: function asCoerceNumber(x) { michael@0: return +x; michael@0: } michael@0: Runtime.asCoerceNumber = asCoerceNumber; michael@0: function asCoerceBoolean(x) { michael@0: return !(!x); michael@0: } michael@0: Runtime.asCoerceBoolean = asCoerceBoolean; michael@0: function asCoerceObject(x) { michael@0: if (x == undefined) { michael@0: return null; michael@0: } michael@0: if (typeof x === 'string' || typeof x === 'number') { michael@0: return x; michael@0: } michael@0: return Object(x); michael@0: } michael@0: Runtime.asCoerceObject = asCoerceObject; michael@0: function asDefaultCompareFunction(a, b) { michael@0: return String(a).localeCompare(String(b)); michael@0: } michael@0: Runtime.asDefaultCompareFunction = asDefaultCompareFunction; michael@0: function asCompare(a, b, options, compareFunction) { michael@0: true; michael@0: true; michael@0: var result = 0; michael@0: if (!compareFunction) { michael@0: compareFunction = asDefaultCompareFunction; michael@0: } michael@0: if (options & 1) { michael@0: a = String(a).toLowerCase(); michael@0: b = String(b).toLowerCase(); michael@0: } michael@0: if (options & 16) { michael@0: a = Shumway.toNumber(a); michael@0: b = Shumway.toNumber(b); michael@0: result = a < b ? -1 : a > b ? 1 : 0; michael@0: } else { michael@0: result = compareFunction(a, b); michael@0: } michael@0: if (options & 2) { michael@0: result *= -1; michael@0: } michael@0: return result; michael@0: } michael@0: Runtime.asCompare = asCompare; michael@0: function asAdd(l, r) { michael@0: if (typeof l === 'string' || typeof r === 'string') { michael@0: return String(l) + String(r); michael@0: } michael@0: return l + r; michael@0: } michael@0: Runtime.asAdd = asAdd; michael@0: function asHasNext2(object, index) { michael@0: if (Shumway.isNullOrUndefined(object)) { michael@0: return { michael@0: index: 0, michael@0: object: null michael@0: }; michael@0: } michael@0: object = boxValue(object); michael@0: var nextIndex = object.asNextNameIndex(index); michael@0: if (nextIndex > 0) { michael@0: return { michael@0: index: nextIndex, michael@0: object: object michael@0: }; michael@0: } michael@0: while (true) { michael@0: var object = Object.getPrototypeOf(object); michael@0: if (!object) { michael@0: return { michael@0: index: 0, michael@0: object: null michael@0: }; michael@0: } michael@0: nextIndex = object.asNextNameIndex(0); michael@0: if (nextIndex > 0) { michael@0: return { michael@0: index: nextIndex, michael@0: object: object michael@0: }; michael@0: } michael@0: } michael@0: return { michael@0: index: 0, michael@0: object: null michael@0: }; michael@0: } michael@0: Runtime.asHasNext2 = asHasNext2; michael@0: function getDescendants(object, mn) { michael@0: if (!isXMLType(object)) { michael@0: throw 'Not XML object in getDescendants'; michael@0: } michael@0: return object.descendants(mn); michael@0: } michael@0: Runtime.getDescendants = getDescendants; michael@0: function checkFilter(value) { michael@0: if (!value.class || !isXMLType(value)) { michael@0: throw 'TypeError operand of childFilter not of XML type'; michael@0: } michael@0: return value; michael@0: } michael@0: Runtime.checkFilter = checkFilter; michael@0: function initializeGlobalObject(global) { michael@0: var VM_NATIVE_BUILTIN_SURROGATES = [ michael@0: { michael@0: name: 'Object', michael@0: methods: [ michael@0: 'toString', michael@0: 'valueOf' michael@0: ] michael@0: }, michael@0: { michael@0: name: 'Function', michael@0: methods: [ michael@0: 'toString', michael@0: 'valueOf' michael@0: ] michael@0: } michael@0: ]; michael@0: var originals = global[Runtime.VM_NATIVE_BUILTIN_ORIGINALS] = createEmptyObject(); michael@0: VM_NATIVE_BUILTIN_SURROGATES.forEach(function (surrogate) { michael@0: var object = global[surrogate.name]; michael@0: originals[surrogate.name] = createEmptyObject(); michael@0: surrogate.methods.forEach(function (originalFunctionName) { michael@0: var originalFunction; michael@0: if (object.prototype.hasOwnProperty(originalFunctionName)) { michael@0: originalFunction = object.prototype[originalFunctionName]; michael@0: } else { michael@0: originalFunction = originals['Object'][originalFunctionName]; michael@0: } michael@0: originals[surrogate.name][originalFunctionName] = originalFunction; michael@0: var overrideFunctionName = Multiname.getPublicQualifiedName(originalFunctionName); michael@0: if (useSurrogates) { michael@0: global[surrogate.name].prototype[originalFunctionName] = function surrogate() { michael@0: if (this[overrideFunctionName]) { michael@0: return this[overrideFunctionName](); michael@0: } michael@0: return originalFunction.call(this); michael@0: }; michael@0: } michael@0: }); michael@0: }); michael@0: [ michael@0: 'Object', michael@0: 'Number', michael@0: 'Boolean', michael@0: 'String', michael@0: 'Array', michael@0: 'Date', michael@0: 'RegExp' michael@0: ].forEach(function (name) { michael@0: defineReadOnlyProperty(global[name].prototype, Runtime.VM_NATIVE_PROTOTYPE_FLAG, true); michael@0: }); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'getNamespaceResolutionMap', getNamespaceResolutionMap); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'resolveMultinameProperty', resolveMultinameProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asGetProperty', asGetProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asGetPublicProperty', asGetPublicProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asGetResolvedStringProperty', asGetResolvedStringProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asSetProperty', asSetProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asSetPublicProperty', asSetPublicProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asDefineProperty', asDefineProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asDefinePublicProperty', asDefinePublicProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asCallProperty', asCallProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asCallSuper', asCallSuper); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asGetSuper', asGetSuper); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asSetSuper', asSetSuper); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asCallPublicProperty', asCallPublicProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asCallResolvedStringProperty', asCallResolvedStringProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asConstructProperty', asConstructProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asHasProperty', asHasProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asHasTraitProperty', asHasTraitProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asDeleteProperty', asDeleteProperty); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asNextName', asNextName); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asNextValue', asNextValue); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asNextNameIndex', asNextNameIndex); michael@0: defineNonEnumerableProperty(global.Object.prototype, 'asGetEnumerableKeys', asGetEnumerableKeys); michael@0: [ michael@0: 'Array', michael@0: 'Int8Array', michael@0: 'Uint8Array', michael@0: 'Uint8ClampedArray', michael@0: 'Int16Array', michael@0: 'Uint16Array', michael@0: 'Int32Array', michael@0: 'Uint32Array', michael@0: 'Float32Array', michael@0: 'Float64Array' michael@0: ].forEach(function (name) { michael@0: if (!(name in global)) { michael@0: log(name + ' was not found in globals'); michael@0: return; michael@0: } michael@0: defineNonEnumerableProperty(global[name].prototype, 'asGetNumericProperty', asGetNumericProperty); michael@0: defineNonEnumerableProperty(global[name].prototype, 'asSetNumericProperty', asSetNumericProperty); michael@0: defineNonEnumerableProperty(global[name].prototype, 'asGetProperty', asGetPropertyLikelyNumeric); michael@0: defineNonEnumerableProperty(global[name].prototype, 'asSetProperty', asSetPropertyLikelyNumeric); michael@0: }); michael@0: global.Array.prototype.asGetProperty = function (namespaces, name, flags) { michael@0: if (typeof name === 'number') { michael@0: return this[name]; michael@0: } michael@0: return asGetProperty.call(this, namespaces, name, flags); michael@0: }; michael@0: global.Array.prototype.asSetProperty = function (namespaces, name, flags, value) { michael@0: if (typeof name === 'number') { michael@0: this[name] = value; michael@0: return; michael@0: } michael@0: return asSetProperty.call(this, namespaces, name, flags, value); michael@0: }; michael@0: } michael@0: Runtime.initializeGlobalObject = initializeGlobalObject; michael@0: function nameInTraits(object, qn) { michael@0: if (object.hasOwnProperty(Runtime.VM_BINDINGS) && object.hasOwnProperty(qn)) { michael@0: return true; michael@0: } michael@0: var proto = Object.getPrototypeOf(object); michael@0: return proto.hasOwnProperty(Runtime.VM_BINDINGS) && proto.hasOwnProperty(qn); michael@0: } michael@0: Runtime.nameInTraits = nameInTraits; michael@0: function CatchScopeObject(domain, trait) { michael@0: if (trait) { michael@0: new Shumway.AVM2.Runtime.CatchBindings(new Shumway.AVM2.Runtime.Scope(null, this), trait).applyTo(domain, this); michael@0: } michael@0: } michael@0: Runtime.CatchScopeObject = CatchScopeObject; michael@0: var Global = function () { michael@0: function Global(script) { michael@0: this.scriptInfo = script; michael@0: script.global = this; michael@0: this.scriptBindings = new Shumway.AVM2.Runtime.ScriptBindings(script, new Shumway.AVM2.Runtime.Scope(null, this, false)); michael@0: this.scriptBindings.applyTo(script.abc.applicationDomain, this); michael@0: script.loaded = true; michael@0: } michael@0: Global.prototype.toString = function () { michael@0: return '[object global]'; michael@0: }; michael@0: Global.prototype.isExecuted = function () { michael@0: return this.scriptInfo.executed; michael@0: }; michael@0: Global.prototype.isExecuting = function () { michael@0: return this.scriptInfo.executing; michael@0: }; michael@0: Global.prototype.ensureExecuted = function () { michael@0: Shumway.AVM2.Runtime.ensureScriptIsExecuted(this.scriptInfo); michael@0: }; michael@0: return Global; michael@0: }(); michael@0: Runtime.Global = Global; michael@0: defineNonEnumerableProperty(Global.prototype, Multiname.getPublicQualifiedName('toString'), function () { michael@0: return this.toString(); michael@0: }); michael@0: var LazyInitializer = function () { michael@0: function LazyInitializer(target) { michael@0: this.target = target; michael@0: } michael@0: LazyInitializer.create = function (target) { michael@0: if (target.asLazyInitializer) { michael@0: return target.asLazyInitializer; michael@0: } michael@0: return target.asLazyInitializer = new LazyInitializer(target); michael@0: }; michael@0: LazyInitializer.prototype.getName = function () { michael@0: if (this.name) { michael@0: return this.name; michael@0: } michael@0: var target = this.target, initialize; michael@0: if (this.target instanceof ScriptInfo) { michael@0: var scriptInfo = target; michael@0: this.name = '$' + Shumway.StringUtilities.variableLengthEncodeInt32(scriptInfo.hash); michael@0: initialize = function () { michael@0: Shumway.AVM2.Runtime.ensureScriptIsExecuted(target, 'Lazy Initializer'); michael@0: return scriptInfo.global; michael@0: }; michael@0: } else if (this.target instanceof ClassInfo) { michael@0: var classInfo = target; michael@0: this.name = '$' + Shumway.StringUtilities.variableLengthEncodeInt32(classInfo.hash); michael@0: initialize = function () { michael@0: if (classInfo.classObject) { michael@0: return classInfo.classObject; michael@0: } michael@0: return classInfo.abc.applicationDomain.getProperty(classInfo.instanceInfo.name); michael@0: }; michael@0: } else { michael@0: Shumway.Debug.notImplemented(String(target)); michael@0: } michael@0: var name = this.name; michael@0: Object.defineProperty(LazyInitializer._holder, name, { michael@0: get: function () { michael@0: var value = initialize(); michael@0: Object.defineProperty(LazyInitializer._holder, name, { michael@0: value: value, michael@0: writable: true michael@0: }); michael@0: return value; michael@0: }, michael@0: configurable: true michael@0: }); michael@0: return name; michael@0: }; michael@0: LazyInitializer._holder = jsGlobal; michael@0: return LazyInitializer; michael@0: }(); michael@0: Runtime.LazyInitializer = LazyInitializer; michael@0: function forEachPublicProperty(object, fn, self) { michael@0: if (!object.asBindings) { michael@0: for (var key in object) { michael@0: fn.call(self, key, object[key]); michael@0: } michael@0: return; michael@0: } michael@0: for (var key in object) { michael@0: if (Shumway.isNumeric(key)) { michael@0: fn.call(self, key, object[key]); michael@0: } else if (Multiname.isPublicQualifiedName(key) && object.asBindings.indexOf(key) < 0) { michael@0: var name = Multiname.stripPublicQualifier(key); michael@0: fn.call(self, name, object[key]); michael@0: } michael@0: } michael@0: } michael@0: Runtime.forEachPublicProperty = forEachPublicProperty; michael@0: function wrapJSObject(object) { michael@0: var wrapper = Object.create(object); michael@0: for (var i in object) { michael@0: Object.defineProperty(wrapper, Multiname.getPublicQualifiedName(i), function (object, i) { michael@0: return { michael@0: get: function () { michael@0: return object[i]; michael@0: }, michael@0: set: function (value) { michael@0: object[i] = value; michael@0: }, michael@0: enumerable: true michael@0: }; michael@0: }(object, i)); michael@0: } michael@0: return wrapper; michael@0: } michael@0: Runtime.wrapJSObject = wrapJSObject; michael@0: function asCreateActivation(methodInfo) { michael@0: return Object.create(methodInfo.activationPrototype); michael@0: } michael@0: Runtime.asCreateActivation = asCreateActivation; michael@0: var GlobalMultinameResolver = function () { michael@0: function GlobalMultinameResolver() { michael@0: } michael@0: GlobalMultinameResolver.updateTraits = function (traits) { michael@0: for (var i = 0; i < traits.length; i++) { michael@0: var trait = traits[i]; michael@0: var name = trait.name.name; michael@0: var namespace = trait.name.getNamespace(); michael@0: if (!namespace.isDynamic()) { michael@0: GlobalMultinameResolver.hasNonDynamicNamespaces[name] = true; michael@0: if (GlobalMultinameResolver.wasResolved[name]) { michael@0: Shumway.Debug.notImplemented('We have to the undo the optimization, ' + name + ' can now bind to ' + namespace); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: GlobalMultinameResolver.loadAbc = function (abc) { michael@0: if (!Runtime.globalMultinameAnalysis.value) { michael@0: return; michael@0: } michael@0: var scripts = abc.scripts; michael@0: var classes = abc.classes; michael@0: var methods = abc.methods; michael@0: for (var i = 0; i < scripts.length; i++) { michael@0: GlobalMultinameResolver.updateTraits(scripts[i].traits); michael@0: } michael@0: for (var i = 0; i < classes.length; i++) { michael@0: GlobalMultinameResolver.updateTraits(classes[i].traits); michael@0: GlobalMultinameResolver.updateTraits(classes[i].instanceInfo.traits); michael@0: } michael@0: for (var i = 0; i < methods.length; i++) { michael@0: if (methods[i].traits) { michael@0: GlobalMultinameResolver.updateTraits(methods[i].traits); michael@0: } michael@0: } michael@0: }; michael@0: GlobalMultinameResolver.resolveMultiname = function (multiname) { michael@0: var name = multiname.name; michael@0: if (GlobalMultinameResolver.hasNonDynamicNamespaces[name]) { michael@0: return; michael@0: } michael@0: GlobalMultinameResolver.wasResolved[name] = true; michael@0: return new Multiname([ michael@0: Namespace.PUBLIC michael@0: ], multiname.name); michael@0: }; michael@0: GlobalMultinameResolver.hasNonDynamicNamespaces = createEmptyObject(); michael@0: GlobalMultinameResolver.wasResolved = createEmptyObject(); michael@0: return GlobalMultinameResolver; michael@0: }(); michael@0: Runtime.GlobalMultinameResolver = GlobalMultinameResolver; michael@0: var ActivationInfo = function () { michael@0: function ActivationInfo(methodInfo) { michael@0: this.methodInfo = methodInfo; michael@0: } michael@0: return ActivationInfo; michael@0: }(); michael@0: Runtime.ActivationInfo = ActivationInfo; michael@0: function sliceArguments(args, offset) { michael@0: if (typeof offset === 'undefined') { michael@0: offset = 0; michael@0: } michael@0: return Array.prototype.slice.call(args, offset); michael@0: } michael@0: Runtime.sliceArguments = sliceArguments; michael@0: function canCompile(mi) { michael@0: if (!mi.hasBody) { michael@0: return false; michael@0: } michael@0: if (mi.hasExceptions() && !compilerEnableExceptions.value) { michael@0: return false; michael@0: } else if (mi.code.length > compilerMaximumMethodSize.value) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: Runtime.canCompile = canCompile; michael@0: function shouldCompile(mi) { michael@0: if (!canCompile(mi)) { michael@0: return false; michael@0: } michael@0: if (mi.isClassInitializer || mi.isScriptInitializer) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: Runtime.shouldCompile = shouldCompile; michael@0: function forceCompile(mi) { michael@0: if (mi.hasExceptions()) { michael@0: return false; michael@0: } michael@0: var holder = mi.holder; michael@0: if (holder instanceof ClassInfo) { michael@0: holder = holder.instanceInfo; michael@0: } michael@0: if (holder instanceof InstanceInfo) { michael@0: var packageName = holder.name.namespaces[0].uri; michael@0: switch (packageName) { michael@0: case 'flash.geom': michael@0: case 'flash.events': michael@0: return true; michael@0: default: michael@0: break; michael@0: } michael@0: var className = holder.name.getOriginalName(); michael@0: switch (className) { michael@0: case 'com.google.youtube.model.VideoData': michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: Runtime.forceCompile = forceCompile; michael@0: Runtime.CODE_CACHE = createEmptyObject(); michael@0: function searchCodeCache(methodInfo) { michael@0: if (!Runtime.codeCaching.value) { michael@0: return; michael@0: } michael@0: var cacheInfo = Runtime.CODE_CACHE[methodInfo.abc.hash]; michael@0: if (!cacheInfo) { michael@0: warn('Cannot Find Code Cache For ABC, name: ' + methodInfo.abc.name + ', hash: ' + methodInfo.abc.hash); michael@0: Counter.count('Code Cache ABC Miss'); michael@0: return; michael@0: } michael@0: if (!cacheInfo.isInitialized) { michael@0: methodInfo.abc.scripts.forEach(function (scriptInfo) { michael@0: LazyInitializer.create(scriptInfo).getName(); michael@0: }); michael@0: methodInfo.abc.classes.forEach(function (classInfo) { michael@0: LazyInitializer.create(classInfo).getName(); michael@0: }); michael@0: cacheInfo.isInitialized = true; michael@0: } michael@0: var method = cacheInfo.methods[methodInfo.index]; michael@0: if (!method) { michael@0: if (methodInfo.isInstanceInitializer || methodInfo.isClassInitializer) { michael@0: Counter.count('Code Cache Query On Initializer'); michael@0: } else { michael@0: Counter.count('Code Cache MISS ON OTHER'); michael@0: warn('Shouldn\'t MISS: ' + methodInfo + ' ' + methodInfo.debugName); michael@0: } michael@0: Counter.count('Code Cache Miss'); michael@0: return; michael@0: } michael@0: log('Linking CC: ' + methodInfo); michael@0: Counter.count('Code Cache Hit'); michael@0: return method; michael@0: } michael@0: Runtime.searchCodeCache = searchCodeCache; michael@0: function createInterpretedFunction(methodInfo, scope, hasDynamicScope) { michael@0: var mi = methodInfo; michael@0: var hasDefaults = false; michael@0: var defaults = mi.parameters.map(function (p) { michael@0: if (p.value !== undefined) { michael@0: hasDefaults = true; michael@0: } michael@0: return p.value; michael@0: }); michael@0: var fn; michael@0: if (hasDynamicScope) { michael@0: fn = function (scope) { michael@0: var global = this === jsGlobal ? scope.global.object : this; michael@0: var args = sliceArguments(arguments, 1); michael@0: if (hasDefaults && args.length < defaults.length) { michael@0: args = args.concat(defaults.slice(args.length - defaults.length)); michael@0: } michael@0: return Shumway.AVM2.Interpreter.interpretMethod(global, methodInfo, scope, args); michael@0: }; michael@0: } else { michael@0: fn = function () { michael@0: var global = this === jsGlobal ? scope.global.object : this; michael@0: var args = sliceArguments(arguments); michael@0: if (hasDefaults && args.length < defaults.length) { michael@0: args = args.concat(defaults.slice(arguments.length - defaults.length)); michael@0: } michael@0: return Shumway.AVM2.Interpreter.interpretMethod(global, methodInfo, scope, args); michael@0: }; michael@0: } michael@0: fn.instanceConstructor = fn; michael@0: fn.debugName = 'Interpreter Function #' + vmNextInterpreterFunctionId++; michael@0: return fn; michael@0: } michael@0: Runtime.createInterpretedFunction = createInterpretedFunction; michael@0: function debugName(value) { michael@0: if (Shumway.isFunction(value)) { michael@0: return value.debugName; michael@0: } michael@0: return value; michael@0: } michael@0: Runtime.debugName = debugName; michael@0: function createCompiledFunction(methodInfo, scope, hasDynamicScope, breakpoint, deferCompilation) { michael@0: var mi = methodInfo; michael@0: var cached = searchCodeCache(mi); michael@0: if (!cached) { michael@0: var result = Compiler.compileMethod(mi, scope, hasDynamicScope); michael@0: var parameters = result.parameters; michael@0: var body = result.body; michael@0: } michael@0: var fnName = mi.name ? Multiname.getQualifiedName(mi.name) : 'fn' + compiledFunctionCount; michael@0: if (mi.holder) { michael@0: var fnNamePrefix = ''; michael@0: if (mi.holder instanceof ClassInfo) { michael@0: fnNamePrefix = 'static$' + mi.holder.instanceInfo.name.getName(); michael@0: } else if (mi.holder instanceof InstanceInfo) { michael@0: fnNamePrefix = mi.holder.name.getName(); michael@0: } else if (mi.holder instanceof ScriptInfo) { michael@0: fnNamePrefix = 'script'; michael@0: } michael@0: fnName = fnNamePrefix + '$' + fnName; michael@0: } michael@0: fnName = Shumway.StringUtilities.escapeString(fnName); michael@0: if (mi.verified) { michael@0: fnName += '$V'; michael@0: } michael@0: if (compiledFunctionCount == functionBreak.value || breakpoint) { michael@0: body = '{ debugger; \n' + body + '}'; michael@0: } michael@0: if (!cached) { michael@0: var fnSource = 'function ' + fnName + ' (' + parameters.join(', ') + ') ' + body; michael@0: } michael@0: if (traceLevel.value > 1) { michael@0: mi.trace(new IndentingWriter(), mi.abc); michael@0: } michael@0: mi.debugTrace = function () { michael@0: mi.trace(new IndentingWriter(), mi.abc); michael@0: }; michael@0: if (traceLevel.value > 0) { michael@0: log(fnSource); michael@0: } michael@0: var fn = cached || new Function('return ' + fnSource)(); michael@0: fn.debugName = 'Compiled Function #' + vmNextCompiledFunctionId++; michael@0: return fn; michael@0: } michael@0: Runtime.createCompiledFunction = createCompiledFunction; michael@0: function createFunction(mi, scope, hasDynamicScope, breakpoint) { michael@0: if (typeof breakpoint === 'undefined') { michael@0: breakpoint = false; michael@0: } michael@0: true; michael@0: if (mi.freeMethod) { michael@0: if (hasDynamicScope) { michael@0: return Shumway.AVM2.Runtime.bindFreeMethodScope(mi, scope); michael@0: } michael@0: return mi.freeMethod; michael@0: } michael@0: var fn; michael@0: if (fn = Shumway.AVM2.Runtime.checkMethodOverrides(mi)) { michael@0: true; michael@0: return fn; michael@0: } michael@0: ensureFunctionIsInitialized(mi); michael@0: totalFunctionCount++; michael@0: var useInterpreter = false; michael@0: if ((mi.abc.applicationDomain.mode === 1 || !shouldCompile(mi)) && !forceCompile(mi)) { michael@0: useInterpreter = true; michael@0: } michael@0: if (compileOnly.value >= 0) { michael@0: if (Number(compileOnly.value) !== totalFunctionCount) { michael@0: log('Compile Only Skipping ' + totalFunctionCount); michael@0: useInterpreter = true; michael@0: } michael@0: } michael@0: if (compileUntil.value >= 0) { michael@0: if (totalFunctionCount > 1000) { michael@0: log(Shumway.Debug.backtrace()); michael@0: log(Shumway.AVM2.Runtime.AVM2.getStackTrace()); michael@0: } michael@0: if (totalFunctionCount > compileUntil.value) { michael@0: log('Compile Until Skipping ' + totalFunctionCount); michael@0: useInterpreter = true; michael@0: } michael@0: } michael@0: if (useInterpreter) { michael@0: mi.freeMethod = createInterpretedFunction(mi, scope, hasDynamicScope); michael@0: } else { michael@0: compiledFunctionCount++; michael@0: if (compileOnly.value >= 0 || compileUntil.value >= 0) { michael@0: log('Compiling ' + totalFunctionCount); michael@0: } michael@0: mi.freeMethod = createCompiledFunction(mi, scope, hasDynamicScope, breakpoint, mi.isInstanceInitializer); michael@0: } michael@0: mi.freeMethod.methodInfo = mi; michael@0: if (hasDynamicScope) { michael@0: return Shumway.AVM2.Runtime.bindFreeMethodScope(mi, scope); michael@0: } michael@0: return mi.freeMethod; michael@0: } michael@0: Runtime.createFunction = createFunction; michael@0: function ensureFunctionIsInitialized(methodInfo) { michael@0: var mi = methodInfo; michael@0: if (!mi.analysis) { michael@0: mi.analysis = new Analysis(mi); michael@0: if (mi.needsActivation()) { michael@0: mi.activationPrototype = new ActivationInfo(mi); michael@0: new Shumway.AVM2.Runtime.ActivationBindings(mi).applyTo(mi.abc.applicationDomain, mi.activationPrototype); michael@0: } michael@0: var exceptions = mi.exceptions; michael@0: for (var i = 0, j = exceptions.length; i < j; i++) { michael@0: var handler = exceptions[i]; michael@0: if (handler.varName) { michael@0: var varTrait = Object.create(Trait.prototype); michael@0: varTrait.kind = 0; michael@0: varTrait.name = handler.varName; michael@0: varTrait.typeName = handler.typeName; michael@0: varTrait.holder = mi; michael@0: handler.scopeObject = new CatchScopeObject(mi.abc.applicationDomain, varTrait); michael@0: } else { michael@0: handler.scopeObject = new CatchScopeObject(undefined, undefined); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: Runtime.ensureFunctionIsInitialized = ensureFunctionIsInitialized; michael@0: function getTraitFunction(trait, scope, natives) { michael@0: true; michael@0: true; michael@0: var mi = trait.methodInfo; michael@0: var fn; michael@0: if (mi.isNative()) { michael@0: var md = trait.metadata; michael@0: if (md && md.native) { michael@0: var nativeName = md.native.value[0].value; michael@0: var makeNativeFunction = getNative(nativeName); michael@0: fn = makeNativeFunction && makeNativeFunction(null, scope); michael@0: } else if (md && md.unsafeJSNative) { michael@0: fn = getNative(md.unsafeJSNative.value[0].value); michael@0: } else if (natives) { michael@0: var k = Multiname.getName(mi.name); michael@0: if (trait.isGetter()) { michael@0: fn = natives[k] ? natives[k].get : undefined; michael@0: } else if (trait.isSetter()) { michael@0: fn = natives[k] ? natives[k].set : undefined; michael@0: } else { michael@0: fn = natives[k]; michael@0: } michael@0: } michael@0: if (!fn) { michael@0: Shumway.Debug.warning('No native method for: ' + trait.kindName() + ' ' + mi.holder.name + '::' + Multiname.getQualifiedName(mi.name)); michael@0: return function (mi) { michael@0: return function () { michael@0: Shumway.Debug.warning('Calling undefined native method: ' + trait.kindName() + ' ' + mi.holder.name + '::' + Multiname.getQualifiedName(mi.name)); michael@0: }; michael@0: }(mi); michael@0: } michael@0: } else { michael@0: if (Runtime.traceExecution.value >= 2) { michael@0: log('Creating Function For Trait: ' + trait.holder + ' ' + trait); michael@0: } michael@0: fn = createFunction(mi, scope, false, false); michael@0: true; michael@0: } michael@0: if (Runtime.traceExecution.value >= 3) { michael@0: log('Made Function: ' + Multiname.getQualifiedName(mi.name)); michael@0: } michael@0: return fn; michael@0: } michael@0: Runtime.getTraitFunction = getTraitFunction; michael@0: function createClass(classInfo, baseClass, scope) { michael@0: true; michael@0: var ci = classInfo; michael@0: var ii = ci.instanceInfo; michael@0: var domain = ci.abc.applicationDomain; michael@0: var className = Multiname.getName(ii.name); michael@0: if (Runtime.traceExecution.value) { michael@0: log('Creating ' + (ii.isInterface() ? 'Interface' : 'Class') + ': ' + className + (ci.native ? ' replaced with native ' + ci.native.cls : '')); michael@0: } michael@0: var cls; michael@0: if (ii.isInterface()) { michael@0: cls = Shumway.AVM2.Runtime.Interface.createInterface(classInfo); michael@0: } else { michael@0: cls = Shumway.AVM2.Runtime.Class.createClass(classInfo, baseClass, scope); michael@0: } michael@0: if (Runtime.traceClasses.value) { michael@0: domain.loadedClasses.push(cls); michael@0: domain.traceLoadedClasses(true); michael@0: } michael@0: if (ii.isInterface()) { michael@0: return cls; michael@0: } michael@0: domain.onMessage.notify1('classCreated', cls); michael@0: if (cls.instanceConstructor && cls !== Shumway.AVM2.Runtime.Class) { michael@0: cls.verify(); michael@0: } michael@0: if (baseClass && (Multiname.getQualifiedName(baseClass.classInfo.instanceInfo.name.name) === 'Proxy' || baseClass.isProxy)) { michael@0: installProxyClassWrapper(cls); michael@0: cls.isProxy = true; michael@0: } michael@0: classInfo.classObject = cls; michael@0: createFunction(classInfo.init, scope, false, false).call(cls); michael@0: if (Runtime.sealConstTraits) { michael@0: this.sealConstantTraits(cls, ci.traits); michael@0: } michael@0: return cls; michael@0: } michael@0: Runtime.createClass = createClass; michael@0: function sealConstantTraits(object, traits) { michael@0: for (var i = 0, j = traits.length; i < j; i++) { michael@0: var trait = traits[i]; michael@0: if (trait.isConst()) { michael@0: var qn = Multiname.getQualifiedName(trait.name); michael@0: var value = object[qn]; michael@0: (function (qn, value) { michael@0: Object.defineProperty(object, qn, { michael@0: configurable: false, michael@0: enumerable: false, michael@0: get: function () { michael@0: return value; michael@0: }, michael@0: set: function () { michael@0: throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), 'ReferenceError', 'Illegal write to read-only property ' + qn + '.', 0); michael@0: } michael@0: }); michael@0: }(qn, value)); michael@0: } michael@0: } michael@0: } michael@0: Runtime.sealConstantTraits = sealConstantTraits; michael@0: function applyType(domain, factory, types) { michael@0: var factoryClassName = factory.classInfo.instanceInfo.name.name; michael@0: if (factoryClassName === 'Vector') { michael@0: true; michael@0: var type = types[0]; michael@0: var typeClassName; michael@0: if (!Shumway.isNullOrUndefined(type)) { michael@0: typeClassName = type.classInfo.instanceInfo.name.name.toLowerCase(); michael@0: switch (typeClassName) { michael@0: case 'int': michael@0: case 'uint': michael@0: case 'double': michael@0: case 'object': michael@0: return domain.getClass('packageInternal __AS3__.vec.Vector$' + typeClassName); michael@0: } michael@0: } michael@0: return domain.getClass('packageInternal __AS3__.vec.Vector$object').applyType(type); michael@0: } else { michael@0: return Shumway.Debug.notImplemented(factoryClassName); michael@0: } michael@0: } michael@0: Runtime.applyType = applyType; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var CC = Shumway.AVM2.Runtime.CODE_CACHE; michael@0: var VM_LENGTH = Shumway.AVM2.Runtime.VM_LENGTH; michael@0: var VM_IS_PROXY = Shumway.AVM2.Runtime.VM_IS_PROXY; michael@0: var VM_CALL_PROXY = Shumway.AVM2.Runtime.VM_CALL_PROXY; michael@0: var VM_NATIVE_BUILTIN_ORIGINALS = Shumway.AVM2.Runtime.VM_NATIVE_BUILTIN_ORIGINALS; michael@0: var VM_OPEN_METHOD_PREFIX = 'm'; michael@0: var VM_OPEN_SET_METHOD_PREFIX = 's'; michael@0: var VM_OPEN_GET_METHOD_PREFIX = 'g'; michael@0: var SAVED_SCOPE_NAME = '$SS'; michael@0: var originalStringReplace = String.prototype.replace; michael@0: XRegExp.install({ michael@0: natives: true michael@0: }); michael@0: var callWriter = new IndentingWriter(false, function (str) { michael@0: print(str); michael@0: }); michael@0: var objectIDs = 0; michael@0: var OBJECT_NAME = 'Object Name'; michael@0: function objectConstantName(object) { michael@0: true; michael@0: if (object.hasOwnProperty(OBJECT_NAME)) { michael@0: return object[OBJECT_NAME]; michael@0: } michael@0: if (object instanceof LazyInitializer) { michael@0: return object.getName(); michael@0: } michael@0: var name, id = objectIDs++; michael@0: if (object instanceof Global) { michael@0: name = '$G' + id; michael@0: } else if (object instanceof Multiname) { michael@0: name = '$M' + id; michael@0: } else if (isClass(object)) { michael@0: name = '$C' + id; michael@0: } else { michael@0: name = '$O' + id; michael@0: } michael@0: Object.defineProperty(object, OBJECT_NAME, { michael@0: value: name, michael@0: writable: false, michael@0: enumerable: false michael@0: }); michael@0: jsGlobal[name] = object; michael@0: return name; michael@0: } michael@0: var isClass = Shumway.AVM2.Runtime.isClass; michael@0: var isTrampoline = Shumway.AVM2.Runtime.isTrampoline; michael@0: var isMemoizer = Shumway.AVM2.Runtime.isMemoizer; michael@0: var LazyInitializer = Shumway.AVM2.Runtime.LazyInitializer; michael@0: var getNamespaceResolutionMap = Shumway.AVM2.Runtime.getNamespaceResolutionMap; michael@0: var resolveMultinameProperty = Shumway.AVM2.Runtime.resolveMultinameProperty; michael@0: var asGetPublicProperty = Shumway.AVM2.Runtime.asGetPublicProperty; michael@0: var asGetProperty = Shumway.AVM2.Runtime.asGetProperty; michael@0: var asGetPropertyLikelyNumeric = Shumway.AVM2.Runtime.asGetPropertyLikelyNumeric; michael@0: var asGetResolvedStringProperty = Shumway.AVM2.Runtime.asGetResolvedStringProperty; michael@0: var asCallResolvedStringProperty = Shumway.AVM2.Runtime.asCallResolvedStringProperty; michael@0: var asGetResolvedStringPropertyFallback = Shumway.AVM2.Runtime.asGetResolvedStringPropertyFallback; michael@0: var asSetPublicProperty = Shumway.AVM2.Runtime.asSetPublicProperty; michael@0: var asSetProperty = Shumway.AVM2.Runtime.asSetProperty; michael@0: var asSetPropertyLikelyNumeric = Shumway.AVM2.Runtime.asSetPropertyLikelyNumeric; michael@0: var asDefinePublicProperty = Shumway.AVM2.Runtime.asDefinePublicProperty; michael@0: var asDefineProperty = Shumway.AVM2.Runtime.asDefineProperty; michael@0: var asCallPublicProperty = Shumway.AVM2.Runtime.asCallPublicProperty; michael@0: var asCallProperty = Shumway.AVM2.Runtime.asCallProperty; michael@0: var asCallSuper = Shumway.AVM2.Runtime.asCallSuper; michael@0: var asSetSuper = Shumway.AVM2.Runtime.asSetSuper; michael@0: var asGetSuper = Shumway.AVM2.Runtime.asGetSuper; michael@0: var construct = Shumway.AVM2.Runtime.construct; michael@0: var asConstructProperty = Shumway.AVM2.Runtime.asConstructProperty; michael@0: var asHasProperty = Shumway.AVM2.Runtime.asHasProperty; michael@0: var asDeleteProperty = Shumway.AVM2.Runtime.asDeleteProperty; michael@0: var asGetNumericProperty = Shumway.AVM2.Runtime.asGetNumericProperty; michael@0: var asSetNumericProperty = Shumway.AVM2.Runtime.asSetNumericProperty; michael@0: var asGetDescendants = Shumway.AVM2.Runtime.asGetDescendants; michael@0: var asNextNameIndex = Shumway.AVM2.Runtime.asNextNameIndex; michael@0: var asNextName = Shumway.AVM2.Runtime.asNextName; michael@0: var asNextValue = Shumway.AVM2.Runtime.asNextValue; michael@0: var asGetEnumerableKeys = Shumway.AVM2.Runtime.asGetEnumerableKeys; michael@0: var initializeGlobalObject = Shumway.AVM2.Runtime.initializeGlobalObject; michael@0: initializeGlobalObject(jsGlobal); michael@0: var asTypeOf = Shumway.AVM2.Runtime.asTypeOf; michael@0: var publicizeProperties = Shumway.AVM2.Runtime.publicizeProperties; michael@0: var asGetSlot = Shumway.AVM2.Runtime.asGetSlot; michael@0: var asSetSlot = Shumway.AVM2.Runtime.asSetSlot; michael@0: var asHasNext2 = Shumway.AVM2.Runtime.asHasNext2; michael@0: var getDescendants = Shumway.AVM2.Runtime.getDescendants; michael@0: var checkFilter = Shumway.AVM2.Runtime.checkFilter; michael@0: var ActivationInfo = Shumway.AVM2.Runtime.ActivationInfo; michael@0: var ScopeStack = Shumway.AVM2.Runtime.ScopeStack; michael@0: var Scope = Shumway.AVM2.Runtime.Scope; michael@0: var bindFreeMethodScope = Shumway.AVM2.Runtime.bindFreeMethodScope; michael@0: var nameInTraits = Shumway.AVM2.Runtime.nameInTraits; michael@0: function resolveMultiname(object, mn, traitsOnly) { michael@0: return object.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: } michael@0: var sliceArguments = Shumway.AVM2.Runtime.sliceArguments; michael@0: var nonProxyingHasProperty = Shumway.AVM2.Runtime.nonProxyingHasProperty; michael@0: var forEachPublicProperty = Shumway.AVM2.Runtime.forEachPublicProperty; michael@0: var wrapJSObject = Shumway.AVM2.Runtime.wrapJSObject; michael@0: var asCreateActivation = Shumway.AVM2.Runtime.asCreateActivation; michael@0: var CatchScopeObject = Shumway.AVM2.Runtime.CatchScopeObject; michael@0: var Global = Shumway.AVM2.Runtime.Global; michael@0: var canCompile = Shumway.AVM2.Runtime.canCompile; michael@0: var shouldCompile = Shumway.AVM2.Runtime.shouldCompile; michael@0: var forceCompile = Shumway.AVM2.Runtime.forceCompile; michael@0: var createInterpretedFunction = Shumway.AVM2.Runtime.createInterpretedFunction; michael@0: var debugName = Shumway.AVM2.Runtime.debugName; michael@0: var createCompiledFunction = Shumway.AVM2.Runtime.createCompiledFunction; michael@0: var getMethodOverrideKey = Shumway.AVM2.Runtime.getMethodOverrideKey; michael@0: var checkMethodOverrides = Shumway.AVM2.Runtime.checkMethodOverrides; michael@0: var makeTrampoline = Shumway.AVM2.Runtime.makeTrampoline; michael@0: var makeMemoizer = Shumway.AVM2.Runtime.makeMemoizer; michael@0: var createFunction = Shumway.AVM2.Runtime.createFunction; michael@0: var ensureFunctionIsInitialized = Shumway.AVM2.Runtime.ensureFunctionIsInitialized; michael@0: var getTraitFunction = Shumway.AVM2.Runtime.getTraitFunction; michael@0: var createClass = Shumway.AVM2.Runtime.createClass; michael@0: var sealConstantTraits = Shumway.AVM2.Runtime.sealConstantTraits; michael@0: var applyType = Shumway.AVM2.Runtime.applyType; michael@0: var throwError = Shumway.AVM2.Runtime.throwError; michael@0: var throwErrorFromVM = Shumway.AVM2.Runtime.throwErrorFromVM; michael@0: var translateError = Shumway.AVM2.Runtime.translateError; michael@0: var asIsInstanceOf = Shumway.AVM2.Runtime.asIsInstanceOf; michael@0: var asIsType = Shumway.AVM2.Runtime.asIsType; michael@0: var asAsType = Shumway.AVM2.Runtime.asAsType; michael@0: var asCoerceByMultiname = Shumway.AVM2.Runtime.asCoerceByMultiname; michael@0: var asCoerce = Shumway.AVM2.Runtime.asCoerce; michael@0: var asCoerceString = Shumway.AVM2.Runtime.asCoerceString; michael@0: var asCoerceInt = Shumway.AVM2.Runtime.asCoerceInt; michael@0: var asCoerceUint = Shumway.AVM2.Runtime.asCoerceUint; michael@0: var asCoerceNumber = Shumway.AVM2.Runtime.asCoerceNumber; michael@0: var asCoerceBoolean = Shumway.AVM2.Runtime.asCoerceBoolean; michael@0: var asCoerceObject = Shumway.AVM2.Runtime.asCoerceObject; michael@0: var asDefaultCompareFunction = Shumway.AVM2.Runtime.asDefaultCompareFunction; michael@0: var asCompare = Shumway.AVM2.Runtime.asCompare; michael@0: var asAdd = Shumway.AVM2.Runtime.asAdd; michael@0: var GlobalMultinameResolver = Shumway.AVM2.Runtime.GlobalMultinameResolver; michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: (function (Runtime) { michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static mochi.as3.MochiServices::connect'] = function () { michael@0: return; michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static MochiBot::track'] = function () { michael@0: return; michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.midasplayer.debug.DebugLog::trace'] = function (msg) { michael@0: log(msg); michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.midasplayer.engine.comm.DebugGameComm::getGameData'] = function () { michael@0: return '\ntrue\ntrue\nfalse\n0\n0\n0\n0\n0\n0\n0\n0\n0\n0\nCandy crushed\nbest ever\nscored {0} in one game\nAll Clear Created\ncrushed {0} candy in one game\nScore\nPlease register to play the full game\nLongest chain\nGame ends in {0} seconds\nSuper Stripes Created\nNo more moves!\nMega-Candy Created\nGame starts in {0} seconds\nnow\nLevel reached\nGame Over\nMatch 3 Candy of the same colour to crush them. Matching 4 or 5 in different formations generates special sweets that are extra tasty.\nYou can also combine the special sweets for additional effects by switching them with each other. Try these combinations for a taste you will not forget: \nDouble Colour Bombs Created\nmade {0} combined candy in one game\nPlay like this:\n'; michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.antkarlov.Preloader::com.antkarlov:Preloader.isUrl'] = function () { michael@0: return true; michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static com.demonsters.debugger.MonsterDebugger::initialize'] = function () { michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.spilgames.api.core.tracking.TrackConfig::getTrackers'] = function () { michael@0: return []; michael@0: }; michael@0: Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.spilgames.api.components.TextFields.AutoFitTextFieldEx::com.spilgames.api.components.TextFields:AutoFitTextFieldEx.updateProperties'] = Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.spilgames.api.components.TextFields.AutoFitTextFieldEx::com.spilgames.api.components.TextFields:AutoFitTextFieldEx.updateTextSize'] = function () { michael@0: }; michael@0: }(AVM2.Runtime || (AVM2.Runtime = {}))); michael@0: var Runtime = AVM2.Runtime; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: var checkArguments = true; michael@0: function asCheckVectorSetNumericProperty(i, length, fixed) { michael@0: if (i < 0 || i > length || i === length && fixed || !isNumeric(i)) { michael@0: throwError('RangeError', Errors.OutOfRangeError, i, length); michael@0: } michael@0: } michael@0: function asCheckVectorGetNumericProperty(i, length) { michael@0: if (i < 0 || i >= length || !isNumeric(i)) { michael@0: throwError('RangeError', Errors.OutOfRangeError, i, length); michael@0: } michael@0: } michael@0: var TypedArrayVector = function () { michael@0: var EXTRA_CAPACITY = 4; michael@0: var INITIAL_CAPACITY = 10; michael@0: var DEFAULT_VALUE = 0; michael@0: function vector(length, fixed) { michael@0: length = length | 0; michael@0: this._fixed = !(!fixed); michael@0: this._buffer = new Int32Array(Math.max(INITIAL_CAPACITY, length + EXTRA_CAPACITY)); michael@0: this._offset = 0; michael@0: this._length = length; michael@0: } michael@0: vector.callable = function (object) { michael@0: if (object instanceof vector) { michael@0: return object; michael@0: } michael@0: var length = object.asGetProperty(undefined, 'length'); michael@0: if (length !== undefined) { michael@0: var v = new vector(length, false); michael@0: for (var i = 0; i < length; i++) { michael@0: v.asSetNumericProperty(i, object.asGetPublicProperty(i)); michael@0: } michael@0: return v; michael@0: } michael@0: unexpected(); michael@0: }; michael@0: vector.prototype.internalToString = function () { michael@0: var str = ''; michael@0: var start = this._offset; michael@0: var end = start + this._length; michael@0: for (var i = 0; i < this._buffer.length; i++) { michael@0: if (i === start) { michael@0: str += '['; michael@0: } michael@0: if (i === end) { michael@0: str += ']'; michael@0: } michael@0: str += this._buffer[i]; michael@0: if (i < this._buffer.length - 1) { michael@0: str += ','; michael@0: } michael@0: } michael@0: if (this._offset + this._length === this._buffer.length) { michael@0: str += ']'; michael@0: } michael@0: return str + ': offset: ' + this._offset + ', length: ' + this._length + ', capacity: ' + this._buffer.length; michael@0: }; michael@0: vector.prototype.toString = function () { michael@0: var str = ''; michael@0: for (var i = 0; i < this._length; i++) { michael@0: str += this._buffer[this._offset + i]; michael@0: if (i < this._length - 1) { michael@0: str += ','; michael@0: } michael@0: } michael@0: return str; michael@0: }; michael@0: vector.prototype._view = function () { michael@0: return this._buffer.subarray(this._offset, this._offset + this._length); michael@0: }; michael@0: vector.prototype._ensureCapacity = function (length) { michael@0: var minCapacity = this._offset + length; michael@0: if (minCapacity < this._buffer.length) { michael@0: return; michael@0: } michael@0: if (length <= this._buffer.length) { michael@0: var offset = this._buffer.length - length >> 2; michael@0: this._buffer.set(this._view(), offset); michael@0: this._offset = offset; michael@0: return; michael@0: } michael@0: var oldCapacity = this._buffer.length; michael@0: var newCapacity = oldCapacity * 3 >> 2; michael@0: if (newCapacity < minCapacity) { michael@0: newCapacity = minCapacity; michael@0: } michael@0: var buffer = new Int32Array(newCapacity); michael@0: buffer.set(this._buffer, 0); michael@0: this._buffer = buffer; michael@0: }; michael@0: vector.prototype.concat = function () { michael@0: notImplemented('TypedArrayVector.concat'); michael@0: }; michael@0: vector.prototype.every = function (callback, thisObject) { michael@0: for (var i = 0; i < this._length; i++) { michael@0: if (!callback.call(thisObject, this.asGetNumericProperty(i), i, this)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: }; michael@0: vector.prototype.filter = function (callback, thisObject) { michael@0: var v = new vector(); michael@0: for (var i = 0; i < this._length; i++) { michael@0: if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) { michael@0: v.push(this.asGetNumericProperty(i)); michael@0: } michael@0: } michael@0: return v; michael@0: }; michael@0: vector.prototype.some = function (callback, thisObject) { michael@0: if (arguments.length !== 2) { michael@0: throwError('ArgumentError', Errors.WrongArgumentCountError); michael@0: } else if (!isFunction(callback)) { michael@0: throwError('ArgumentError', Errors.CheckTypeFailedError); michael@0: } michael@0: for (var i = 0; i < this._length; i++) { michael@0: if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: }; michael@0: vector.prototype.forEach = function (callback, thisObject) { michael@0: for (var i = 0; i < this._length; i++) { michael@0: callback.call(thisObject, this.asGetNumericProperty(i), i, this); michael@0: } michael@0: }; michael@0: vector.prototype.join = function (sep) { michael@0: notImplemented('TypedArrayVector.join'); michael@0: }; michael@0: vector.prototype.indexOf = function (searchElement, fromIndex) { michael@0: notImplemented('TypedArrayVector.indexOf'); michael@0: }; michael@0: vector.prototype.lastIndexOf = function (searchElement, fromIndex) { michael@0: notImplemented('TypedArrayVector.lastIndexOf'); michael@0: }; michael@0: vector.prototype.map = function (callback, thisObject) { michael@0: if (!isFunction(callback)) { michael@0: throwError('ArgumentError', Errors.CheckTypeFailedError); michael@0: } michael@0: var v = new vector(); michael@0: for (var i = 0; i < this._length; i++) { michael@0: v.push(callback.call(thisObject, this.asGetNumericProperty(i), i, this)); michael@0: } michael@0: return v; michael@0: }; michael@0: vector.prototype.push = function () { michael@0: this._checkFixed(); michael@0: this._ensureCapacity(this._length + arguments.length); michael@0: for (var i = 0; i < arguments.length; i++) { michael@0: this._buffer[this._offset + this._length++] = arguments[i]; michael@0: } michael@0: }; michael@0: vector.prototype.pop = function () { michael@0: this._checkFixed(); michael@0: if (this._length === 0) { michael@0: return DEFAULT_VALUE; michael@0: } michael@0: this._length--; michael@0: return this._buffer[this._offset + this._length]; michael@0: }; michael@0: vector.prototype.reverse = function () { michael@0: var l = this._offset; michael@0: var r = this._offset + this._length - 1; michael@0: var b = this._buffer; michael@0: while (l < r) { michael@0: var t = b[l]; michael@0: b[l] = b[r]; michael@0: b[r] = t; michael@0: l++; michael@0: r--; michael@0: } michael@0: }; michael@0: vector.CASEINSENSITIVE = 1; michael@0: vector.DESCENDING = 2; michael@0: vector.UNIQUESORT = 4; michael@0: vector.RETURNINDEXEDARRAY = 8; michael@0: vector.NUMERIC = 16; michael@0: function defaultCompareFunction(a, b) { michael@0: return String(a).localeCompare(String(b)); michael@0: } michael@0: function compare(a, b, options, compareFunction) { michael@0: assertNotImplemented(!(options & vector.CASEINSENSITIVE), 'CASEINSENSITIVE'); michael@0: assertNotImplemented(!(options & vector.UNIQUESORT), 'UNIQUESORT'); michael@0: assertNotImplemented(!(options & vector.RETURNINDEXEDARRAY), 'RETURNINDEXEDARRAY'); michael@0: var result = 0; michael@0: if (!compareFunction) { michael@0: compareFunction = defaultCompareFunction; michael@0: } michael@0: if (options & vector.NUMERIC) { michael@0: a = toNumber(a); michael@0: b = toNumber(b); michael@0: result = a < b ? -1 : a > b ? 1 : 0; michael@0: } else { michael@0: result = compareFunction(a, b); michael@0: } michael@0: if (options & vector.DESCENDING) { michael@0: result *= -1; michael@0: } michael@0: return result; michael@0: } michael@0: function _sort(a) { michael@0: var stack = []; michael@0: var sp = -1; michael@0: var l = 0; michael@0: var r = a.length - 1; michael@0: var i, j, swap, temp; michael@0: while (true) { michael@0: if (r - l <= 100) { michael@0: for (j = l + 1; j <= r; j++) { michael@0: swap = a[j]; michael@0: i = j - 1; michael@0: while (i >= l && a[i] > swap) { michael@0: a[i + 1] = a[i--]; michael@0: } michael@0: a[i + 1] = swap; michael@0: } michael@0: if (sp == -1) { michael@0: break; michael@0: } michael@0: r = stack[sp--]; michael@0: l = stack[sp--]; michael@0: } else { michael@0: var median = l + r >> 1; michael@0: i = l + 1; michael@0: j = r; michael@0: swap = a[median]; michael@0: a[median] = a[i]; michael@0: a[i] = swap; michael@0: if (a[l] > a[r]) { michael@0: swap = a[l]; michael@0: a[l] = a[r]; michael@0: a[r] = swap; michael@0: } michael@0: if (a[i] > a[r]) { michael@0: swap = a[i]; michael@0: a[i] = a[r]; michael@0: a[r] = swap; michael@0: } michael@0: if (a[l] > a[i]) { michael@0: swap = a[l]; michael@0: a[l] = a[i]; michael@0: a[i] = swap; michael@0: } michael@0: temp = a[i]; michael@0: while (true) { michael@0: do { michael@0: i++; michael@0: } while (a[i] < temp); michael@0: do { michael@0: j--; michael@0: } while (a[j] > temp); michael@0: if (j < i) { michael@0: break; michael@0: } michael@0: swap = a[i]; michael@0: a[i] = a[j]; michael@0: a[j] = swap; michael@0: } michael@0: a[l + 1] = a[j]; michael@0: a[j] = temp; michael@0: if (r - i + 1 >= j - l) { michael@0: stack[++sp] = i; michael@0: stack[++sp] = r; michael@0: r = j - 1; michael@0: } else { michael@0: stack[++sp] = l; michael@0: stack[++sp] = j - 1; michael@0: l = i; michael@0: } michael@0: } michael@0: } michael@0: return a; michael@0: } michael@0: vector.prototype._sortNumeric = function (descending) { michael@0: _sort(this._view()); michael@0: if (descending) { michael@0: this.reverse(); michael@0: } michael@0: }; michael@0: vector.prototype.sort = function () { michael@0: if (arguments.length === 0) { michael@0: return Array.prototype.sort.call(this._view()); michael@0: } michael@0: var compareFunction, options = 0; michael@0: if (arguments[0] instanceof Function) { michael@0: compareFunction = arguments[0]; michael@0: } else if (isNumber(arguments[0])) { michael@0: options = arguments[0]; michael@0: } michael@0: if (isNumber(arguments[1])) { michael@0: options = arguments[1]; michael@0: } michael@0: if (options & TypedArrayVector.NUMERIC) { michael@0: return this._sortNumeric(options & vector.DESCENDING); michael@0: } michael@0: Array.prototype.sort.call(this._view(), function (a, b) { michael@0: return compare(a, b, options, compareFunction); michael@0: }); michael@0: }; michael@0: vector.prototype.asGetNumericProperty = function (i) { michael@0: checkArguments && asCheckVectorGetNumericProperty(i, this._length); michael@0: return this._buffer[this._offset + i]; michael@0: }; michael@0: vector.prototype.asSetNumericProperty = function (i, v) { michael@0: checkArguments && asCheckVectorSetNumericProperty(i, this._length, this._fixed); michael@0: if (i === this._length) { michael@0: this._ensureCapacity(this._length + 1); michael@0: this._length++; michael@0: } michael@0: this._buffer[this._offset + i] = v; michael@0: }; michael@0: vector.prototype.shift = function () { michael@0: this._checkFixed(); michael@0: if (this._length === 0) { michael@0: return 0; michael@0: } michael@0: this._length--; michael@0: return this._buffer[this._offset++]; michael@0: }; michael@0: vector.prototype._checkFixed = function () { michael@0: if (this._fixed) { michael@0: throwError('RangeError', Errors.VectorFixedError); michael@0: } michael@0: }; michael@0: vector.prototype._slide = function (distance) { michael@0: this._buffer.set(this._view(), this._offset + distance); michael@0: this._offset += distance; michael@0: }; michael@0: vector.prototype.unshift = function () { michael@0: this._checkFixed(); michael@0: if (!arguments.length) { michael@0: return; michael@0: } michael@0: this._ensureCapacity(this._length + arguments.length); michael@0: this._slide(arguments.length); michael@0: this._offset -= arguments.length; michael@0: this._length += arguments.length; michael@0: for (var i = 0; i < arguments.length; i++) { michael@0: this._buffer[this._offset + i] = arguments[i]; michael@0: } michael@0: }; michael@0: vector.prototype.asGetEnumerableKeys = function () { michael@0: if (vector.prototype === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var keys = []; michael@0: for (var i = 0; i < this._length; i++) { michael@0: keys.push(i); michael@0: } michael@0: return keys; michael@0: }; michael@0: vector.prototype.asHasProperty = function (namespaces, name, flags) { michael@0: if (vector.prototype === this || !isNumeric(name)) { michael@0: return Object.prototype.asHasProperty.call(this, namespaces, name, flags); michael@0: } michael@0: var index = toNumber(name); michael@0: return index >= 0 && index < this._length; michael@0: }; michael@0: Object.defineProperty(vector.prototype, 'length', { michael@0: get: function () { michael@0: return this._length; michael@0: }, michael@0: set: function (length) { michael@0: length = length >>> 0; michael@0: if (length > this._length) { michael@0: this._ensureCapacity(length); michael@0: for (var i = this._offset + this._length, j = this._offset + length; i < j; i++) { michael@0: this._buffer[i] = DEFAULT_VALUE; michael@0: } michael@0: } michael@0: this._length = length; michael@0: } michael@0: }); michael@0: vector.prototype._spliceHelper = function (index, insertCount, deleteCount, args, offset) { michael@0: insertCount = clamp(insertCount, 0, args.length - offset); michael@0: deleteCount = clamp(deleteCount, 0, this._length - index); michael@0: this._ensureCapacity(this._length - deleteCount + insertCount); michael@0: var right = this._offset + index + deleteCount; michael@0: var slice = this._buffer.subarray(right, right + this._length - index - deleteCount); michael@0: this._buffer.set(slice, this._offset + index + insertCount); michael@0: this._length += insertCount - deleteCount; michael@0: for (var i = 0; i < insertCount; i++) { michael@0: this._buffer[this._offset + index + i] = args.asGetNumericProperty(offset + i); michael@0: } michael@0: }; michael@0: vector.prototype.asGetEnumerableKeys = function () { michael@0: if (vector.prototype === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var keys = []; michael@0: for (var i = 0; i < this._length; i++) { michael@0: keys.push(i); michael@0: } michael@0: return keys; michael@0: }; michael@0: return vector; michael@0: }(); michael@0: var typedArrayVectorTemplate = 'var EXTRA_CAPACITY=4,INITIAL_CAPACITY=10,DEFAULT_VALUE=0;function vector(a,b){a|=0;this._fixed=!!b;this._buffer=new Int32Array(Math.max(INITIAL_CAPACITY,a+EXTRA_CAPACITY));this._offset=0;this._length=a}vector.callable=function(a){if(a instanceof vector)return a;var b=a.asGetProperty(void 0,"length");if(void 0!==b){for(var c=new vector(b,!1),d=0;d>2,this._buffer.set(this._view(),b),this._offset=b):(a=3*this._buffer.length>>2,ab?1:0):f=d(a,b);c&vector.DESCENDING&&(f*=-1);return f} function _sort(a){for(var b=[],c=-1,d=0,f=a.length-1,e,g,h,k;;)if(100>=f-d){for(g=d+1;g<=f;g++){h=a[g];for(e=g-1;e>=d&&a[e]>h;)a[e+1]=a[e--];a[e+1]=h}if(-1==c)break;f=b[c--];d=b[c--]}else{k=d+f>>1;e=d+1;g=f;h=a[k];a[k]=a[e];a[e]=h;a[d]>a[f]&&(h=a[d],a[d]=a[f],a[f]=h);a[e]>a[f]&&(h=a[e],a[e]=a[f],a[f]=h);a[d]>a[e]&&(h=a[d],a[d]=a[e],a[e]=h);for(k=a[e];;){do e++;while(a[e]k);if(g=g-d?(b[++c]=e,b[++c]=f,f=g-1):(b[++c]=d, b[++c]=g-1,d=e)}return a}vector.prototype._sortNumeric=function(a){_sort(this._view());a&&this.reverse()};vector.prototype.sort=function(){if(0===arguments.length)return Array.prototype.sort.call(this._view());var a,b=0;arguments[0]instanceof Function?a=arguments[0]:isNumber(arguments[0])&&(b=arguments[0]);isNumber(arguments[1])&&(b=arguments[1]);if(b&TypedArrayVector.NUMERIC)return this._sortNumeric(b&vector.DESCENDING);Array.prototype.sort.call(this._view(),function(c,d){return compare(c,d,b,a)})}; vector.prototype.asGetNumericProperty=function(a){checkArguments&&asCheckVectorGetNumericProperty(a,this._length);return this._buffer[this._offset+a]};vector.prototype.asSetNumericProperty=function(a,b){checkArguments&&asCheckVectorSetNumericProperty(a,this._length,this._fixed);a===this._length&&(this._ensureCapacity(this._length+1),this._length++);this._buffer[this._offset+a]=b};vector.prototype.shift=function(){this._checkFixed();if(0===this._length)return 0;this._length--;return this._buffer[this._offset++]}; vector.prototype._checkFixed=function(){this._fixed&&throwError("RangeError",Errors.VectorFixedError)};vector.prototype._slide=function(a){this._buffer.set(this._view(),this._offset+a);this._offset+=a};vector.prototype.unshift=function(){this._checkFixed();if(arguments.length){this._ensureCapacity(this._length+arguments.length);this._slide(arguments.length);this._offset-=arguments.length;this._length+=arguments.length;for(var a=0;a>>=0;if(a>this._length){this._ensureCapacity(a);for(var b=this._offset+this._length,c=this._offset+a;b b ? 1 : 0; michael@0: } else { michael@0: result = compareFunction(a, b); michael@0: } michael@0: if (options & DESCENDING) { michael@0: result *= -1; michael@0: } michael@0: return result; michael@0: } michael@0: vector.prototype.sort = function (comparator) { michael@0: return this._buffer.sort(comparator); michael@0: }; michael@0: vector.prototype.asGetNumericProperty = function (i) { michael@0: checkArguments && asCheckVectorGetNumericProperty(i, this._buffer.length); michael@0: return this._buffer[i]; michael@0: }; michael@0: vector.prototype._coerce = function (v) { michael@0: if (this._type) { michael@0: return this._type.coerce(v); michael@0: } else if (v === undefined) { michael@0: return null; michael@0: } michael@0: return v; michael@0: }; michael@0: vector.prototype.asSetNumericProperty = function (i, v) { michael@0: checkArguments && asCheckVectorSetNumericProperty(i, this._buffer.length, this._fixed); michael@0: this._buffer[i] = this._coerce(v); michael@0: }; michael@0: vector.prototype.shift = function () { michael@0: this._checkFixed(); michael@0: if (this._buffer.length === 0) { michael@0: return undefined; michael@0: } michael@0: return this._buffer.shift(); michael@0: }; michael@0: vector.prototype._checkFixed = function () { michael@0: if (this._fixed) { michael@0: throwError('RangeError', Errors.VectorFixedError); michael@0: } michael@0: }; michael@0: vector.prototype.unshift = function () { michael@0: if (!arguments.length) { michael@0: return; michael@0: } michael@0: this._checkFixed(); michael@0: var items = []; michael@0: for (var i = 0; i < arguments.length; i++) { michael@0: items.push(this._coerce(arguments[i])); michael@0: } michael@0: this._buffer.unshift.apply(this._buffer, items); michael@0: }; michael@0: Object.defineProperty(vector.prototype, 'length', { michael@0: get: function () { michael@0: return this._buffer.length; michael@0: }, michael@0: set: function (length) { michael@0: length = length >>> 0; michael@0: if (length > this._buffer.length) { michael@0: for (var i = this._buffer.length; i < length; i++) { michael@0: this._buffer[i] = this._defaultValue; michael@0: } michael@0: } else { michael@0: this._buffer.length = length; michael@0: } michael@0: true; michael@0: } michael@0: }); michael@0: vector.prototype._spliceHelper = function (index, insertCount, deleteCount, args, offset) { michael@0: insertCount = clamp(insertCount, 0, args.length - offset); michael@0: deleteCount = clamp(deleteCount, 0, this._buffer.length - index); michael@0: var items = []; michael@0: for (var i = 0; i < insertCount; i++) { michael@0: items.push(this._coerce(args.asGetNumericProperty(offset + i))); michael@0: } michael@0: this._buffer.splice.apply(this._buffer, [ michael@0: index, michael@0: deleteCount michael@0: ].concat(items)); michael@0: }; michael@0: vector.prototype.asGetEnumerableKeys = function () { michael@0: if (vector.prototype === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var keys = []; michael@0: for (var i = 0; i < this._buffer.length; i++) { michael@0: keys.push(i); michael@0: } michael@0: return keys; michael@0: }; michael@0: vector.prototype.asHasProperty = function (namespaces, name, flags) { michael@0: if (vector.prototype === this || !isNumeric(name)) { michael@0: return Object.prototype.asHasProperty.call(this, namespaces, name, flags); michael@0: } michael@0: var index = toNumber(name); michael@0: return index >= 0 && index < this._buffer.length; michael@0: }; michael@0: return vector; michael@0: }(); michael@0: GenericVector.prototype.asGetProperty = function (namespaces, name, flags) { michael@0: if (typeof name === 'number') { michael@0: return this.asGetNumericProperty(name); michael@0: } michael@0: return asGetProperty.call(this, namespaces, name, flags); michael@0: }; michael@0: GenericVector.prototype.asSetProperty = function (namespaces, name, flags, value) { michael@0: if (typeof name === 'number') { michael@0: this.asSetNumericProperty(name, value); michael@0: return; michael@0: } michael@0: return asSetProperty.call(this, namespaces, name, flags, value); michael@0: }; michael@0: function arraySort(o, args) { michael@0: if (args.length === 0) { michael@0: return o.sort(); michael@0: } michael@0: var compareFunction, options = 0; michael@0: if (args[0] instanceof Function) { michael@0: compareFunction = args[0]; michael@0: } else if (isNumber(args[0])) { michael@0: options = args[0]; michael@0: } michael@0: if (isNumber(args[1])) { michael@0: options = args[1]; michael@0: } michael@0: o.sort(function (a, b) { michael@0: return asCompare(a, b, options, compareFunction); michael@0: }); michael@0: return o; michael@0: } michael@0: function ArrayClass(domain, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Array', Array, ApplicationDomain.passthroughCallable(Array)); michael@0: c.extendBuiltin(baseClass); michael@0: var CACHE_NUMERIC_COMPARATORS = true; michael@0: var numericComparatorCache = createEmptyObject(); michael@0: c.native = { michael@0: static: { michael@0: _pop: function _pop(o) { michael@0: return o.pop(); michael@0: }, michael@0: _reverse: function _reverse(o) { michael@0: return o.reverse(); michael@0: }, michael@0: _concat: function _concat(o, args) { michael@0: return o.concat.apply(o, args); michael@0: }, michael@0: _shift: function _shift(o) { michael@0: return o.shift(); michael@0: }, michael@0: _slice: function _slice(o, A, B) { michael@0: return o.slice(A, B); michael@0: }, michael@0: _unshift: function _unshift(o, args) { michael@0: return o.unshift.apply(o, args); michael@0: }, michael@0: _splice: function _splice(o, args) { michael@0: return o.splice.apply(o, args); michael@0: }, michael@0: _sort: function _sort(o, args) { michael@0: if (args.length === 0) { michael@0: return o.sort(); michael@0: } michael@0: var compareFunction, options = 0; michael@0: if (args[0] instanceof Function) { michael@0: compareFunction = args[0]; michael@0: } else if (isNumber(args[0])) { michael@0: options = args[0]; michael@0: } michael@0: if (isNumber(args[1])) { michael@0: options = args[1]; michael@0: } michael@0: o.sort(function (a, b) { michael@0: return asCompare(a, b, options, compareFunction); michael@0: }); michael@0: return o; michael@0: }, michael@0: _sortOn: function _sortOn(o, names, options) { michael@0: if (isString(names)) { michael@0: names = [ michael@0: names michael@0: ]; michael@0: } michael@0: if (isNumber(options)) { michael@0: options = [ michael@0: options michael@0: ]; michael@0: } michael@0: for (var i = names.length - 1; i >= 0; i--) { michael@0: var key = Multiname.getPublicQualifiedName(names[i]); michael@0: if (CACHE_NUMERIC_COMPARATORS && options[i] & SORT_NUMERIC) { michael@0: var str = 'var x = toNumber(a.' + key + '), y = toNumber(b.' + key + ');'; michael@0: if (options[i] & SORT_DESCENDING) { michael@0: str += 'return x < y ? 1 : (x > y ? -1 : 0);'; michael@0: } else { michael@0: str += 'return x < y ? -1 : (x > y ? 1 : 0);'; michael@0: } michael@0: var numericComparator = numericComparatorCache[str]; michael@0: if (!numericComparator) { michael@0: numericComparator = numericComparatorCache[str] = new Function('a', 'b', str); michael@0: } michael@0: o.sort(numericComparator); michael@0: } else { michael@0: o.sort(function (a, b) { michael@0: return asCompare(a[key], b[key], options[i] | 0); michael@0: }); michael@0: } michael@0: } michael@0: return o; michael@0: }, michael@0: _indexOf: function _indexOf(o, searchElement, fromIndex) { michael@0: return o.indexOf(searchElement, fromIndex); michael@0: }, michael@0: _lastIndexOf: function _lastIndexOf(o, searchElement, fromIndex) { michael@0: return o.lastIndexOf(searchElement, fromIndex); michael@0: }, michael@0: _every: function _every(o, callback, thisObject) { michael@0: for (var i = 0; i < o.length; i++) { michael@0: if (callback.call(thisObject, o[i], i, o) !== true) { michael@0: return false; michael@0: } michael@0: } michael@0: return false; michael@0: }, michael@0: _filter: function _filter(o, callback, thisObject) { michael@0: var result = []; michael@0: for (var i = 0; i < o.length; i++) { michael@0: if (callback.call(thisObject, o[i], i, o) === true) { michael@0: result.push(o[i]); michael@0: } michael@0: } michael@0: return result; michael@0: }, michael@0: _forEach: function _forEach(o, callback, thisObject) { michael@0: return o.forEach(callback, thisObject); michael@0: }, michael@0: _map: function _map(o, callback, thisObject) { michael@0: return o.map(callback, thisObject); michael@0: }, michael@0: _some: function _some(o, callback, thisObject) { michael@0: return o.some(callback, thisObject); michael@0: } michael@0: }, michael@0: instance: { michael@0: pop: Array.prototype.pop, michael@0: push: Array.prototype.push, michael@0: unshift: Array.prototype.unshift, michael@0: length: { michael@0: get: function length() { michael@0: return this.length; michael@0: }, michael@0: set: function length(newLength) { michael@0: this.length = newLength; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: c.coerce = function (value) { michael@0: return value; michael@0: }; michael@0: c.isInstanceOf = function (value) { michael@0: return true; michael@0: }; michael@0: return c; michael@0: } michael@0: var XMLClass, XMLListClass, QNameClass, ASXML, XML, ASXMLList, XMLList; michael@0: var isXMLType, isXMLName, XMLParser; michael@0: (function () { michael@0: function XMLEncoder(ancestorNamespaces, indentLevel, prettyPrinting) { michael@0: function visit(node, encode) { michael@0: if (node.isXML) { michael@0: switch (node.kind) { michael@0: case 'element': michael@0: return encode.element(node); michael@0: case 'attribute': michael@0: return encode.attribute(node); michael@0: case 'text': michael@0: return encode.text(node); michael@0: case 'cdata': michael@0: return encode.cdata(node); michael@0: case 'comment': michael@0: return encode.comment(node); michael@0: case 'processing-instruction': michael@0: return encode.pi(node); michael@0: } michael@0: } else if (node.isXMLList) { michael@0: return encode.list(node); michael@0: } else { michael@0: throw 'Not implemented'; michael@0: } michael@0: } michael@0: function encode(node, encoder) { michael@0: return visit(node, { michael@0: element: function (n) { michael@0: var s, a; michael@0: var ns = n.name.mn.namespaces[0]; michael@0: var prefix = ns.prefix ? ns.prefix + ':' : ''; michael@0: s = '<' + prefix + n.name.localName; michael@0: var namespaceDeclarations = []; michael@0: if (ns.prefix || ns.uri) { michael@0: namespaceDeclarations.push(ns); michael@0: } michael@0: if (prefix) { michael@0: namespaceDeclarations[ns.prefix] = true; michael@0: } michael@0: var t = n; michael@0: while (t) { michael@0: for (var i = 0; i < t.inScopeNamespaces.length; i++) { michael@0: ns = t.inScopeNamespaces[i]; michael@0: if (!namespaceDeclarations[ns.prefix]) { michael@0: namespaceDeclarations.push(ns); michael@0: namespaceDeclarations[ns.prefix] = true; michael@0: } michael@0: } michael@0: t = t.parent; michael@0: } michael@0: for (var i = 0; i < namespaceDeclarations.length; i++) { michael@0: a = namespaceDeclarations[i]; michael@0: if (a.prefix) { michael@0: s += ' xmlns:' + a.prefix + '="' + a.uri + '"'; michael@0: } else { michael@0: s += ' xmlns="' + a.uri + '"'; michael@0: } michael@0: } michael@0: for (var i = 0; i < n.attributes.length; i++) { michael@0: a = n.attributes[i]; michael@0: var ns = n.name.uri; michael@0: var prefix = n.prefix ? ns.prefix + ':' : ''; michael@0: var name = prefix + a.name.localName; michael@0: s += ' ' + name + '="' + a.value + '"'; michael@0: } michael@0: if (n.children.length) { michael@0: s += '>'; michael@0: for (var i = 0; i < n.children.length; i++) { michael@0: s += visit(n.children[i], this); michael@0: } michael@0: s += ''; michael@0: } else { michael@0: s += '/>'; michael@0: } michael@0: return s; michael@0: }, michael@0: text: function (text) { michael@0: return escapeAttributeValue(text.value); michael@0: }, michael@0: attribute: function (n) { michael@0: return escapeAttributeValue(n.value); michael@0: }, michael@0: cdata: function (n) { michael@0: }, michael@0: comment: function (n) { michael@0: }, michael@0: pi: function (n) { michael@0: }, michael@0: doctype: function (n) { michael@0: }, michael@0: list: function (n) { michael@0: var s = ''; michael@0: for (var i = 0; i < n.children.length; i++) { michael@0: if (i > 0) { michael@0: s += '\n'; michael@0: } michael@0: s += toXMLString(n.children[i], []); michael@0: } michael@0: return s; michael@0: } michael@0: }); michael@0: } michael@0: this.encode = encode; michael@0: } michael@0: function escapeAttributeValue(v) { michael@0: return v.replace('&', '&').replace('<', '<').replace('>', '>'); michael@0: } michael@0: XMLParser = function XMLParser() { michael@0: function parseXml(s, sink) { michael@0: var i = 0, scopes = [ michael@0: { michael@0: space: 'default', michael@0: xmlns: '', michael@0: namespaces: { michael@0: 'xmlns': 'http://www.w3.org/2000/xmlns/', michael@0: 'xml': 'http://www.w3.org/XML/1998/namespace' michael@0: } michael@0: } michael@0: ]; michael@0: function trim(s) { michael@0: return s.replace(/^\s+/, '').replace(/\s+$/, ''); michael@0: } michael@0: function resolveEntities(s) { michael@0: return s.replace(/&([^;]+);/g, function (all, entity) { michael@0: if (entity.substring(0, 2) === '#x') { michael@0: return String.fromCharCode(parseInt(entity.substring(2), 16)); michael@0: } else if (entity.substring(0, 1) === '#') { michael@0: return String.fromCharCode(parseInt(entity.substring(1), 10)); michael@0: } michael@0: switch (entity) { michael@0: case 'lt': michael@0: return '<'; michael@0: case 'gt': michael@0: return '>'; michael@0: case 'amp': michael@0: return '&'; michael@0: } michael@0: throw 'Unknown entity: ' + entity; michael@0: }); michael@0: } michael@0: function isWhitespacePreserved() { michael@0: for (var j = scopes.length - 1; j >= 0; --j) { michael@0: if (scopes[j].space === 'preserve') { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: function lookupDefaultNs() { michael@0: for (var j = scopes.length - 1; j >= 0; --j) { michael@0: if (scopes[j].hasOwnProperty('xmlns')) { michael@0: return scopes[j].xmlns; michael@0: } michael@0: } michael@0: } michael@0: function lookupNs(prefix) { michael@0: for (var j = scopes.length - 1; j >= 0; --j) { michael@0: if (scopes[j].namespaces.hasOwnProperty(prefix)) { michael@0: return scopes[j].namespaces[prefix]; michael@0: } michael@0: } michael@0: throw 'Unknown namespace: ' + prefix; michael@0: } michael@0: function getName(name, resolveDefaultNs) { michael@0: var j = name.indexOf(':'); michael@0: if (j >= 0) { michael@0: var namespace = lookupNs(name.substring(0, j)); michael@0: var prefix = name.substring(0, j); michael@0: var localName = name.substring(j + 1); michael@0: return { michael@0: name: namespace + '::' + localName, michael@0: localName: localName, michael@0: prefix: prefix, michael@0: namespace: namespace michael@0: }; michael@0: } else if (resolveDefaultNs) { michael@0: return { michael@0: name: name, michael@0: localName: name, michael@0: prefix: '', michael@0: namespace: lookupDefaultNs() michael@0: }; michael@0: } else { michael@0: return { michael@0: name: name, michael@0: localName: name, michael@0: prefix: '', michael@0: namespace: '' michael@0: }; michael@0: } michael@0: } michael@0: var whitespaceMap = { michael@0: '10': true, michael@0: '13': true, michael@0: '9': true, michael@0: '32': true michael@0: }; michael@0: function isWhitespace(s, index) { michael@0: return s.charCodeAt(index) in whitespaceMap; michael@0: } michael@0: function parseContent(s, start) { michael@0: var pos = start, name, attributes = []; michael@0: function skipWs() { michael@0: while (pos < s.length && isWhitespace(s, pos)) { michael@0: ++pos; michael@0: } michael@0: } michael@0: while (pos < s.length && !isWhitespace(s, pos) && s.charAt(pos) !== '>' && s.charAt(pos) !== '/') { michael@0: ++pos; michael@0: } michael@0: name = s.substring(start, pos); michael@0: skipWs(); michael@0: while (pos < s.length && s.charAt(pos) !== '>' && s.charAt(pos) !== '/' && s.charAt(pos) !== '?') { michael@0: skipWs(); michael@0: var attrName = '', attrValue = ''; michael@0: while (pos < s.length && !isWhitespace(s, pos) && s.charAt(pos) !== '=') { michael@0: attrName += s.charAt(pos); michael@0: ++pos; michael@0: } michael@0: skipWs(); michael@0: if (s.charAt(pos) !== '=') michael@0: throw '\'=\' expected'; michael@0: ++pos; michael@0: skipWs(); michael@0: var attrEndChar = s.charAt(pos); michael@0: if (attrEndChar !== '"' && attrEndChar !== '\'') michael@0: throw 'Quote expected'; michael@0: var attrEndIndex = s.indexOf(attrEndChar, ++pos); michael@0: if (attrEndIndex < 0) michael@0: throw new 'Unexpected EOF[6]'(); michael@0: attrValue = s.substring(pos, attrEndIndex); michael@0: attributes.push({ michael@0: name: attrName, michael@0: value: resolveEntities(attrValue) michael@0: }); michael@0: pos = attrEndIndex + 1; michael@0: skipWs(); michael@0: } michael@0: return { michael@0: name: name, michael@0: attributes: attributes, michael@0: parsed: pos - start michael@0: }; michael@0: } michael@0: while (i < s.length) { michael@0: var ch = s.charAt(i); michael@0: var j = i; michael@0: if (ch === '<') { michael@0: ++j; michael@0: var ch2 = s.charAt(j), q, name; michael@0: switch (ch2) { michael@0: case '/': michael@0: ++j; michael@0: q = s.indexOf('>', j); michael@0: if (q < 0) { michael@0: throw 'Unexpected EOF[1]'; michael@0: } michael@0: name = getName(s.substring(j, q), true); michael@0: sink.endElement(name); michael@0: scopes.pop(); michael@0: j = q + 1; michael@0: break; michael@0: case '?': michael@0: ++j; michael@0: var content = parseContent(s, j); michael@0: if (s.substring(j + content.parsed, j + content.parsed + 2) != '?>') { michael@0: throw 'Unexpected EOF[2]'; michael@0: } michael@0: sink.pi(content.name, content.attributes); michael@0: j += content.parsed + 2; michael@0: break; michael@0: case '!': michael@0: if (s.substring(j + 1, j + 3) === '--') { michael@0: q = s.indexOf('-->', j + 3); michael@0: if (q < 0) { michael@0: throw 'Unexpected EOF[3]'; michael@0: } michael@0: sink.comment(s.substring(j + 3, q)); michael@0: j = q + 3; michael@0: } else if (s.substring(j + 1, j + 8) === '[CDATA[') { michael@0: q = s.indexOf(']]>', j + 8); michael@0: if (q < 0) { michael@0: throw 'Unexpected EOF[4]'; michael@0: } michael@0: sink.cdata(s.substring(j + 8, q)); michael@0: j = q + 3; michael@0: } else if (s.substring(j + 1, j + 8) === 'DOCTYPE') { michael@0: var q2 = s.indexOf('[', j + 8), complexDoctype = false; michael@0: q = s.indexOf('>', j + 8); michael@0: if (q < 0) { michael@0: throw 'Unexpected EOF[5]'; michael@0: } michael@0: if (q2 > 0 && q > q2) { michael@0: q = s.indexOf(']>', j + 8); michael@0: if (q < 0) { michael@0: throw 'Unexpected EOF[7]'; michael@0: } michael@0: complexDoctype = true; michael@0: } michael@0: var doctypeContent = s.substring(j + 8, q + (complexDoctype ? 1 : 0)); michael@0: sink.doctype(doctypeContent); michael@0: j = q + (complexDoctype ? 2 : 1); michael@0: } else { michael@0: throw 'Unknown !tag'; michael@0: } michael@0: break; michael@0: default: michael@0: var content = parseContent(s, j); michael@0: var isClosed = false; michael@0: if (s.substring(j + content.parsed, j + content.parsed + 2) === '/>') { michael@0: isClosed = true; michael@0: } else if (s.substring(j + content.parsed, j + content.parsed + 1) !== '>') { michael@0: throw 'Unexpected EOF[2]'; michael@0: } michael@0: var scope = { michael@0: namespaces: [] michael@0: }; michael@0: var contentAttributes = content.attributes; michael@0: for (q = 0; q < contentAttributes.length; ++q) { michael@0: var attribute = contentAttributes[q]; michael@0: var attributeName = attribute.name; michael@0: if (attributeName.substring(0, 6) === 'xmlns:') { michael@0: var prefix = attributeName.substring(6); michael@0: var uri = attribute.value; michael@0: scope.namespaces[prefix] = trim(uri); michael@0: scope.namespaces.push({ michael@0: uri: uri, michael@0: prefix: prefix michael@0: }); michael@0: delete contentAttributes[q]; michael@0: } else if (attributeName === 'xmlns') { michael@0: var uri = attribute.value; michael@0: scope.namespaces['xmlns'] = trim(uri); michael@0: scope.namespaces.push({ michael@0: uri: uri, michael@0: prefix: '' michael@0: }); michael@0: delete contentAttributes[q]; michael@0: } else if (attributeName.substring(0, 4) === 'xml:') { michael@0: scope[attributeName.substring(4)] = trim(attribute.value); michael@0: } else if (attributeName.substring(0, 3) === 'xml') { michael@0: throw 'Invalid xml attribute'; michael@0: } else { michael@0: } michael@0: } michael@0: scopes.push(scope); michael@0: var attributes = []; michael@0: for (q = 0; q < contentAttributes.length; ++q) { michael@0: attribute = contentAttributes[q]; michael@0: if (attribute) { michael@0: attributes.push({ michael@0: name: getName(attribute.name, false), michael@0: value: attribute.value michael@0: }); michael@0: } michael@0: } michael@0: sink.beginElement(getName(content.name, true), attributes, scope, isClosed); michael@0: j += content.parsed + (isClosed ? 2 : 1); michael@0: if (isClosed) michael@0: scopes.pop(); michael@0: break; michael@0: } michael@0: } else { michael@0: do { michael@0: if (++j >= s.length) michael@0: break; michael@0: } while (s.charAt(j) !== '<'); michael@0: var text = s.substring(i, j); michael@0: var isWs = text.replace(/^\s+/, '').length === 0; michael@0: if (!isWs || isWhitespacePreserved()) { michael@0: sink.text(resolveEntities(text), isWs); michael@0: } michael@0: } michael@0: i = j; michael@0: } michael@0: } michael@0: this.parseFromString = function (s, mimeType) { michael@0: var currentElement = new XML('element', '', '', ''); michael@0: var elementsStack = []; michael@0: parseXml(s, { michael@0: beginElement: function (name, attrs, scope, isEmpty) { michael@0: var parent = currentElement; michael@0: elementsStack.push(parent); michael@0: currentElement = createNode('element', name.namespace, name.localName, name.prefix); michael@0: for (var i = 0; i < attrs.length; ++i) { michael@0: var rawAttr = attrs[i]; michael@0: var attr = createNode('attribute', rawAttr.name.namespace, rawAttr.name.localName, rawAttr.name.prefix); michael@0: attr.value = rawAttr.value; michael@0: currentElement.attributes.push(attr); michael@0: } michael@0: var namespaces = scope.namespaces; michael@0: for (var i = 0; i < namespaces.length; ++i) { michael@0: var rawNs = namespaces[i]; michael@0: var ns = ASNamespace.createNamespace(rawNs.uri, rawNs.prefix); michael@0: currentElement.inScopeNamespaces.push(ns); michael@0: } michael@0: parent.insert(parent.length(), currentElement); michael@0: if (isEmpty) { michael@0: currentElement = elementsStack.pop(); michael@0: } michael@0: }, michael@0: endElement: function (name) { michael@0: currentElement = elementsStack.pop(); michael@0: }, michael@0: text: function (text, isWhitespace) { michael@0: var node = createNode('text', '', ''); michael@0: node.value = text; michael@0: currentElement.insert(currentElement.length(), node); michael@0: }, michael@0: cdata: function (text) { michael@0: var node = createNode('text', '', ''); michael@0: node.value = text; michael@0: currentElement.insert(currentElement.length(), node); michael@0: }, michael@0: comment: function (text) { michael@0: }, michael@0: pi: function (name, attrs) { michael@0: }, michael@0: doctype: function (text) { michael@0: } michael@0: }); michael@0: return currentElement; michael@0: }; michael@0: function createNode(kind, uri, name, prefix) { michael@0: return new XML(kind, uri, name, prefix); michael@0: } michael@0: }; michael@0: var xmlParser = new XMLParser(); michael@0: isXMLType = function isXMLType(val) { michael@0: return val.isXML || val.isXMLList; michael@0: }; michael@0: function toString(node) { michael@0: if (typeof node === 'object' && node !== null) { michael@0: switch (node.kind) { michael@0: case 'text': michael@0: case 'attribute': michael@0: return node.value; michael@0: default: michael@0: if (node.hasSimpleContent()) { michael@0: var str = ''; michael@0: node.children.forEach(function (v, i) { michael@0: str += toString(v); michael@0: }); michael@0: return str; michael@0: } michael@0: return toXMLString(node); michael@0: } michael@0: } else { michael@0: return String(node); michael@0: } michael@0: } michael@0: function toXMLString(node, ancestorNamespaces, indentLevel) { michael@0: return new XMLEncoder(ancestorNamespaces, indentLevel, true).encode(node); michael@0: } michael@0: function toXML(v) { michael@0: if (v === null) { michael@0: throw new TypeError(formatErrorMessage(Errors.ConvertNullToObjectError)); michael@0: } else if (v === undefined) { michael@0: throw new TypeError(formatErrorMessage(Errors.ConvertUndefinedToObjectError)); michael@0: } else if (v.isXML) { michael@0: return v; michael@0: } else if (v.isXMLList) { michael@0: if (v.length() === 1) { michael@0: return v.children[0]; michael@0: } michael@0: throw new TypeError(formatErrorMessage(Errors.XMLMarkupMustBeWellFormed)); michael@0: } else { michael@0: var x = xmlParser.parseFromString(String(v)); michael@0: if (x.length() === 0) { michael@0: var x = new XML('text'); michael@0: return x; michael@0: } else if (x.length() === 1) { michael@0: x.children[0].parent = null; michael@0: return x.children[0]; michael@0: } michael@0: throw 'SyntaxError in ToXML'; michael@0: } michael@0: } michael@0: var defaultNamespace = ''; michael@0: function toXMLList(value) { michael@0: if (value === null) { michael@0: throw new TypeError(formatErrorMessage(Errors.ConvertNullToObjectError)); michael@0: } else if (value === undefined) { michael@0: throw new TypeError(formatErrorMessage(Errors.ConvertUndefinedToObjectError)); michael@0: } else if (value instanceof XML) { michael@0: var xl = new XMLList(value.parent, value.name); michael@0: xl.append(value); michael@0: return xl; michael@0: } else if (value instanceof XMLList) { michael@0: return value; michael@0: } else { michael@0: var s = '' + String(value) + ''; michael@0: var x = new ASXML(s); michael@0: var xl = new XMLList(); michael@0: for (var i = 0; i < x.length(); i++) { michael@0: var v = x.children[i]; michael@0: v.parent = null; michael@0: xl.append(v); michael@0: } michael@0: return xl; michael@0: } michael@0: } michael@0: function toAttributeName(v) { michael@0: if (v === undefined || v === null || typeof v === 'boolean' || typeof v === 'number') { michael@0: throw 'TypeError: invalid operand to ToAttributeName()'; michael@0: } else if (isXMLType(v)) { michael@0: v = toString(v); michael@0: } else if (v instanceof Object && v !== null) { michael@0: if (v instanceof QName) { michael@0: return new QName(v.uri, v.localName, true); michael@0: } michael@0: v = toString(v); michael@0: } michael@0: if (typeof v === 'string') { michael@0: var ns = new ASNamespace(); michael@0: var qn = new QName(ns, v, true); michael@0: } else { michael@0: } michael@0: return qn; michael@0: } michael@0: function toXMLName(mn) { michael@0: return new QName(mn); michael@0: } michael@0: function getDefaultNamespace(scope) { michael@0: while (scope) { michael@0: var obj = scope.object; michael@0: if (obj.defaultNamepsace !== undefined) { michael@0: return obj.defaultNamespace; michael@0: } michael@0: scope = scope.parent; michael@0: } michael@0: var ns = ASNamespace.createNamespace('', ''); michael@0: return ns; michael@0: } michael@0: isXMLName = function isXMLName(v) { michael@0: try { michael@0: var qn = new QName(v); michael@0: } catch (e) { michael@0: return false; michael@0: } michael@0: return true; michael@0: }; michael@0: function asGetProperty(namespaces, name, flags, isMethod) { michael@0: var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [ michael@0: ASNamespace.PUBLIC michael@0: ], name, flags); michael@0: return this.getProperty(mn, isMethod); michael@0: } michael@0: function asSetProperty(namespaces, name, flags, value) { michael@0: var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [ michael@0: ASNamespace.PUBLIC michael@0: ], name, flags); michael@0: this.setProperty(mn, value); michael@0: } michael@0: function asHasProperty(namespaces, name, flags) { michael@0: var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [ michael@0: ASNamespace.PUBLIC michael@0: ], name, flags); michael@0: return this.hasProperty(mn); michael@0: } michael@0: function asCallProperty(namespaces, name, flags, isLex, args) { michael@0: var receiver = isLex ? null : this; michael@0: var property = this.asGetProperty(namespaces, name, flags, true); michael@0: if (!property) { michael@0: return this.toString().asCallProperty(namespaces ? namespaces : [ michael@0: ASNamespace.PUBLIC michael@0: ], name, flags, isLex, args); michael@0: } michael@0: return property.apply(receiver, args); michael@0: } michael@0: var ATTR_NAME = 1; michael@0: var ELEM_NAME = 2; michael@0: var ANY_NAME = 4; michael@0: var ANY_NAMESPACE = 8; michael@0: function nameKind(mn) { michael@0: var flags = 0; michael@0: if (mn.isAttribute()) { michael@0: flags |= ATTR_NAME; michael@0: } else { michael@0: flags |= ELEM_NAME; michael@0: } michael@0: if (mn.isAnyName()) { michael@0: flags |= ANY_NAME; michael@0: } michael@0: if (mn.isAnyNamespace()) { michael@0: flags |= ANY_NAMESPACE; michael@0: } michael@0: return flags; michael@0: } michael@0: XMLClass = function XMLClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var FLAG_IGNORE_COMMENTS = 1; michael@0: var FLAG_IGNORE_PROCESSING_INSTRUCTIONS = 2; michael@0: var FLAG_IGNORE_WHITESPACE = 4; michael@0: var FLAG_PRETTY_PRINTING = 8; michael@0: ASXML = function (value) { michael@0: if (!(this instanceof ASXML)) { michael@0: if (value instanceof ASXML) { michael@0: return value; michael@0: } michael@0: return new ASXML(value); michael@0: } michael@0: if (value === null || value === undefined) { michael@0: value = ''; michael@0: } michael@0: var x = toXML(value); michael@0: if (isXMLType(value)) { michael@0: x = x.deepCopy(); michael@0: } michael@0: return x; michael@0: }; michael@0: XML = function (kind, uri, name, prefix) { michael@0: if (kind === undefined) { michael@0: kind = 'text'; michael@0: } michael@0: if (uri === undefined) { michael@0: uri = ''; michael@0: } michael@0: if (name === undefined) { michael@0: name = ''; michael@0: } michael@0: this.init(kind, uri, name, prefix); michael@0: }; michael@0: var c = new Class('XML', ASXML, ApplicationDomain.passthroughCallable(ASXML)); michael@0: c.flags = FLAG_IGNORE_COMMENTS | FLAG_IGNORE_PROCESSING_INSTRUCTIONS | FLAG_IGNORE_WHITESPACE | FLAG_PRETTY_PRINTING; michael@0: c.prettyIndent = 2; michael@0: c.extend(baseClass); michael@0: var Xp = XML.prototype = ASXML.prototype; michael@0: Xp.init = function init(kind, uri, name, prefix) { michael@0: this.name = new QName(new Multiname([ michael@0: new ASNamespace(prefix, uri) michael@0: ], name)); michael@0: this.kind = kind; michael@0: this.parent = null; michael@0: this.inScopeNamespaces = []; michael@0: switch (kind) { michael@0: case 'element': michael@0: this.attributes = []; michael@0: this.children = []; michael@0: break; michael@0: case 'attribute': michael@0: case 'text': michael@0: this.value = ''; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: return this; michael@0: }; michael@0: Xp.length = function () { michael@0: if (!this.children) { michael@0: return 0; michael@0: } michael@0: return this.children.length; michael@0: }; michael@0: Xp.canHandleProperties = true; michael@0: Xp.deepCopy = function () { michael@0: return new ASXML(toXMLString(this)); michael@0: }; michael@0: Xp.resolveValue = function resolveValue() { michael@0: return this; michael@0: }; michael@0: Xp.hasSimpleContent = function hasSimpleContent() { michael@0: if (this.kind === 'comment' || this.kind === 'processing-instruction') { michael@0: return false; michael@0: } michael@0: var result = true; michael@0: if (this.children) { michael@0: this.children.forEach(function (v) { michael@0: if (v.kind === 'element') { michael@0: result = false; michael@0: } michael@0: }); michael@0: } michael@0: return result; michael@0: }; michael@0: Xp.asGetEnumerableKeys = function asGetEnumerableKeys() { michael@0: if (Xp === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var keys = []; michael@0: this.children.forEach(function (v, i) { michael@0: keys.push(v.name); michael@0: }); michael@0: return keys; michael@0: }; michael@0: function setAttribute(node, name, value) { michael@0: if (node.nodeType === Node.DOCUMENT_NODE) { michael@0: node.childNodes[0].setAttribute(name, value); michael@0: } else if (node.nodeType === Node.ELEMENT_NODE) { michael@0: node.setAttribute(name, value); michael@0: } else { michael@0: throw 'error or unhandled case in setAttribute'; michael@0: } michael@0: } michael@0: Xp.setProperty = function (p, v) { michael@0: var x, i, c, n; michael@0: x = this; michael@0: if (p === p >>> 0) { michael@0: throw 'TypeError in XML.prototype.setProperty(): invalid property name ' + p; michael@0: } michael@0: if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') { michael@0: return; michael@0: } michael@0: if (!v || !v.isXML && !v.isXMLList || v.kind === 'text' || v.kind === 'attribute') { michael@0: c = toString(v); michael@0: } else { michael@0: c = v.deepCopy(); michael@0: } michael@0: n = toXMLName(p); michael@0: if (n.isAttr) { michael@0: if (!this.attributes) { michael@0: return; michael@0: } michael@0: this.attributes.forEach(function (v, i, o) { michael@0: if (v.name === n.localName) { michael@0: delete o[i]; michael@0: } michael@0: }); michael@0: var a = new XML('attribute', n.uri, n.localName); michael@0: a.value = v; michael@0: a.parent = this; michael@0: this.attributes.push(a); michael@0: return; michael@0: } michael@0: var isValidName = isXMLName(n); michael@0: if (!isValidName && n.localName !== '*') { michael@0: return; michael@0: } michael@0: var i = undefined; michael@0: var primitiveAssign = !isXMLType(c) && n.localName !== '*'; michael@0: for (var k = x.length() - 1; k >= 0; k--) { michael@0: if ((n.isAny || x.children[k].kind === 'element' && x.children[k].name.localName === n.localName) && (n.uri === null || x.children[k].kind === 'element' && x.children[k].name.uri === n.uri)) { michael@0: if (i !== undefined) { michael@0: x.deleteByIndex(String(i)); michael@0: } michael@0: i = k; michael@0: } michael@0: } michael@0: if (i === undefined) { michael@0: i = x.length(); michael@0: if (primitiveAssign) { michael@0: if (n.uri === null) { michael@0: var name = new QName(getDefaultNamespace(scope), n); michael@0: } else { michael@0: var name = new QName(n); michael@0: } michael@0: var y = new XML('element', name.uri, name.localName, name.prefix); michael@0: y.parent = x; michael@0: var ns = name.getNamespace(); michael@0: x.replace(String(i), y); michael@0: y.addInScopeNamespace(ns); michael@0: } michael@0: } michael@0: if (primitiveAssign) { michael@0: x.children[i].children = []; michael@0: var s = toString(c); michael@0: if (s !== '') { michael@0: x.children[i].replace('0', s); michael@0: } michael@0: } else { michael@0: x.replace(String(i), c); michael@0: } michael@0: return; michael@0: }; michael@0: Xp.asGetProperty = asGetProperty; michael@0: Xp.asGetResolvedStringProperty = asGetResolvedStringPropertyFallback; michael@0: Xp.asSetProperty = asSetProperty; michael@0: Xp.asHasProperty = asHasProperty; michael@0: Xp.asCallProperty = asCallProperty; michael@0: Xp.getProperty = function (mn, isMethod) { michael@0: if (isMethod) { michael@0: var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: return this[Multiname.getQualifiedName(resolved)]; michael@0: } michael@0: if (!Multiname.isQName(mn) && isNumeric(mn)) { michael@0: if (Number(0) === 0) { michael@0: return this; michael@0: } michael@0: return null; michael@0: } michael@0: var x = this; michael@0: var name = toXMLName(mn); michael@0: var xl = new XMLList(x, name); michael@0: var flags = nameKind(name.mn); michael@0: var anyName = flags & ANY_NAME; michael@0: var anyNamespace = flags & ANY_NAMESPACE; michael@0: if (flags & ATTR_NAME) { michael@0: if (x.attributes) { michael@0: x.attributes.forEach(function (v, i) { michael@0: if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: } michael@0: } else { michael@0: x.children.forEach(function (v, i) { michael@0: if ((anyName || v.kind === 'element' && v.name.localName === name.localName) && (anyNamespace || v.kind === 'element' && v.name.uri === name.uri)) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: } michael@0: return xl; michael@0: }; michael@0: Xp.hasProperty = function (mn, isMethod) { michael@0: if (isMethod) { michael@0: var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: return !(!this[Multiname.getQualifiedName(resolved)]); michael@0: } michael@0: if (!Multiname.isQName(mn) && isNumeric(mn)) { michael@0: if (Number(0) === 0) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: var name = toXMLName(mn); michael@0: var flags = nameKind(name.mn); michael@0: var anyName = flags & ANY_NAME; michael@0: var anyNamespace = flags & ANY_NAMESPACE; michael@0: if (flags & ATTR_NAME) { michael@0: return this.attributes.some(function (v, i) { michael@0: if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) { michael@0: return true; michael@0: } michael@0: }); michael@0: if (x.attributes) { michael@0: x.attributes.forEach(function (v, i) { michael@0: if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: } michael@0: } else { michael@0: if (this.children.some(function (v, i) { michael@0: if ((anyName || v.kind === 'element' && v.name.localName === name.localName) && (anyNamespace || v.kind === 'element' && v.name.uri === name.uri)) { michael@0: return true; michael@0: } michael@0: })) { michael@0: return true; michael@0: } michael@0: var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: return !(!this[Multiname.getQualifiedName(resolved)]); michael@0: } michael@0: }; michael@0: Xp.delete = function (key, isMethod) { michael@0: notImplemented('XML.[[Delete]]'); michael@0: }; michael@0: Xp.deleteByIndex = function (p) { michael@0: var x = this; michael@0: var i = p >>> 0; michael@0: if (String(i) !== String(p)) { michael@0: throw 'TypeError in XML.prototype.deleteByIndex(): invalid index ' + p; michael@0: } michael@0: if (p < x.length()) { michael@0: if (x.children[p]) { michael@0: x.children[p].parent = null; michael@0: delete x.children[p]; michael@0: for (q = i + 1; q < x.length(); q++) { michael@0: x.children[q - 1] = x.children[q]; michael@0: } michael@0: x.children.length = x.children.length - 1; michael@0: } michael@0: } michael@0: }; michael@0: Xp.isXML = true; michael@0: Xp.insert = function insert(p, v) { michael@0: var x, s, i, n; michael@0: x = this; michael@0: if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') { michael@0: return; michael@0: } michael@0: i = p >>> 0; michael@0: if (String(p) !== String(i)) { michael@0: throw 'TypeError in XML.prototype.insert(): invalid property name ' + p; michael@0: } michael@0: if (x.kind === 'element') { michael@0: var a = x; michael@0: while (a) { michael@0: if (a === v) { michael@0: throw 'Error in XML.prototype.insert()'; michael@0: } michael@0: a = a.parent; michael@0: } michael@0: } michael@0: if (x.isXMLList) { michael@0: n = x.length(); michael@0: if (n === 0) { michael@0: return; michael@0: } michael@0: } else { michael@0: n = 1; michael@0: } michael@0: for (var j = x.length() - 1; j >= i; j--) { michael@0: x[j + n] = x[j]; michael@0: } michael@0: if (x.isXMLList) { michael@0: n = v.length(); michael@0: for (var j = 0; j < n; j++) { michael@0: v.children[j].parent = x; michael@0: x[i + j] = v[j]; michael@0: } michael@0: } else { michael@0: v.parent = x; michael@0: x.children[i] = v; michael@0: } michael@0: }; michael@0: Xp.replace = function (p, v) { michael@0: var x, s; michael@0: x = this; michael@0: if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') { michael@0: return; michael@0: } michael@0: var i = p >>> 0; michael@0: if (String(p) !== String(i)) { michael@0: throw 'TypeError in XML.prototype.replace(): invalid name ' + p; michael@0: } michael@0: if (i >= x.length()) { michael@0: p = String(x.length()); michael@0: } michael@0: if (v.kind === 'element') { michael@0: var a = x; michael@0: while (a) { michael@0: if (a === v) { michael@0: throw 'Error in XML.prototype.replace()'; michael@0: } michael@0: a = a.parent; michael@0: } michael@0: } michael@0: if (v.kind === 'element' || v.kind === 'text' || v.kind === 'comment' || v.kind === 'processing-instruction') { michael@0: v.parent = x; michael@0: if (x[p]) { michael@0: x.children[p].parent = null; michael@0: } michael@0: x.children[p] = v; michael@0: } else if (x.isXMLList) { michael@0: x.deleteByIndex(p); michael@0: x.insert(p, v); michael@0: } else { michael@0: s = toString(v); michael@0: t = new XML(); michael@0: t.parent = x; michael@0: t.value = s; michael@0: if (x[p]) { michael@0: x.children[p].parent = null; michael@0: } michael@0: x.children[p] = t; michael@0: } michael@0: }; michael@0: Xp.addInScopeNamespace = function (ns) { michael@0: var x, s; michael@0: x = this; michael@0: if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') { michael@0: return; michael@0: } michael@0: if (ns.prefix !== undefined) { michael@0: if (ns.prefix === '' && x.name.uri === '') { michael@0: return; michael@0: } michael@0: var match = null; michael@0: x.inScopeNamespaces.forEach(function (v, i) { michael@0: if (v.prefix === ns.prefix) { michael@0: match = v; michael@0: } michael@0: }); michael@0: if (match !== null && match.uri !== ns.uri) { michael@0: x.inScopeNamespaces.forEach(function (v, i) { michael@0: if (v.prefix === match.prefix) { michael@0: x.inScopeNamespaces[i] = ns; michael@0: } michael@0: }); michael@0: } michael@0: if (x.name.prefix === ns.prefix) { michael@0: x.name.prefix = undefined; michael@0: } michael@0: x.attributes.forEach(function (v, i) { michael@0: if (v.name.prefix === ns.name.prefix) { michael@0: v.name.prefix = undefined; michael@0: } michael@0: }); michael@0: } michael@0: }; michael@0: Xp.descendants = function (name) { michael@0: name = toXMLName(name); michael@0: var x = this; michael@0: var xl = new XMLList(); michael@0: if (x.kind !== 'element') { michael@0: return xl; michael@0: } michael@0: if (name.isAttr) { michael@0: this.attributes.forEach(function (v, i) { michael@0: if (name.isAny || name.localName === v.name.localName) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: } else { michael@0: this.children.forEach(function (v, i) { michael@0: if (name.isAny || name.localName === v.name.localName) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: } michael@0: this.children.forEach(function (v, i) { michael@0: xl.append(v.descendants(name)); michael@0: }); michael@0: return xl; michael@0: }; michael@0: Xp.comments = function () { michael@0: var x = this; michael@0: var xl = new XMLList(x, null); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'comment') { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: return xl; michael@0: }; michael@0: Xp.text = function () { michael@0: var x = this; michael@0: var xl = new XMLList(x, null); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'text') { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: return xl; michael@0: }; michael@0: c.native = { michael@0: static: { michael@0: ignoreComments: { michael@0: get: function ignoreComments() { michael@0: return getBitFlags(c.flags, FLAG_IGNORE_COMMENTS); michael@0: }, michael@0: set: function ignoreComments(newIgnore) { michael@0: c.flags = setBitFlags(c.flags, FLAG_IGNORE_COMMENTS, newIgnore); michael@0: } michael@0: }, michael@0: ignoreProcessingInstructions: { michael@0: get: function ignoreProcessingInstructions() { michael@0: return getBitFlags(c.flags, FLAG_IGNORE_PROCESSING_INSTRUCTIONS); michael@0: }, michael@0: set: function ignoreProcessingInstructions(newIgnore) { michael@0: c.flags = setBitFlags(c.flags, FLAG_IGNORE_PROCESSING_INSTRUCTIONS, newIgnore); michael@0: } michael@0: }, michael@0: ignoreWhitespace: { michael@0: get: function ignoreWhitespace() { michael@0: return getBitFlags(c.flags, FLAG_IGNORE_WHITESPACE); michael@0: }, michael@0: set: function ignoreWhitespace(newIgnore) { michael@0: c.flags = setBitFlags(c.flags, FLAG_IGNORE_WHITESPACE, newIgnore); michael@0: } michael@0: }, michael@0: prettyPrinting: { michael@0: get: function prettyPrinting() { michael@0: return getBitFlags(c.flags, FLAG_PRETTY_PRINTING); michael@0: }, michael@0: set: function prettyPrinting(newPretty) { michael@0: c.flags = setBitFlags(c.flags, FLAG_PRETTY_PRINTING, newPretty); michael@0: } michael@0: }, michael@0: prettyIndent: { michael@0: get: function prettyIndent() { michael@0: return c.prettyIndent; michael@0: }, michael@0: set: function prettyIndent(newIndent) { michael@0: c.prettyIndent = newIndent; michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: toString: function () { michael@0: return toString(this); michael@0: }, michael@0: hasOwnProperty: function hasOwnProperty(P) { michael@0: somewhatImplemented('XML.hasOwnProperty'); michael@0: return this.hasProperty(P); michael@0: }, michael@0: propertyIsEnumerable: function propertyIsEnumerable(P) { michael@0: notImplemented('XML.propertyIsEnumerable'); michael@0: }, michael@0: addNamespace: function addNamespace(ns) { michael@0: notImplemented('XML.addNamespace'); michael@0: }, michael@0: appendChild: function appendChild(child) { michael@0: var children = this.getProperty('*'); michael@0: children.setProperty(children.length(), child); michael@0: return this; michael@0: }, michael@0: attribute: function attribute(name) { michael@0: return this.getProperty(toAttributeName(name)); michael@0: }, michael@0: attributes: function attributes() { michael@0: return this.getProperty(toAttributeName('*')); michael@0: }, michael@0: child: function child(name) { michael@0: return this.getProperty(name); michael@0: }, michael@0: childIndex: function childIndex() { michael@0: notImplemented('XML.childIndex'); michael@0: }, michael@0: children: function children() { michael@0: var list = new XMLList(); michael@0: Array.prototype.push.apply(list.children, this.children); michael@0: return list; michael@0: }, michael@0: comments: function comments() { michael@0: return this.comments(); michael@0: }, michael@0: contains: function contains(value) { michael@0: notImplemented('XML.contains'); michael@0: }, michael@0: copy: function copy() { michael@0: return this.deepCopy(); michael@0: }, michael@0: descendants: function descendants(name) { michael@0: if (name === undefined) { michael@0: name = '*'; michael@0: } michael@0: return this.descendants(name); michael@0: }, michael@0: elements: function elements(name) { michael@0: var x = this; michael@0: var any = false; michael@0: if (name === undefined) { michael@0: name = '*'; michael@0: any = true; michael@0: } michael@0: var name = toXMLName(name); michael@0: var xl = new XMLList(this.parent, name); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'element' && (any || v.name.localName === name.localName) && (name.uri === null || v.kind === 'element' && v.name.uri === name.uri)) { michael@0: xl.append(v); michael@0: } michael@0: }); michael@0: return xl; michael@0: }, michael@0: hasComplexContent: function hasComplexContent() { michael@0: notImplemented('XML.hasComplexContent'); michael@0: }, michael@0: hasSimpleContent: function hasSimpleContent() { michael@0: return this.hasSimpleContent(); michael@0: }, michael@0: inScopeNamespaces: function inScopeNamespaces() { michael@0: notImplemented('XML.inScopeNamespaces'); michael@0: }, michael@0: insertChildAfter: function insertChildAfter(child1, child2) { michael@0: notImplemented('XML.insertChildAfter'); michael@0: }, michael@0: insertChildBefore: function insertChildBefore(child1, child2) { michael@0: notImplemented('XML.insertChildBefore'); michael@0: }, michael@0: localName: function localName() { michael@0: return this.name.localName; michael@0: }, michael@0: name: function name() { michael@0: return this.name; michael@0: }, michael@0: _namespace: function _namespace(prefix, argc) { michael@0: somewhatImplemented('XML._namespace()'); michael@0: return this.name.uri; michael@0: }, michael@0: namespaceDeclarations: function namespaceDeclarations() { michael@0: return new XMLList(); michael@0: }, michael@0: nodeKind: function nodeKind() { michael@0: return this.kind; michael@0: }, michael@0: normalize: function normalize() { michael@0: notImplemented('XML.normalize'); michael@0: }, michael@0: parent: function parent() { michael@0: notImplemented('XML.parent'); michael@0: }, michael@0: processingInstructions: function processingInstructions(name) { michael@0: notImplemented('XML.processingInstructions'); michael@0: }, michael@0: prependChild: function prependChild(value) { michael@0: notImplemented('XML.prependChild'); michael@0: }, michael@0: removeNamespace: function removeNamespace(ns) { michael@0: notImplemented('XML.removeNamespace'); michael@0: }, michael@0: replace: function replace(propertyName, value) { michael@0: var c, x, s, i; michael@0: x = this; michael@0: if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') { michael@0: return x; michael@0: } michael@0: if (!isXMLType(value)) { michael@0: c = value.toString(); michael@0: } else { michael@0: c = value.deepCopy(); michael@0: } michael@0: var i = propertyName >>> 0; michael@0: if (String(propertyName) === String(i)) { michael@0: x.replace(propertyName, c); michael@0: return x; michael@0: } michael@0: n = new QName(propertyName); michael@0: i = undefined; michael@0: for (k = x.length() - 1; k >= 0; k--) { michael@0: var v = x.children[k]; michael@0: if (n.isAny || v.kind === 'element' && v.name.localName === n.localName && (n.uri === null || v.kind === 'element' && v.name.uri === n.uri)) { michael@0: if (i !== undefined) { michael@0: x.deleteByIndex(String(i)); michael@0: } michael@0: i = k; michael@0: } michael@0: } michael@0: if (i !== undefined) { michael@0: x.replace(i.toString(), c); michael@0: } michael@0: return x; michael@0: }, michael@0: setChildren: function setChildren(value) { michael@0: notImplemented('XML.setChildren'); michael@0: }, michael@0: setLocalName: function setLocalName(name) { michael@0: notImplemented('XML.setLocalName'); michael@0: }, michael@0: setName: function setName(name) { michael@0: notImplemented('XML.setName'); michael@0: }, michael@0: setNamespace: function setNamespace(ns) { michael@0: notImplemented('XML.setNamespace'); michael@0: }, michael@0: text: function text() { michael@0: return this.text(); michael@0: }, michael@0: toXMLString: function () { michael@0: return toXMLString(this); michael@0: }, michael@0: notification: function notification() { michael@0: notImplemented('XML.notification'); michael@0: }, michael@0: setNotification: function setNotification(f) { michael@0: notImplemented('XML.setNotification'); michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: }; michael@0: XMLListClass = function XMLListClass(runtime, scope, instanceConstructor, baseClass) { michael@0: ASXMLList = function (value) { michael@0: if (!(this instanceof ASXMLList)) { michael@0: return callXMLList(value); michael@0: } michael@0: return constructXMLList(value); michael@0: }; michael@0: function callXMLList(v) { michael@0: if (v === null || v === undefined) { michael@0: v = ''; michael@0: } michael@0: return toXMLList(v); michael@0: } michael@0: function constructXMLList(val) { michael@0: if (val === null || val === undefined) { michael@0: val = ''; michael@0: } michael@0: if (val.isXMLList) { michael@0: var xl = new XMLList(); michael@0: xl.append(val); michael@0: return xl; michael@0: } michael@0: return toXMLList(val); michael@0: } michael@0: XMLList = function (targetObject, targetProperty) { michael@0: this.targetObject = targetObject ? targetObject : null; michael@0: this.targetProperty = targetProperty ? targetProperty : null; michael@0: this.children = []; michael@0: }; michael@0: var c = new Class('XMLList', ASXMLList, ApplicationDomain.passthroughCallable(ASXMLList)); michael@0: c.extend(baseClass); michael@0: var XLp = XMLList.prototype = ASXMLList.prototype; michael@0: XLp.canHandleProperties = true; michael@0: XLp.hasSimpleContent = function hasSimpleContent() { michael@0: if (this.length() === 0) { michael@0: return true; michael@0: } else if (this.length() === 1) { michael@0: return toXML(this).hasSimpleContent(); michael@0: } michael@0: var result = true; michael@0: this.children.forEach(function (v) { michael@0: if (v.kind === 'element') { michael@0: result = false; michael@0: } michael@0: }); michael@0: return result; michael@0: }; michael@0: XLp.asGetProperty = asGetProperty; michael@0: XLp.asGetResolvedStringProperty = asGetResolvedStringPropertyFallback; michael@0: XLp.asSetProperty = asSetProperty; michael@0: XLp.asHasProperty = asHasProperty; michael@0: XLp.asCallProperty = asCallProperty; michael@0: XLp.setProperty = function (mn, v, isMethod) { michael@0: var x, i, r; michael@0: x = this; michael@0: i = mn >>> 0; michael@0: if (String(mn) === String(i)) { michael@0: var targetObject = this.targetObject; michael@0: var targetProperty = this.targetProperty; michael@0: if (targetObject !== null) { michael@0: r = targetObject.resolveValue(); michael@0: if (r === null) { michael@0: return; michael@0: } michael@0: } else { michael@0: r = null; michael@0: } michael@0: if (i >= x.length()) { michael@0: if (r && r.isXMLList) { michael@0: if (r.length !== 1) { michael@0: return; michael@0: } else { michael@0: r = r.children[0]; michael@0: } michael@0: } michael@0: if (r && r.kind !== 'element') { michael@0: return; michael@0: } michael@0: var y = new XML(); michael@0: y.parent = r; michael@0: y.name = x.targetProperty; michael@0: if (targetProperty === null || targetProperty.localName === '*') { michael@0: y.name = null; michael@0: y.kind = 'text'; michael@0: } else if (targetProperty.isAttr) { michael@0: var attributeExists = r.getProperty(y.name); michael@0: if (attributeExists.length() > 0) { michael@0: return; michael@0: } michael@0: r.kind = 'attribute'; michael@0: } else { michael@0: y.kind = 'element'; michael@0: } michael@0: i = x.length(); michael@0: if (y.kind !== 'attribute') { michael@0: if (r !== null) { michael@0: if (i > 0) { michael@0: var j = 0; michael@0: while (j < r.length() - 1 && r.children[j] !== x.children[i - 1]) { michael@0: j++; michael@0: } michael@0: } else { michael@0: var j = r.length() - 1; michael@0: } michael@0: r.insert(String(j + 1), y); michael@0: } michael@0: if (v.isXML) { michael@0: y.name = v.name; michael@0: } else if (v.isXMLList) { michael@0: y.name = v.targetProperty; michael@0: } michael@0: } michael@0: x.append(y); michael@0: } michael@0: if (!v.isXML && !v.isXMLList || v.kind === 'text' || v.kind === 'attribute') { michael@0: v = toString(v); michael@0: } michael@0: if (x.children[i].kind === 'attribute') { michael@0: var z = toAttributeName(x.children[i].name); michael@0: x.children[i].parent.setProperty(z, v); michael@0: var attr = x.children[i].parent.getProperty(z); michael@0: x.children[i] = attr.children[0]; michael@0: } else if (v.isXMLList) { michael@0: var c = v.deepCopy(); michael@0: var parent = x.children[i].parent; michael@0: if (parent !== null) { michael@0: var q; michael@0: parent.children.some(function (v, p) { michael@0: if (v == x.children[i]) { michael@0: q = p; michael@0: return true; michael@0: } michael@0: }); michael@0: parent.replace(q, c); michael@0: c.children.forEach(function (v, j) { michael@0: c.children[j] = parent.children[q >>> 0 + j]; michael@0: }); michael@0: } michael@0: if (c.length() === 0) { michael@0: for (var j = x + 1; j < x.length() - 1; j++) { michael@0: x.children[String(j - 1)] = x.children[j]; michael@0: } michael@0: } else { michael@0: for (var j = x.length() - 1; j >= i + 1; j--) { michael@0: x.children[String(j + c.length() - 1)] = x.children[j]; michael@0: } michael@0: } michael@0: for (var j = 0; j < c.length(); j++) { michael@0: x.children[i + j] = c.children[j]; michael@0: } michael@0: } else if (v.isXML || (k = x.children[i].kind) === 'text' || k === 'comment' || k === 'processing-instruction') { michael@0: var parent = x.children[i].parent; michael@0: if (parent !== null) { michael@0: var q; michael@0: parent.children.some(function (v, p) { michael@0: if (v == x.children[i]) { michael@0: q = p; michael@0: return true; michael@0: } michael@0: }); michael@0: parent.replace(q, v); michael@0: var v = parent.children[q]; michael@0: } michael@0: if (typeof v === 'string') { michael@0: var t = new XML('text'); michael@0: t.parent = x; michael@0: t.value = v; michael@0: x.children[i] = t; michael@0: } else { michael@0: x.children[i] = v; michael@0: } michael@0: } else { michael@0: x.children[i].setProperty('*', v); michael@0: } michael@0: } else if (x.length() <= 1) { michael@0: if (x.length() === 0) { michael@0: r = x.resolveValue(); michael@0: if (r === null || r.length() !== 1) { michael@0: return; michael@0: } michael@0: x.append(r); michael@0: } michael@0: x.children[0].setProperty(mn, v); michael@0: } michael@0: }; michael@0: XLp.getProperty = function (mn, isMethod) { michael@0: if (isMethod) { michael@0: var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: return this[Multiname.getQualifiedName(resolved)]; michael@0: } michael@0: var x = this; michael@0: var i = mn >>> 0; michael@0: if (String(mn) === String(i)) { michael@0: return x.children[mn]; michael@0: } michael@0: var name = toXMLName(mn); michael@0: var xl = new XMLList(this, name); michael@0: x.children.forEach(function (v, i) { michael@0: var xl2; michael@0: if (v.kind === 'element') { michael@0: xl2 = v.getProperty(mn); michael@0: if (xl2.length() > 0) { michael@0: xl.append(xl2); michael@0: } michael@0: } michael@0: }); michael@0: return xl; michael@0: }; michael@0: XLp.hasProperty = function (mn, isMethod) { michael@0: if (isMethod) { michael@0: var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: return !(!this[Multiname.getQualifiedName(resolved)]); michael@0: } michael@0: var x = this; michael@0: var i = mn >>> 0; michael@0: if (String(mn) === String(i)) { michael@0: return !(!x.children[mn]); michael@0: } michael@0: var name = toXMLName(mn); michael@0: return this.children.some(function (v, i) { michael@0: var xl2 = v.getProperty(mn); michael@0: if (xl2.length() > 0) { michael@0: return true; michael@0: } michael@0: }); michael@0: }; michael@0: XLp.delete = function (key, isMethod) { michael@0: }; michael@0: XLp.append = function (val) { michael@0: if (val.isXMLList) { michael@0: this.targetObject = val.targetObject; michael@0: this.targetProperty = val.targetProperty; michael@0: if (val.length() === 0) { michael@0: return; michael@0: } michael@0: for (var i = 0; i < val.length(); i++) { michael@0: this.children.push(val.children[i]); michael@0: } michael@0: } else if (val.isXML) { michael@0: this.children.push(val); michael@0: } michael@0: }; michael@0: XLp.length = function () { michael@0: return this.children.length; michael@0: }; michael@0: XLp.resolve = function () { michael@0: var base = this.targetObject.resolveValue(); michael@0: if (base === null) { michael@0: return null; michael@0: } michael@0: var target = this.targetObject.getProperty(this.targetProperty); michael@0: if (base.length === 0) { michael@0: notImplemented('XMLList.resolve'); michael@0: base.setProperty(this.targetProperty, ''); michael@0: target = base.getProperty(this.targetProperty); michael@0: return target; michael@0: } michael@0: }; michael@0: XLp.deepCopy = function () { michael@0: var xl = new XMLList(); michael@0: this.children.forEach(function (v, i) { michael@0: xl.children[i] = v.deepCopy(); michael@0: }); michael@0: return xl; michael@0: }; michael@0: XLp.descendants = function (name) { michael@0: var xl = new XMLList(null); michael@0: this.children.forEach(function (v, i) { michael@0: if (v.kind === 'element') { michael@0: xl.append(v.descendants(name)); michael@0: } michael@0: }); michael@0: return xl; michael@0: }; michael@0: XLp.resolveValue = function resolveValue() { michael@0: if (this.length() > 0) { michael@0: return this; michael@0: } michael@0: var x = this; michael@0: var name = x.name; michael@0: var targetObject = x.targetObject; michael@0: var targetProperty = x.targetProperty; michael@0: if (targetObject === null || targetProperty === null || name.isAttr || name.isAny) { michael@0: return null; michael@0: } michael@0: var base = targetObject.resolveValue(); michael@0: if (base === null) { michael@0: return null; michael@0: } michael@0: var target = base.getProperty(targetProperty); michael@0: if (target.length() === 0) { michael@0: if (base.isXMLList && base.length() > 1) { michael@0: return null; michael@0: } michael@0: base.setProperty(targetProperty, ''); michael@0: target = base.getProperty(targetProperty); michael@0: } michael@0: return target; michael@0: }; michael@0: XLp.asGetEnumerableKeys = function asGetEnumerableKeys() { michael@0: if (XLp === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var keys = []; michael@0: this.children.forEach(function (v, i) { michael@0: keys.push(i); michael@0: }); michael@0: return keys; michael@0: }; michael@0: c.native = { michael@0: instance: { michael@0: init: function () { michael@0: } michael@0: } michael@0: }; michael@0: XLp.isXMLList = true; michael@0: c.native = { michael@0: static: {}, michael@0: instance: { michael@0: toString: function () { michael@0: return toString(this); michael@0: }, michael@0: hasOwnProperty: function hasOwnProperty(P) { michael@0: somewhatImplemented('XMLList.hasOwnProperty'); michael@0: return this.hasProperty(P); michael@0: }, michael@0: propertyIsEnumerable: function propertyIsEnumerable(P) { michael@0: notImplemented('XMLList.propertyIsEnumerable'); michael@0: }, michael@0: attribute: function attribute(name) { michael@0: return this.getProperty(toAttributeName(name)); michael@0: }, michael@0: attributes: function attributes() { michael@0: return this.getProperty(toAttributeName('*')); michael@0: }, michael@0: child: function child(propertyName) { michael@0: notImplemented('XMLList.child'); michael@0: }, michael@0: children: function children() { michael@0: var list = new XMLList(); michael@0: for (var i = 0; i < this.children.length; i++) { michael@0: var child = this.children[i]; michael@0: Array.prototype.push.apply(list.children, child.children); michael@0: } michael@0: return list; michael@0: }, michael@0: comments: function comments() { michael@0: var x = this; michael@0: var xl = new XMLList(x, null); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'element') { michael@0: xl.append(v.comments()); michael@0: } michael@0: }); michael@0: return xl; michael@0: }, michael@0: contains: function contains(value) { michael@0: for (var i = 0; i < this.children.length; i++) { michael@0: if (this.children[i] === value) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: }, michael@0: copy: function copy() { michael@0: return this.deepCopy(); michael@0: }, michael@0: descendants: function descendants(name) { michael@0: return this.descendants(name === undefined ? '*' : name); michael@0: }, michael@0: elements: function elements(name) { michael@0: var x = this; michael@0: var any = false; michael@0: if (name === undefined) { michael@0: name = '*'; michael@0: any = true; michael@0: } michael@0: var name = toXMLName(name); michael@0: var xl = new XMLList(x, name); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'element') { michael@0: xl.append(v.comments()); michael@0: } michael@0: }); michael@0: return xl; michael@0: }, michael@0: hasComplexContent: function hasComplexContent() { michael@0: notImplemented('XMLList.hasComplexContent'); michael@0: }, michael@0: hasSimpleContent: function hasSimpleContent() { michael@0: return this.hasSimpleContent(); michael@0: }, michael@0: length: function length() { michael@0: return this.children.length; michael@0: }, michael@0: name: function name() { michael@0: return toXML(this).name; michael@0: }, michael@0: normalize: function normalize() { michael@0: notImplemented('XMLList.normalize'); michael@0: }, michael@0: parent: function parent() { michael@0: notImplemented('XMLList.parent'); michael@0: }, michael@0: processingInstructions: function processingInstructions(name) { michael@0: notImplemented('XMLList.processingInstructions'); michael@0: }, michael@0: text: function text() { michael@0: var x = this; michael@0: var xl = new XMLList(x, null); michael@0: x.children.forEach(function (v, i) { michael@0: if (v.kind === 'text' || v.kind === 'element') { michael@0: xl.append(v.text()); michael@0: } michael@0: }); michael@0: return xl; michael@0: }, michael@0: toXMLString: function () { michael@0: return toXMLString(this); michael@0: }, michael@0: addNamespace: function addNamespace(ns) { michael@0: notImplemented('XMLList.addNamespace'); michael@0: }, michael@0: appendChild: function appendChild(child) { michael@0: toXML(this).appendChild(child); michael@0: return this; michael@0: }, michael@0: childIndex: function childIndex() { michael@0: notImplemented('XMLList.childIndex'); michael@0: }, michael@0: inScopeNamespaces: function inScopeNamespaces() { michael@0: notImplemented('XMLList.inScopeNamespaces'); michael@0: }, michael@0: insertChildAfter: function insertChildAfter(child1, child2) { michael@0: notImplemented('XMLList.insertChildAfter'); michael@0: }, michael@0: insertChildBefore: function insertChildBefore(child1, child2) { michael@0: notImplemented('XMLList.insertChildBefore'); michael@0: }, michael@0: nodeKind: function nodeKind() { michael@0: return toXML(this).kind; michael@0: }, michael@0: _namespace: function _namespace(prefix, argc) { michael@0: notImplemented('XMLList._namespace'); michael@0: }, michael@0: localName: function localName() { michael@0: notImplemented('XMLList.localName'); michael@0: }, michael@0: namespaceDeclarations: function namespaceDeclarations() { michael@0: somewhatImplemented('XMLList.prototype.namespaceDeclarations()'); michael@0: return new XMLList(); michael@0: }, michael@0: prependChild: function prependChild(value) { michael@0: notImplemented('XMLList.prependChild'); michael@0: }, michael@0: removeNamespace: function removeNamespace(ns) { michael@0: notImplemented('XMLList.removeNamespace'); michael@0: }, michael@0: replace: function replace(propertyName, value) { michael@0: toXML(this).replace(propertyName, value); michael@0: return this; michael@0: }, michael@0: setChildren: function setChildren(value) { michael@0: notImplemented('XMLList.setChildren'); michael@0: }, michael@0: setLocalName: function setLocalName(name) { michael@0: notImplemented('XMLList.setLocalName'); michael@0: }, michael@0: setName: function setName(name) { michael@0: notImplemented('XMLList.setName'); michael@0: }, michael@0: setNamespace: function setNamespace(ns) { michael@0: notImplemented('XMLList.setNamespace'); michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: }; michael@0: QNameClass = function QNameClass(runtime, scope, instanceConstructor, baseClass) { michael@0: QName = function QName(ns, name, isAttr) { michael@0: if (!(this instanceof QName)) { michael@0: if (name === undefined && ns instanceof QName) { michael@0: return ns; michael@0: } else { michael@0: return new QName(ns, name); michael@0: } michael@0: } michael@0: if (name === undefined) { michael@0: name = ns; michael@0: ns = undefined; michael@0: } michael@0: if (typeof ns === 'string' || ns instanceof QName) { michael@0: ns = new ASNamespace(ns); michael@0: } michael@0: var mn; michael@0: if (name instanceof QName) { michael@0: if (ns === undefined) { michael@0: mn = name.mn; michael@0: } else { michael@0: mn = new Multiname([ michael@0: ns michael@0: ], name.mn.getName()); michael@0: } michael@0: } else if (name instanceof Multiname) { michael@0: if (ns === undefined) { michael@0: if (name.isQName() || name.isAnyName() || name.isAnyNamespace()) { michael@0: mn = name; michael@0: } else { michael@0: mn = new Multiname([ michael@0: getDefaultNamespace(scope) michael@0: ], name.getName(), name.flags); michael@0: } michael@0: } else { michael@0: mn = new Multiname([ michael@0: ns michael@0: ], name.getName(), name.flags); michael@0: } michael@0: } else if (name === '*') { michael@0: mn = new Multiname([], null, isAttr ? Multiname.ATTRIBUTE : 0); michael@0: } else if (name === '@*') { michael@0: mn = new Multiname([], null, Multiname.ATTRIBUTE); michael@0: } else { michael@0: ns = ns === undefined ? getDefaultNamespace(scope) : ns; michael@0: if (name === undefined) { michael@0: mn = new Multiname([ michael@0: ns michael@0: ], ''); michael@0: } else { michael@0: mn = new Multiname([ michael@0: ns michael@0: ], toString(name), isAttr ? Multiname.ATTRIBUTE : 0); michael@0: } michael@0: } michael@0: this.mn = mn; michael@0: this.isAny = mn.isAnyName(); michael@0: this.isAnyNamespace = mn.isAnyNamespace(); michael@0: this.isAttr = mn.isAttribute(); michael@0: }; michael@0: var c = new Class('QName', QName, ApplicationDomain.passthroughCallable(QName)); michael@0: c.extend(baseClass); michael@0: QNp = QName.prototype; michael@0: defineNonEnumerableGetter(QNp, 'localName', function () { michael@0: if (!this._localName) { michael@0: this._localName = this.isAny ? '*' : this.mn.getName(); michael@0: } michael@0: return this._localName; michael@0: }); michael@0: defineNonEnumerableGetter(QNp, 'uri', function () { michael@0: if (!this._uri) { michael@0: var ns = this.mn.namespaces[0]; michael@0: this._uri = ns && ns.uri ? ns.uri : this.isAny || this.isAnyNamespace ? null : ''; michael@0: } michael@0: return this._uri; michael@0: }); michael@0: defineNonEnumerableGetter(QNp, 'prefix', function () { michael@0: return this.mn.namespaces[0].prefix; michael@0: }); michael@0: defineNonEnumerableSetter(QNp, 'prefix', function (prefix) { michael@0: this.mn.namespaces[0].prefix = prefix; michael@0: }); michael@0: QNp.getNamespace = function (isns) { michael@0: if (this.uri === null) { michael@0: throw 'TypeError in QName.prototype.getNamespace()'; michael@0: } michael@0: if (!isns) { michael@0: isns = []; michael@0: } michael@0: var ns; michael@0: for (var i = 0; i < isns.length; i++) { michael@0: if (this.uri === isns[i].uri) { michael@0: ns = isns[i]; michael@0: } michael@0: } michael@0: if (!ns) { michael@0: ns = ASNamespace.createNamespace(this.uri); michael@0: } michael@0: return ns; michael@0: }; michael@0: c.native = { michael@0: static: {}, michael@0: instance: { michael@0: localName: { michael@0: get: function localName() { michael@0: return this.localName; michael@0: } michael@0: }, michael@0: uri: { michael@0: get: function uri() { michael@0: return this.uri; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: }; michael@0: }()); michael@0: var AMFUtils = function AMFUtilsClosure() { michael@0: var AMF0_NUMBER_MARKER = 0; michael@0: var AMF0_BOOLEAN_MARKER = 1; michael@0: var AMF0_STRING_MARKER = 2; michael@0: var AMF0_OBJECT_MARKER = 3; michael@0: var AMF0_NULL_MARKER = 5; michael@0: var AMF0_UNDEFINED_MARKER = 6; michael@0: var AMF0_REFERENCE_MARKER = 7; michael@0: var AMF0_ECMA_ARRAY_MARKER = 8; michael@0: var AMF0_OBJECT_END_MARKER = 9; michael@0: var AMF0_STRICT_ARRAY_MARKER = 10; michael@0: var AMF0_DATE_MARKER = 11; michael@0: var AMF0_LONG_STRING_MARKER = 12; michael@0: var AMF0_XML_MARKER = 15; michael@0: var AMF0_TYPED_OBJECT_MARKER = 16; michael@0: var AMF0_AVMPLUS_MARKER = 17; michael@0: function writeString(ba, s) { michael@0: if (s.length > 65535) { michael@0: throw 'AMF short string exceeded'; michael@0: } michael@0: if (!s.length) { michael@0: ba.writeByte(0); michael@0: ba.writeByte(0); michael@0: return; michael@0: } michael@0: var bytes = utf8decode(s); michael@0: ba.writeByte(bytes.length >> 8 & 255); michael@0: ba.writeByte(bytes.length & 255); michael@0: for (var i = 0; i < bytes.length; i++) { michael@0: ba.writeByte(bytes[i]); michael@0: } michael@0: } michael@0: function readString(ba) { michael@0: var byteLength = ba.readByte() << 8 | ba.readByte(); michael@0: if (!byteLength) { michael@0: return ''; michael@0: } michael@0: var buffer = new Uint8Array(byteLength); michael@0: for (var i = 0; i < byteLength; i++) { michael@0: buffer[i] = ba.readByte(); michael@0: } michael@0: return utf8encode(buffer); michael@0: } michael@0: function writeDouble(ba, value) { michael@0: var buffer = new ArrayBuffer(8); michael@0: var view = new DataView(buffer); michael@0: view.setFloat64(0, value, false); michael@0: for (var i = 0; i < buffer.byteLength; i++) { michael@0: ba.writeByte(view.getUint8(i)); michael@0: } michael@0: } michael@0: function readDouble(ba) { michael@0: var buffer = new ArrayBuffer(8); michael@0: var view = new DataView(buffer); michael@0: for (var i = 0; i < buffer.byteLength; i++) { michael@0: view.setUint8(i, ba.readByte()); michael@0: } michael@0: return view.getFloat64(0, false); michael@0: } michael@0: function setAvmProperty(obj, propertyName, value) { michael@0: obj.asSetPublicProperty(propertyName, value); michael@0: } michael@0: var amf0 = { michael@0: write: function (ba, obj) { michael@0: switch (typeof obj) { michael@0: case 'boolean': michael@0: ba.writeByte(AMF0_BOOLEAN_MARKER); michael@0: ba.writeByte(obj ? 1 : 0); michael@0: break; michael@0: case 'number': michael@0: ba.writeByte(AMF0_NUMBER_MARKER); michael@0: writeDouble(ba, obj); michael@0: break; michael@0: case 'undefined': michael@0: ba.writeByte(AMF0_UNDEFINED_MARKER); michael@0: break; michael@0: case 'string': michael@0: ba.writeByte(AMF0_STRING_MARKER); michael@0: writeString(ba, obj); michael@0: break; michael@0: case 'object': michael@0: if (obj === null) { michael@0: ba.writeByte(AMF0_NULL_MARKER); michael@0: } else if (Array.isArray(obj)) { michael@0: ba.writeByte(AMF0_ECMA_ARRAY_MARKER); michael@0: ba.writeByte(obj.length >>> 24 & 255); michael@0: ba.writeByte(obj.length >> 16 & 255); michael@0: ba.writeByte(obj.length >> 8 & 255); michael@0: ba.writeByte(obj.length & 255); michael@0: forEachPublicProperty(obj, function (key, value) { michael@0: writeString(ba, key); michael@0: this.write(ba, value); michael@0: }, this); michael@0: ba.writeByte(0); michael@0: ba.writeByte(0); michael@0: ba.writeByte(AMF0_OBJECT_END_MARKER); michael@0: } else { michael@0: ba.writeByte(AMF0_OBJECT_MARKER); michael@0: forEachPublicProperty(obj, function (key, value) { michael@0: writeString(ba, key); michael@0: this.write(ba, value); michael@0: }, this); michael@0: ba.writeByte(0); michael@0: ba.writeByte(0); michael@0: ba.writeByte(AMF0_OBJECT_END_MARKER); michael@0: } michael@0: return; michael@0: } michael@0: }, michael@0: read: function (ba) { michael@0: var marker = ba.readByte(); michael@0: switch (marker) { michael@0: case AMF0_NUMBER_MARKER: michael@0: return readDouble(ba); michael@0: case AMF0_BOOLEAN_MARKER: michael@0: return !(!ba.readByte()); michael@0: case AMF0_STRING_MARKER: michael@0: return readString(ba); michael@0: case AMF0_OBJECT_MARKER: michael@0: var obj = {}; michael@0: while (true) { michael@0: var key = readString(ba); michael@0: if (!key.length) michael@0: break; michael@0: setAvmProperty(obj, key, this.read(ba)); michael@0: } michael@0: if (ba.readByte() !== AMF0_OBJECT_END_MARKER) { michael@0: throw 'AMF0 End marker is not found'; michael@0: } michael@0: return obj; michael@0: case AMF0_NULL_MARKER: michael@0: return null; michael@0: case AMF0_UNDEFINED_MARKER: michael@0: return undefined; michael@0: case AMF0_ECMA_ARRAY_MARKER: michael@0: var obj = []; michael@0: obj.length = ba.readByte() << 24 | ba.readByte() << 16 | ba.readByte() << 8 | ba.readByte(); michael@0: while (true) { michael@0: var key = readString(ba); michael@0: if (!key.length) michael@0: break; michael@0: setAvmProperty(obj, key, this.read(ba)); michael@0: } michael@0: if (ba.readByte() !== AMF0_OBJECT_END_MARKER) { michael@0: throw 'AMF0 End marker is not found'; michael@0: } michael@0: return obj; michael@0: case AMF0_STRICT_ARRAY_MARKER: michael@0: var obj = []; michael@0: obj.length = ba.readByte() << 24 | ba.readByte() << 16 | ba.readByte() << 8 | ba.readByte(); michael@0: for (var i = 0; i < obj.length; i++) { michael@0: obj[i] = this.read(ba); michael@0: } michael@0: return obj; michael@0: case AMF0_AVMPLUS_MARKER: michael@0: return readAmf3Data(ba, {}); michael@0: default: michael@0: throw 'AMF0 Unknown marker ' + marker; michael@0: } michael@0: } michael@0: }; michael@0: var AMF3_UNDEFINED_MARKER = 0; michael@0: var AMF3_NULL_MARKER = 1; michael@0: var AMF3_FALSE_MARKER = 2; michael@0: var AMF3_TRUE_MARKER = 3; michael@0: var AMF3_INTEGER_MARKER = 4; michael@0: var AMF3_DOUBLE_MARKER = 5; michael@0: var AMF3_STRING_MARKER = 6; michael@0: var AMF3_XML_DOC_MARKER = 7; michael@0: var AMF3_DATE_MARKER = 8; michael@0: var AMF3_ARRAY_MARKER = 9; michael@0: var AMF3_OBJECT_MARKER = 10; michael@0: var AMF3_XML_MARKER = 11; michael@0: var AMF3_BYTEARRAY_MARKER = 12; michael@0: var AMF3_VECTOR_INT_MARKER = 13; michael@0: var AMF3_VECTOR_UINT_MARKER = 14; michael@0: var AMF3_VECTOR_DOUBLE_MARKER = 15; michael@0: var AMF3_VECTOR_OBJECT_MARKER = 16; michael@0: var AMF3_DICTIONARY_MARKER = 17; michael@0: function readU29(ba) { michael@0: var b1 = ba.readByte(); michael@0: if ((b1 & 128) === 0) { michael@0: return b1; michael@0: } michael@0: var b2 = ba.readByte(); michael@0: if ((b2 & 128) === 0) { michael@0: return (b1 & 127) << 7 | b2; michael@0: } michael@0: var b3 = ba.readByte(); michael@0: if ((b3 & 128) === 0) { michael@0: return (b1 & 127) << 14 | (b2 & 127) << 7 | b3; michael@0: } michael@0: var b4 = ba.readByte(); michael@0: return (b1 & 127) << 22 | (b2 & 127) << 15 | (b3 & 127) << 8 | b4; michael@0: } michael@0: function writeU29(ba, value) { michael@0: if ((value & 4294967168) === 0) { michael@0: ba.writeByte(value & 127); michael@0: } else if ((value & 4294950912) === 0) { michael@0: ba.writeByte(128 | value >> 7 & 127); michael@0: ba.writeByte(value & 127); michael@0: } else if ((value & 4292870144) === 0) { michael@0: ba.writeByte(128 | value >> 14 & 127); michael@0: ba.writeByte(128 | value >> 7 & 127); michael@0: ba.writeByte(value & 127); michael@0: } else if ((value & 3221225472) === 0) { michael@0: ba.writeByte(128 | value >> 22 & 127); michael@0: ba.writeByte(128 | value >> 15 & 127); michael@0: ba.writeByte(128 | value >> 8 & 127); michael@0: ba.writeByte(value & 255); michael@0: } else { michael@0: throw 'AMF3 U29 range'; michael@0: } michael@0: } michael@0: function readUTF8vr(ba, caches) { michael@0: var u29s = readU29(ba); michael@0: if (u29s === 1) { michael@0: return ''; michael@0: } michael@0: var stringsCache = caches.stringsCache || (caches.stringsCache = []); michael@0: if ((u29s & 1) === 0) { michael@0: return stringsCache[u29s >> 1]; michael@0: } michael@0: var byteLength = u29s >> 1; michael@0: var buffer = new Uint8Array(byteLength); michael@0: for (var i = 0; i < byteLength; i++) { michael@0: buffer[i] = ba.readByte(); michael@0: } michael@0: var value = utf8encode(buffer); michael@0: stringsCache.push(value); michael@0: return value; michael@0: } michael@0: function writeUTF8vr(ba, value, caches) { michael@0: if (value === '') { michael@0: ba.writeByte(1); michael@0: return; michael@0: } michael@0: var stringsCache = caches.stringsCache || (caches.stringsCache = []); michael@0: var index = stringsCache.indexOf(value); michael@0: if (index >= 0) { michael@0: writeU29(ba, index << 1); michael@0: return; michael@0: } michael@0: stringsCache.push(value); michael@0: var bytes = utf8decode(value); michael@0: writeU29(ba, 1 | bytes.length << 1); michael@0: for (var i = 0; i < bytes.length; i++) { michael@0: ba.writeByte(bytes[i]); michael@0: } michael@0: } michael@0: function readAmf3Data(ba, caches) { michael@0: var marker = ba.readByte(); michael@0: switch (marker) { michael@0: case AMF3_NULL_MARKER: michael@0: return null; michael@0: case AMF3_UNDEFINED_MARKER: michael@0: return undefined; michael@0: case AMF3_FALSE_MARKER: michael@0: return false; michael@0: case AMF3_TRUE_MARKER: michael@0: return true; michael@0: case AMF3_INTEGER_MARKER: michael@0: return readU29(ba); michael@0: case AMF3_DOUBLE_MARKER: michael@0: return readDouble(ba); michael@0: case AMF3_STRING_MARKER: michael@0: return readUTF8vr(ba, caches); michael@0: case AMF3_DATE_MARKER: michael@0: return new Date(readDouble(ba)); michael@0: case AMF3_OBJECT_MARKER: michael@0: var u29o = readU29(ba); michael@0: if ((u29o & 1) === 0) { michael@0: return caches.objectsCache[u29o >> 1]; michael@0: } michael@0: if ((u29o & 4) !== 0) { michael@0: throw 'AMF3 Traits-Ext is not supported'; michael@0: } michael@0: var traits, objectClass; michael@0: if ((u29o & 2) === 0) { michael@0: traits = caches.traitsCache[u29o >> 2]; michael@0: objectClass = traits.class; michael@0: } else { michael@0: traits = {}; michael@0: var aliasName = readUTF8vr(ba, caches); michael@0: traits.className = aliasName; michael@0: objectClass = aliasName && aliasesCache.names[aliasName]; michael@0: traits.class = objectClass; michael@0: traits.isDynamic = (u29o & 8) !== 0; michael@0: traits.members = []; michael@0: var slots = objectClass && objectClass.instanceBindings.slots; michael@0: for (var i = 0, j = u29o >> 4; i < j; i++) { michael@0: var traitName = readUTF8vr(ba, caches); michael@0: var slot = null; michael@0: for (var j = 1; slots && j < slots.length; j++) { michael@0: if (slots[j].name.name === traitName) { michael@0: slot = slots[j]; michael@0: break; michael@0: } michael@0: } michael@0: traits.members.push(slot ? Multiname.getQualifiedName(slot.name) : Multiname.getPublicQualifiedName(traitName)); michael@0: } michael@0: (caches.traitsCache || (caches.traitsCache = [])).push(traits); michael@0: } michael@0: var obj = objectClass ? objectClass.createInstance() : {}; michael@0: (caches.objectsCache || (caches.objectsCache = [])).push(obj); michael@0: for (var i = 0; i < traits.members.length; i++) { michael@0: var value = readAmf3Data(ba, caches); michael@0: obj[traits.members[i]] = value; michael@0: } michael@0: if (traits.isDynamic) { michael@0: while (true) { michael@0: var key = readUTF8vr(ba, caches); michael@0: if (!key.length) michael@0: break; michael@0: var value = readAmf3Data(ba, caches); michael@0: setAvmProperty(obj, key, value); michael@0: } michael@0: } michael@0: return obj; michael@0: case AMF3_ARRAY_MARKER: michael@0: var u29o = readU29(ba); michael@0: if ((u29o & 1) === 0) { michael@0: return caches.objectsCache[u29o >> 1]; michael@0: } michael@0: var obj = []; michael@0: (caches.objectsCache || (caches.objectsCache = [])).push(obj); michael@0: var densePortionLength = u29o >> 1; michael@0: while (true) { michael@0: var key = readUTF8vr(ba, caches); michael@0: if (!key.length) michael@0: break; michael@0: var value = readAmf3Data(ba, caches); michael@0: setAvmProperty(obj, key, value); michael@0: } michael@0: for (var i = 0; i < densePortionLength; i++) { michael@0: var value = readAmf3Data(ba, caches); michael@0: setAvmProperty(obj, i, value); michael@0: } michael@0: return obj; michael@0: default: michael@0: throw 'AMF3 Unknown marker ' + marker; michael@0: } michael@0: } michael@0: function writeCachedReference(ba, obj, caches) { michael@0: var objectsCache = caches.objectsCache || (caches.objectsCache = []); michael@0: var index = objectsCache.indexOf(obj); michael@0: if (index < 0) { michael@0: objectsCache.push(obj); michael@0: return false; michael@0: } michael@0: writeU29(ba, index << 1); michael@0: return true; michael@0: } michael@0: function writeAmf3Data(ba, obj, caches) { michael@0: switch (typeof obj) { michael@0: case 'boolean': michael@0: ba.writeByte(obj ? AMF3_TRUE_MARKER : AMF3_FALSE_MARKER); michael@0: break; michael@0: case 'number': michael@0: if (obj === (obj | 0)) { michael@0: ba.writeByte(AMF3_INTEGER_MARKER); michael@0: writeU29(ba, obj); michael@0: } else { michael@0: ba.writeByte(AMF3_DOUBLE_MARKER); michael@0: writeDouble(ba, obj); michael@0: } michael@0: break; michael@0: case 'undefined': michael@0: ba.writeByte(AMF3_UNDEFINED_MARKER); michael@0: break; michael@0: case 'string': michael@0: ba.writeByte(AMF3_STRING_MARKER); michael@0: writeUTF8vr(ba, obj, caches); michael@0: break; michael@0: case 'object': michael@0: if (obj === null) { michael@0: ba.writeByte(AMF3_NULL_MARKER); michael@0: } else if (Array.isArray(obj)) { michael@0: ba.writeByte(AMF3_ARRAY_MARKER); michael@0: if (writeCachedReference(ba, obj, caches)) michael@0: break; michael@0: var densePortionLength = 0; michael@0: while (densePortionLength in obj) { michael@0: ++densePortionLength; michael@0: } michael@0: writeU29(ba, densePortionLength << 1 | 1); michael@0: forEachPublicProperty(obj, function (i, value) { michael@0: if (isNumeric(i) && i >= 0 && i < densePortionLength) { michael@0: return; michael@0: } michael@0: writeUTF8vr(ba, i, caches); michael@0: writeAmf3Data(ba, value, caches); michael@0: }); michael@0: writeUTF8vr(ba, '', caches); michael@0: for (var j = 0; j < densePortionLength; j++) { michael@0: writeAmf3Data(ba, obj[j], caches); michael@0: } michael@0: } else if (obj instanceof Date) { michael@0: ba.writeByte(AMF3_DATE_MARKER); michael@0: if (writeCachedReference(ba, obj, caches)) michael@0: break; michael@0: writeU29(ba, 1); michael@0: writeDouble(ba, obj.valueOf()); michael@0: } else { michael@0: ba.writeByte(AMF3_OBJECT_MARKER); michael@0: if (writeCachedReference(ba, obj, caches)) michael@0: break; michael@0: var isDynamic = true; michael@0: var objectClass = obj.class; michael@0: if (objectClass) { michael@0: isDynamic = !objectClass.classInfo.instanceInfo.isSealed(); michael@0: var aliasName = aliasesCache.classes.get(objectClass) || ''; michael@0: var traits, traitsCount; michael@0: var traitsCache = caches.traitsCache || (caches.traitsCache = []); michael@0: var traitsInfos = caches.traitsInfos || (caches.traitsInfos = []); michael@0: var traitsRef = traitsCache.indexOf(objectClass); michael@0: if (traitsRef < 0) { michael@0: var slots = objectClass.instanceBindings.slots; michael@0: traits = []; michael@0: var traitsNames = []; michael@0: for (var i = 1; i < slots.length; i++) { michael@0: var slot = slots[i]; michael@0: if (!slot.name.getNamespace().isPublic()) { michael@0: continue; michael@0: } michael@0: traits.push(Multiname.getQualifiedName(slot.name)); michael@0: traitsNames.push(slot.name.name); michael@0: } michael@0: traitsCache.push(objectClass); michael@0: traitsInfos.push(traits); michael@0: traitsCount = traitsNames.length; michael@0: writeU29(ba, (isDynamic ? 11 : 3) + (traitsCount << 4)); michael@0: writeUTF8vr(ba, aliasName, caches); michael@0: for (var i = 0; i < traitsCount; i++) { michael@0: writeUTF8vr(ba, traitsNames[i], caches); michael@0: } michael@0: } else { michael@0: traits = traitsInfos[traitsRef]; michael@0: traitsCount = traits.length; michael@0: writeU29(ba, 1 + (traitsRef << 2)); michael@0: } michael@0: for (var i = 0; i < traitsCount; i++) { michael@0: writeAmf3Data(ba, obj[traits[i]], caches); michael@0: } michael@0: } else { michael@0: writeU29(ba, 11); michael@0: writeUTF8vr(ba, '', caches); michael@0: } michael@0: if (isDynamic) { michael@0: forEachPublicProperty(obj, function (i, value) { michael@0: writeUTF8vr(ba, i, caches); michael@0: writeAmf3Data(ba, value, caches); michael@0: }); michael@0: writeUTF8vr(ba, '', caches); michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: } michael@0: var aliasesCache = { michael@0: classes: new WeakMap(), michael@0: names: Object.create(null) michael@0: }; michael@0: var amf3 = { michael@0: write: function (ba, obj) { michael@0: writeAmf3Data(ba, obj, {}); michael@0: }, michael@0: read: function (ba) { michael@0: return readAmf3Data(ba, {}); michael@0: } michael@0: }; michael@0: return { michael@0: encodings: [ michael@0: amf0, michael@0: null, michael@0: null, michael@0: amf3 michael@0: ], michael@0: aliasesCache: aliasesCache michael@0: }; michael@0: }(); michael@0: function ProxyClass(runtime, scope, instanceConstructor, baseClass) { michael@0: function ProxyConstructor() { michael@0: somewhatImplemented('Proxy'); michael@0: } michael@0: var c = new Class('Proxy', ProxyConstructor, ApplicationDomain.coerceCallable(ProxyConstructor)); michael@0: c.extendBuiltin(baseClass); michael@0: return c; michael@0: } michael@0: var proxyTrapQns = { michael@0: 'getProperty': null, michael@0: 'setProperty': null, michael@0: 'hasProperty': null, michael@0: 'callProperty': null michael@0: }; michael@0: for (var name in proxyTrapQns) { michael@0: proxyTrapQns[name] = VM_OPEN_METHOD_PREFIX + Multiname.getQualifiedName(new Multiname([ michael@0: ASNamespace.PROXY michael@0: ], name)); michael@0: } michael@0: function isProxyObject(obj) { michael@0: return obj[VM_IS_PROXY]; michael@0: } michael@0: function nameFromQualifiedName(qn) { michael@0: if (isNumeric(qn)) { michael@0: return qn; michael@0: } michael@0: var mn = Multiname.fromQualifiedName(qn); michael@0: if (mn === undefined) { michael@0: return undefined; michael@0: } michael@0: return mn.name; michael@0: } michael@0: function hasNonProxyingCaller() { michael@0: var caller = arguments.callee; michael@0: var maxDepth = 5; michael@0: var domain; michael@0: for (var i = 0; i < maxDepth && caller; i++) { michael@0: if (caller === nonProxyingHasProperty) { michael@0: return true; michael@0: } michael@0: caller = caller.caller; michael@0: } michael@0: return false; michael@0: } michael@0: function installProxyClassWrapper(cls) { michael@0: var TRACE_PROXY = false; michael@0: if (TRACE_PROXY) { michael@0: print('proxy wrapping, class: ' + cls); michael@0: } michael@0: var instanceConstructor = cls.instanceConstructor; michael@0: function construct() { michael@0: if (TRACE_PROXY) { michael@0: print('proxy create, class: ' + cls); michael@0: } michael@0: var target = Object.create(instanceConstructor.prototype); michael@0: var proxy = Proxy.create({ michael@0: get: function (o, qn) { michael@0: if (qn === VM_IS_PROXY) { michael@0: TRACE_PROXY && print('proxy check'); michael@0: return true; michael@0: } michael@0: if (qn === VM_CALL_PROXY) { michael@0: TRACE_PROXY && print('proxy get caller'); michael@0: return function apply(mn, receiver, args) { michael@0: receiver = receiver ? target : null; michael@0: if (TRACE_PROXY) { michael@0: print('proxy call, class: ' + target.class + ', mn: ' + mn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller()); michael@0: } michael@0: var resolved = Multiname.isQName(mn) ? mn : target.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags); michael@0: var qn = resolved ? Multiname.getQualifiedName(resolved) : Multiname.getPublicQualifiedName(mn.name); michael@0: if (!nameInTraits(target, qn)) { michael@0: return target[proxyTrapQns.callProperty](mn.name, args); michael@0: } michael@0: if (TRACE_PROXY) { michael@0: TRACE_PROXY && print('> proxy pass through ' + resolved); michael@0: } michael@0: if (target.asOpenMethods && target.asOpenMethods[qn]) { michael@0: return target.asOpenMethods[qn].apply(o, args); michael@0: } michael@0: return undefined; michael@0: }; michael@0: } michael@0: if (TRACE_PROXY) { michael@0: print('proxy get, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller()); michael@0: } michael@0: if (!hasNonProxyingCaller()) { michael@0: var name = nameFromQualifiedName(qn); michael@0: if (name !== undefined && !nameInTraits(target, qn)) { michael@0: return target[proxyTrapQns.getProperty](name); michael@0: } michael@0: } michael@0: if (target.asOpenMethods && target.asOpenMethods[qn]) { michael@0: return bindSafely(target.asOpenMethods[qn], o); michael@0: } michael@0: TRACE_PROXY && print('> proxy pass through ' + qn); michael@0: return target[qn]; michael@0: }, michael@0: set: function (o, qn, value) { michael@0: if (TRACE_PROXY) { michael@0: print('proxy set, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller()); michael@0: } michael@0: if (!hasNonProxyingCaller()) { michael@0: var name = nameFromQualifiedName(qn); michael@0: if (name !== undefined && !nameInTraits(target, qn)) { michael@0: target[proxyTrapQns.setProperty](name, value); michael@0: return; michael@0: } michael@0: } michael@0: TRACE_PROXY && print('> proxy pass through ' + qn); michael@0: target[qn] = value; michael@0: }, michael@0: has: function (qn) { michael@0: if (TRACE_PROXY) { michael@0: print('proxy has, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller()); michael@0: } michael@0: if (!hasNonProxyingCaller()) { michael@0: var name = nameFromQualifiedName(qn); michael@0: if (name !== undefined && !nameInTraits(target, qn)) { michael@0: return target[proxyTrapQns.hasProperty](name); michael@0: } michael@0: } michael@0: return qn in target; michael@0: }, michael@0: hasOwn: function (qn) { michael@0: if (TRACE_PROXY) { michael@0: print('proxy hasOwn, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller()); michael@0: } michael@0: if (!hasNonProxyingCaller()) { michael@0: var name = nameFromQualifiedName(qn); michael@0: if (name !== undefined && !nameInTraits(target, qn)) { michael@0: return target[proxyTrapQns.hasProperty](name); michael@0: } michael@0: } michael@0: TRACE_PROXY && print('> proxy pass through ' + qn); michael@0: return !(!Object.getOwnPropertyDescriptor(target, qn)); michael@0: }, michael@0: enumerate: function () { michael@0: notImplemented('enumerate'); michael@0: }, michael@0: keys: function () { michael@0: notImplemented('keys'); michael@0: } michael@0: }, instanceConstructor.prototype); michael@0: instanceConstructor.apply(proxy, sliceArguments(arguments, 0)); michael@0: return proxy; michael@0: } michael@0: cls.instanceConstructor = construct; michael@0: } michael@0: function DictionaryClass(domain, scope, instanceConstructor, baseClass) { michael@0: function ASDictionary(weakKeys) { michael@0: this.weakKeys = weakKeys; michael@0: this.map = new WeakMap(); michael@0: if (!weakKeys) { michael@0: this.keys = []; michael@0: } michael@0: this.primitiveMap = createEmptyObject(); michael@0: } michael@0: var c = new Class('Dictionary', ASDictionary, ApplicationDomain.passthroughCallable(ASDictionary)); michael@0: c.extendNative(baseClass, ASDictionary); michael@0: function makePrimitiveKey(key) { michael@0: if (typeof key === 'string' || typeof key === 'number') { michael@0: return key; michael@0: } michael@0: return undefined; michael@0: } michael@0: var prototype = ASDictionary.prototype; michael@0: defineNonEnumerableProperty(prototype, 'asGetProperty', function asGetProperty(namespaces, name, flags, isMethod) { michael@0: var key = makePrimitiveKey(name); michael@0: if (key !== undefined) { michael@0: return this.primitiveMap[key]; michael@0: } michael@0: return this.map.get(Object(name)); michael@0: }); michael@0: defineNonEnumerableProperty(prototype, 'asGetResolvedStringProperty', asGetResolvedStringPropertyFallback); michael@0: defineNonEnumerableProperty(prototype, 'asSetProperty', function asSetProperty(namespaces, name, flags, value) { michael@0: var key = makePrimitiveKey(name); michael@0: if (key !== undefined) { michael@0: this.primitiveMap[key] = value; michael@0: return; michael@0: } michael@0: this.map.set(Object(name), value); michael@0: if (!this.weakKeys && this.keys.indexOf(name) < 0) { michael@0: this.keys.push(name); michael@0: } michael@0: }); michael@0: defineNonEnumerableProperty(prototype, 'asCallProperty', function asCallProperty(namespaces, name, flags, isLex, args) { michael@0: notImplemented('asCallProperty'); michael@0: }); michael@0: defineNonEnumerableProperty(prototype, 'asHasProperty', function asHasProperty(namespaces, name, flags, nonProxy) { michael@0: var key = makePrimitiveKey(name); michael@0: if (key !== undefined) { michael@0: return key in this.primitiveMap; michael@0: } michael@0: return this.map.has(Object(name)); michael@0: }); michael@0: defineNonEnumerableProperty(prototype, 'asDeleteProperty', function asDeleteProperty(namespaces, name, flags) { michael@0: var key = makePrimitiveKey(name); michael@0: if (key !== undefined) { michael@0: delete this.primitiveMap[key]; michael@0: } michael@0: this.map.delete(Object(name)); michael@0: var i; michael@0: if (!this.weakKeys && (i = this.keys.indexOf(name)) >= 0) { michael@0: this.keys.splice(i, 1); michael@0: } michael@0: return true; michael@0: }); michael@0: defineNonEnumerableProperty(prototype, 'asGetEnumerableKeys', function () { michael@0: if (prototype === this) { michael@0: return Object.prototype.asGetEnumerableKeys.call(this); michael@0: } michael@0: var primitiveMapKeys = []; michael@0: for (var k in this.primitiveMap) { michael@0: primitiveMapKeys.push(k); michael@0: } michael@0: if (this.weakKeys) { michael@0: return primitiveMapKeys; michael@0: } michael@0: return primitiveMapKeys.concat(this.keys); michael@0: }); michael@0: c.native = { michael@0: instance: { michael@0: init: function () { michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function debugBreak(message) { michael@0: debugger; michael@0: print('\x1b[91mdebugBreak: ' + message + '\x1b[0m'); michael@0: } michael@0: var NativeASNamespace; michael@0: var natives = function () { michael@0: var C = ApplicationDomain.passthroughCallable; michael@0: var CC = ApplicationDomain.constructingCallable; michael@0: function ObjectClass(applicationDomain, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Object', Object, C(Object)); michael@0: c.native = { michael@0: instance: { michael@0: isPrototypeOf: Object.prototype.isPrototypeOf, michael@0: hasOwnProperty: function (name) { michael@0: if (name === undefined) { michael@0: return false; michael@0: } michael@0: name = Multiname.getPublicQualifiedName(name); michael@0: if (Object.prototype.hasOwnProperty.call(this, name)) { michael@0: return true; michael@0: } michael@0: return Object.getPrototypeOf(this).hasOwnProperty(name); michael@0: }, michael@0: propertyIsEnumerable: function (name) { michael@0: if (name === undefined) { michael@0: return false; michael@0: } michael@0: name = Multiname.getPublicQualifiedName(name); michael@0: return Object.prototype.propertyIsEnumerable.call(this, name); michael@0: } michael@0: }, michael@0: static: { michael@0: _setPropertyIsEnumerable: function _setPropertyIsEnumerable(obj, name, isEnum) { michael@0: name = Multiname.getPublicQualifiedName(name); michael@0: var descriptor = Object.getOwnPropertyDescriptor(obj, name); michael@0: descriptor.enumerable = false; michael@0: Object.defineProperty(obj, name, descriptor); michael@0: } michael@0: } michael@0: }; michael@0: c.dynamicPrototype = c.traitsPrototype = Object.prototype; michael@0: c.setDefaultProperties(); michael@0: c.defaultValue = null; michael@0: c.coerce = function (value) { michael@0: return asCoerceObject(value); michael@0: }; michael@0: c.isInstanceOf = function (value) { michael@0: if (value === null) { michael@0: return false; michael@0: } michael@0: return true; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: if (value === null || value === undefined) { michael@0: return false; michael@0: } michael@0: return true; michael@0: }; michael@0: return c; michael@0: } michael@0: function ClassClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = Class; michael@0: c.debugName = 'Class'; michael@0: c.prototype.extendBuiltin.call(c, baseClass); michael@0: c.coerce = function (value) { michael@0: return value; michael@0: }; michael@0: c.isInstanceOf = function (value) { michael@0: return true; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: return value instanceof c.instanceConstructor; michael@0: }; michael@0: return c; michael@0: } michael@0: function BooleanClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Boolean', Boolean, C(Boolean)); michael@0: c.extendBuiltin(baseClass); michael@0: c.native = { michael@0: instance: { michael@0: toString: Boolean.prototype.toString, michael@0: valueOf: Boolean.prototype.valueOf michael@0: } michael@0: }; michael@0: c.coerce = Boolean; michael@0: c.isInstanceOf = function (value) { michael@0: return typeof value === 'boolean' || value instanceof Boolean; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: if (typeof value === 'boolean' || value instanceof Boolean) { michael@0: return true; michael@0: } michael@0: return false; michael@0: }; michael@0: return c; michael@0: } michael@0: function FunctionClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Function', Function, C(Function)); michael@0: c.extendBuiltin(baseClass); michael@0: c.native = { michael@0: instance: { michael@0: prototype: { michael@0: get: function () { michael@0: return this.prototype; michael@0: }, michael@0: set: function (p) { michael@0: this.prototype = p; michael@0: } michael@0: }, michael@0: length: { michael@0: get: function () { michael@0: if (this.hasOwnProperty(VM_LENGTH)) { michael@0: return this.asLength; michael@0: } michael@0: return this.length; michael@0: } michael@0: }, michael@0: call: Function.prototype.call, michael@0: apply: Function.prototype.apply michael@0: } michael@0: }; michael@0: c.coerce = function (value) { michael@0: return value; michael@0: }; michael@0: c.isInstanceOf = function (value) { michael@0: return typeof value === 'function'; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: return typeof value === 'function'; michael@0: }; michael@0: return c; michael@0: } michael@0: function MethodClosure($this, fn) { michael@0: var bound = bindSafely(fn, $this); michael@0: defineNonEnumerableProperty(this, 'call', bound.call.bind(bound)); michael@0: defineNonEnumerableProperty(this, 'apply', bound.apply.bind(bound)); michael@0: } michael@0: MethodClosure.prototype = { michael@0: toString: function () { michael@0: return 'function Function() {}'; michael@0: } michael@0: }; michael@0: function MethodClosureClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('MethodClosure', MethodClosure); michael@0: c.extendBuiltin(baseClass); michael@0: return c; michael@0: } michael@0: function StringClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('String', String, C(String)); michael@0: c.extendBuiltin(baseClass); michael@0: var Sp = String.prototype; michael@0: c.native = { michael@0: instance: { michael@0: length: { michael@0: get: function () { michael@0: return this.length; michael@0: } michael@0: }, michael@0: indexOf: Sp.indexOf, michael@0: lastIndexOf: Sp.lastIndexOf, michael@0: charAt: Sp.charAt, michael@0: charCodeAt: Sp.charCodeAt, michael@0: concat: Sp.concat, michael@0: localeCompare: Sp.localeCompare, michael@0: match: function (re) { michael@0: if (re === void 0 || re === null) { michael@0: return null; michael@0: } else { michael@0: if (re instanceof RegExp && re.global) { michael@0: var matches = [], m; michael@0: while (m = re.exec(this)) { michael@0: matches.push(m[0]); michael@0: } michael@0: return matches; michael@0: } michael@0: if (!(re instanceof RegExp) && !(typeof re === 'string')) { michael@0: re = String(re); michael@0: } michael@0: return this.match(re); michael@0: } michael@0: }, michael@0: replace: Sp.replace, michael@0: search: function (re) { michael@0: if (re === void 0) { michael@0: return -1; michael@0: } else { michael@0: return this.search(re); michael@0: } michael@0: }, michael@0: slice: Sp.slice, michael@0: split: Sp.split, michael@0: substr: Sp.substr, michael@0: substring: Sp.substring, michael@0: toLowerCase: Sp.toLowerCase, michael@0: toLocaleLowerCase: Sp.toLocaleLowerCase, michael@0: toUpperCase: function () { michael@0: var str = Sp.toUpperCase.apply(this); michael@0: var str = str.replace(/\u039C/g, String.fromCharCode(181)); michael@0: return str; michael@0: }, michael@0: toLocaleUpperCase: function () { michael@0: var str = Sp.toLocaleUpperCase.apply(this); michael@0: var str = str.replace(/\u039C/g, String.fromCharCode(181)); michael@0: return str; michael@0: }, michael@0: toString: Sp.toString, michael@0: valueOf: Sp.valueOf michael@0: }, michael@0: static: String michael@0: }; michael@0: c.isInstance = function (value) { michael@0: return value !== null && value !== undefined && typeof value.valueOf() === 'string'; michael@0: }; michael@0: c.coerce = function (value) { michael@0: if (value === null || value === undefined) { michael@0: return null; michael@0: } michael@0: return String(value); michael@0: }; michael@0: c.isInstanceOf = function (value) { michael@0: return Object(value) instanceof String; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: return Object(value) instanceof String; michael@0: }; michael@0: return c; michael@0: } michael@0: function VectorClass(domain, scope, instanceConstructor, baseClass) { michael@0: return createVectorClass(undefined, baseClass); michael@0: } michael@0: function ObjectVectorClass(domain, scope, instanceConstructor, baseClass) { michael@0: return createVectorClass(domain.getClass('Object'), baseClass); michael@0: } michael@0: function IntVectorClass(domain, scope, instanceConstructor, baseClass) { michael@0: return createVectorClass(domain.getClass('int'), baseClass); michael@0: } michael@0: function UIntVectorClass(domain, scope, instanceConstructor, baseClass) { michael@0: return createVectorClass(domain.getClass('uint'), baseClass); michael@0: } michael@0: function DoubleVectorClass(domain, scope, instanceConstructor, baseClass) { michael@0: return createVectorClass(domain.getClass('Number'), baseClass); michael@0: } michael@0: function createVectorClass(type, baseClass) { michael@0: var V; michael@0: if (type) { michael@0: var className = 'Vector$' + type.classInfo.instanceInfo.name.name; michael@0: switch (className) { michael@0: case 'Vector$int': michael@0: V = Int32Vector; michael@0: break; michael@0: case 'Vector$uint': michael@0: V = Uint32Vector; michael@0: break; michael@0: case 'Vector$Number': michael@0: V = Float64Vector; michael@0: break; michael@0: case 'Vector$Object': michael@0: V = GenericVector; michael@0: break; michael@0: default: michael@0: unexpected(); michael@0: break; michael@0: } michael@0: } else { michael@0: V = GenericVector.applyType(null); michael@0: } michael@0: var Vp = V.prototype; michael@0: var cls = new Class(className, V, C(V.callable)); michael@0: if (V === GenericVector) { michael@0: cls.applyType = function (type) { michael@0: return cls; michael@0: }; michael@0: } michael@0: cls.extendWrapper(baseClass, V); michael@0: cls.native = { michael@0: instance: { michael@0: fixed: { michael@0: get: function () { michael@0: return this._fixed; michael@0: }, michael@0: set: function (v) { michael@0: this._fixed = v; michael@0: } michael@0: }, michael@0: length: { michael@0: get: function () { michael@0: return this.length; michael@0: }, michael@0: set: function setLength(length) { michael@0: this.length = length; michael@0: } michael@0: }, michael@0: push: Vp.push, michael@0: pop: Vp.pop, michael@0: shift: Vp.shift, michael@0: unshift: Vp.unshift, michael@0: _reverse: Vp.reverse, michael@0: _filter: Vp.filter, michael@0: _map: Vp.map, michael@0: newThisType: function newThisType() { michael@0: return new cls.instanceConstructor(); michael@0: }, michael@0: _spliceHelper: function _spliceHelper(insertPoint, insertCount, deleteCount, args, offset) { michael@0: return this._spliceHelper(insertPoint, insertCount, deleteCount, args, offset); michael@0: } michael@0: }, michael@0: static: { michael@0: _some: function (o, callback, thisObject) { michael@0: return o.some(callback, thisObject); michael@0: }, michael@0: _every: function (o, callback, thisObject) { michael@0: return o.every(callback, thisObject); michael@0: }, michael@0: _forEach: function (o, callback, thisObject) { michael@0: return o.forEach(callback, thisObject); michael@0: }, michael@0: _sort: arraySort michael@0: } michael@0: }; michael@0: cls.vectorType = type; michael@0: cls.coerce = function (value) { michael@0: return value; michael@0: }; michael@0: cls.isInstanceOf = function (value) { michael@0: return true; michael@0: }; michael@0: cls.isInstance = function (value) { michael@0: if (value === null || typeof value !== 'object') { michael@0: return false; michael@0: } michael@0: if (!this.instanceConstructor.vectorType && value.class.vectorType) { michael@0: return true; michael@0: } michael@0: return this.instanceConstructor.prototype.isPrototypeOf(value); michael@0: }; michael@0: return cls; michael@0: } michael@0: function NumberClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Number', Number, C(Number)); michael@0: c.extendBuiltin(baseClass); michael@0: c.native = { michael@0: instance: Number.prototype michael@0: }; michael@0: c.defaultValue = Number(0); michael@0: c.isInstance = function (value) { michael@0: return value !== null && value !== undefined && typeof value.valueOf() === 'number'; michael@0: }; michael@0: c.coerce = Number; michael@0: c.isInstanceOf = function (value) { michael@0: return Object(value) instanceof Number; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: return Object(value) instanceof Number; michael@0: }; michael@0: return c; michael@0: } michael@0: function Int(x) { michael@0: return x | 0; michael@0: } michael@0: function boxedInt(x) { michael@0: return Object(x | 0); michael@0: } michael@0: function intClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('int', boxedInt, C(Int)); michael@0: c.extendBuiltin(baseClass); michael@0: c.defaultValue = 0; michael@0: c.coerce = Int; michael@0: c.isInstanceOf = function (value) { michael@0: return false; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: if (value instanceof Number) { michael@0: value = value.valueOf(); michael@0: } michael@0: return (value | 0) === value; michael@0: }; michael@0: return c; michael@0: } michael@0: function Uint(x) { michael@0: return x >>> 0; michael@0: } michael@0: function boxedUint(x) { michael@0: return Object(x >>> 0); michael@0: } michael@0: function uintClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('uint', boxedUint, C(Uint)); michael@0: c.extend(baseClass); michael@0: c.defaultValue = 0; michael@0: c.isInstanceOf = function (value) { michael@0: return false; michael@0: }; michael@0: c.isInstance = function (value) { michael@0: if (value instanceof Number) { michael@0: value = value.valueOf(); michael@0: } michael@0: return value >>> 0 === value; michael@0: }; michael@0: c.coerce = Uint; michael@0: return c; michael@0: } michael@0: function MathClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Math'); michael@0: c.native = { michael@0: static: Math michael@0: }; michael@0: return c; michael@0: } michael@0: function DateClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('Date', Date, C(Date)); michael@0: c.extendBuiltin(baseClass); michael@0: c.native = { michael@0: instance: Date.prototype, michael@0: static: Date michael@0: }; michael@0: return c; michael@0: } michael@0: function makeErrorClass(name) { michael@0: var ErrorDefinition = { michael@0: __glue__: { michael@0: script: { michael@0: instance: { michael@0: message: 'public message', michael@0: name: 'public name' michael@0: } michael@0: }, michael@0: native: { michael@0: instance: { michael@0: getStackTrace: function () { michael@0: somewhatImplemented('Error.getStackTrace()'); michael@0: return AVM2.getStackTrace(); michael@0: } michael@0: }, michael@0: static: { michael@0: getErrorMessage: getErrorMessage michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return function (runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class(name, instanceConstructor); michael@0: c.extend(baseClass); michael@0: if (name === 'Error') { michael@0: c.link(ErrorDefinition); michael@0: c.linkNatives(ErrorDefinition); michael@0: } michael@0: return c; michael@0: }; michael@0: } michael@0: function RegExpClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('RegExp', XRegExp, C(XRegExp)); michael@0: c.extendBuiltin(baseClass); michael@0: RegExpClass.exec = function exec() { michael@0: var result = this.exec.apply(this, arguments); michael@0: if (!result) { michael@0: return result; michael@0: } michael@0: var keys = Object.keys(result); michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var k = keys[i]; michael@0: if (!isNumeric(k)) { michael@0: if (result[k] === undefined) { michael@0: result[k] = ''; michael@0: } michael@0: } michael@0: } michael@0: publicizeProperties(result); michael@0: return result; michael@0: }; michael@0: RegExpClass.test = function test() { michael@0: return this.exec.apply(this, arguments) !== null; michael@0: }; michael@0: c.native = { michael@0: instance: { michael@0: global: { michael@0: get: function () { michael@0: return this.global; michael@0: } michael@0: }, michael@0: source: { michael@0: get: function () { michael@0: return this.source; michael@0: } michael@0: }, michael@0: ignoreCase: { michael@0: get: function () { michael@0: return this.ignoreCase; michael@0: } michael@0: }, michael@0: multiline: { michael@0: get: function () { michael@0: return this.multiline; michael@0: } michael@0: }, michael@0: lastIndex: { michael@0: get: function () { michael@0: return this.lastIndex; michael@0: }, michael@0: set: function (i) { michael@0: this.lastIndex = i; michael@0: } michael@0: }, michael@0: dotall: { michael@0: get: function () { michael@0: return this.dotall; michael@0: } michael@0: }, michael@0: extended: { michael@0: get: function () { michael@0: return this.extended; michael@0: } michael@0: }, michael@0: exec: RegExpClass.exec, michael@0: test: RegExpClass.test michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function NamespaceClass(runtime, scope, instanceConstructor, baseClass) { michael@0: NativeASNamespace = function NativeASNamespace(prefixValue, uriValue) { michael@0: if (uriValue === undefined) { michael@0: uriValue = prefixValue; michael@0: prefixValue = undefined; michael@0: } michael@0: var prefix, uri; michael@0: if (prefixValue === undefined) { michael@0: if (uriValue === undefined) { michael@0: prefix = ''; michael@0: uri = ''; michael@0: } else if (typeof uriValue === 'object') { michael@0: prefix = uriValue.prefix; michael@0: if (uriValue instanceof ASNamespace) { michael@0: uri = uriValue.uri; michael@0: } else if (uriValue instanceof QName) { michael@0: uri = uriValue.uri; michael@0: } michael@0: } else { michael@0: uri = uriValue + ''; michael@0: if (uri === '') { michael@0: prefix = ''; michael@0: } else { michael@0: prefix = undefined; michael@0: } michael@0: } michael@0: } else { michael@0: if (typeof uriValue === 'object' && uriValue instanceof QName && uriValue.uri !== null) { michael@0: uri = uriValue.uri; michael@0: } else { michael@0: uri = uriValue + ''; michael@0: } michael@0: if (uri === '') { michael@0: if (prefixValue === undefined || prefixValue + '' === '') { michael@0: prefix = ''; michael@0: } else { michael@0: throw 'type error'; michael@0: } michael@0: } else if (prefixValue === undefined || prefixValue === '') { michael@0: prefix = undefined; michael@0: } else if (false && !isXMLName(prefixValue)) { michael@0: prefix = undefined; michael@0: } else { michael@0: prefix = prefixValue + ''; michael@0: } michael@0: } michael@0: return ASNamespace.createNamespace(uri, prefix); michael@0: }; michael@0: var c = new Class('Namespace', NativeASNamespace, C(NativeASNamespace)); michael@0: c.extendNative(baseClass, ASNamespace); michael@0: var Np = ASNamespace.prototype; michael@0: c.native = { michael@0: instance: { michael@0: prefix: { michael@0: get: Np.getPrefix michael@0: }, michael@0: uri: { michael@0: get: Np.getURI michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function JSONClass(runtime, scope, instanceConstructor, baseClass) { michael@0: function transformJSValueToAS(value) { michael@0: if (typeof value !== 'object') { michael@0: return value; michael@0: } michael@0: var keys = Object.keys(value); michael@0: var result = value instanceof Array ? [] : {}; michael@0: for (var i = 0; i < keys.length; i++) { michael@0: result.asSetPublicProperty(keys[i], transformJSValueToAS(value[keys[i]])); michael@0: } michael@0: return result; michael@0: } michael@0: function transformASValueToJS(value) { michael@0: if (typeof value !== 'object') { michael@0: return value; michael@0: } michael@0: var keys = Object.keys(value); michael@0: var result = value instanceof Array ? [] : {}; michael@0: for (var i = 0; i < keys.length; i++) { michael@0: var key = keys[i]; michael@0: var jsKey = key; michael@0: if (!isNumeric(key)) { michael@0: jsKey = Multiname.getNameFromPublicQualifiedName(key); michael@0: } michael@0: result[jsKey] = transformASValueToJS(value[key]); michael@0: } michael@0: return result; michael@0: } michael@0: function ASJSON() { michael@0: } michael@0: var c = new Class('JSON', ASJSON, C(ASJSON)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: static: { michael@0: parseCore: function parseCore(text) { michael@0: return transformJSValueToAS(JSON.parse(text)); michael@0: }, michael@0: stringifySpecializedToString: function stringifySpecializedToString(value, replacerArray, replacerFunction, gap) { michael@0: return JSON.stringify(transformASValueToJS(value), replacerFunction, gap); michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function CapabilitiesClass(runtime, scope, instanceConstructor, baseClass) { michael@0: function Capabilities() { michael@0: } michael@0: var c = new Class('Capabilities', Capabilities, C(Capabilities)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: static: { michael@0: playerType: { michael@0: get: function () { michael@0: return 'AVMPlus'; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function FileClass(runtime, scope, instanceConstructor, baseClass) { michael@0: function File() { michael@0: } michael@0: var c = new Class('File', File, C(File)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: static: { michael@0: exists: function (filename) { michael@0: notImplemented('File.exists'); michael@0: return false; michael@0: }, michael@0: read: function (filename) { michael@0: return snarf(filename); michael@0: }, michael@0: write: function (filename, data) { michael@0: notImplemented('File.write'); michael@0: return true; michael@0: }, michael@0: readByteArray: function (filename) { michael@0: var ByteArrayClass = AVM2.currentDomain().getClass('flash.utils.ByteArray'); michael@0: var data = ByteArrayClass.createInstance(); michael@0: data.writeRawBytes(snarf(filename, 'binary')); michael@0: return data; michael@0: }, michael@0: writeByteArray: function (filename, bytes) { michael@0: write('bin/' + filename, bytes.getBytes()); michael@0: return true; michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function ShumwayClass(runtime, scope, instanceConstructor, baseClass) { michael@0: function Shumway() { michael@0: } michael@0: var c = new Class('Shumway', Shumway, C(Shumway)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: static: { michael@0: info: function (x) { michael@0: console.info(x); michael@0: }, michael@0: json: function (x) { michael@0: return JSON.stringify(x); michael@0: }, michael@0: eval: function (x) { michael@0: return eval(x); michael@0: }, michael@0: debugger: function (x) { michael@0: debugger; michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function constant(x) { michael@0: return function () { michael@0: return x; michael@0: }; michael@0: } michael@0: function ByteArrayClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var BA = function () { michael@0: ByteArray.call(this); michael@0: }; michael@0: var BAp = BA.prototype = Object.create(ByteArray.prototype); michael@0: var c = new Class('ByteArray', BA, C(BA)); michael@0: c.extendBuiltin(baseClass); michael@0: BAp.asGetNumericProperty = function (i) { michael@0: if (i >= this.length) { michael@0: return undefined; michael@0: } michael@0: return this.uint8v[i]; michael@0: }; michael@0: BAp.asSetNumericProperty = function (i, v) { michael@0: var len = i + 1; michael@0: this.ensureCapacity(len); michael@0: this.uint8v[i] = v; michael@0: if (len > this.length) { michael@0: this.length = len; michael@0: } michael@0: }; michael@0: BAp.readUTF = function readUTF() { michael@0: return this.readUTFBytes(this.readShort()); michael@0: }; michael@0: BAp.readUTFBytes = function readUTFBytes(length) { michael@0: var pos = this.position; michael@0: if (pos + length > this.length) { michael@0: throwEOFError(); michael@0: } michael@0: this.position += length; michael@0: return utf8encode(new Int8Array(this.a, pos, length)); michael@0: }; michael@0: BAp.writeUTF = function writeUTF(str) { michael@0: var bytes = utf8decode(str); michael@0: this.writeShort(bytes.length); michael@0: this.writeRawBytes(bytes); michael@0: }; michael@0: BAp.writeUTFBytes = function writeUTFBytes(str) { michael@0: var bytes = utf8decode(str); michael@0: this.writeRawBytes(bytes); michael@0: }; michael@0: BAp.toString = function toString() { michael@0: return utf8encode(new Int8Array(this.a, 0, this.length)); michael@0: }; michael@0: c.native = { michael@0: instance: { michael@0: length: { michael@0: get: function () { michael@0: return this.length; michael@0: }, michael@0: set: function setLength(length) { michael@0: var cap = this.a.byteLength; michael@0: if (length > cap) { michael@0: this.ensureCapacity(length); michael@0: } michael@0: this.length = length; michael@0: this.position = clamp(this.position, 0, this.length); michael@0: } michael@0: }, michael@0: bytesAvailable: { michael@0: get: function () { michael@0: return this.length - this.position; michael@0: } michael@0: }, michael@0: position: { michael@0: get: function () { michael@0: return this.position; michael@0: }, michael@0: set: function (p) { michael@0: this.position = p; michael@0: } michael@0: }, michael@0: endian: { michael@0: get: function () { michael@0: return this.le ? 'littleEndian' : 'bigEndian'; michael@0: }, michael@0: set: function (e) { michael@0: this.le = e === 'littleEndian'; michael@0: } michael@0: }, michael@0: objectEncoding: { michael@0: get: function () { michael@0: return this.objectEncoding; michael@0: }, michael@0: set: function (v) { michael@0: this.objectEncoding = v; michael@0: } michael@0: }, michael@0: writeBytes: BAp.writeBytes, michael@0: writeBoolean: BAp.writeBoolean, michael@0: writeByte: BAp.writeByte, michael@0: writeShort: BAp.writeShort, michael@0: writeInt: BAp.writeInt, michael@0: writeUnsignedInt: BAp.writeUnsignedInt, michael@0: writeFloat: BAp.writeFloat, michael@0: writeDouble: BAp.writeDouble, michael@0: writeMultiByte: BAp.writeMultiByte, michael@0: writeObject: function writeObject(v) { michael@0: return AMFUtils.encodings[this.objectEncoding].write(this, v); michael@0: }, michael@0: writeUTF: BAp.writeUTF, michael@0: writeUTFBytes: BAp.writeUTFBytes, michael@0: readBoolean: BAp.readBoolean, michael@0: readByte: BAp.readByte, michael@0: readBytes: BAp.readBytes, michael@0: readUnsignedByte: BAp.readUnsignedByte, michael@0: readShort: BAp.readShort, michael@0: readUnsignedShort: BAp.readUnsignedShort, michael@0: readInt: BAp.readInt, michael@0: readUnsignedInt: BAp.readUnsignedInt, michael@0: readFloat: BAp.readFloat, michael@0: readDouble: BAp.readDouble, michael@0: readMultiByte: BAp.readMultiByte, michael@0: readObject: function readObject() { michael@0: return AMFUtils.encodings[this.objectEncoding].read(this); michael@0: }, michael@0: readUTF: BAp.readUTF, michael@0: readUTFBytes: BAp.readUTFBytes, michael@0: toString: BAp.toString, michael@0: clear: BAp.clear, michael@0: _compress: BAp.compress, michael@0: _uncompress: BAp.uncompress michael@0: }, michael@0: static: { michael@0: defaultObjectEncoding: { michael@0: get: function () { michael@0: return ByteArray.DEFAULT_OBJECT_ENCODING; michael@0: }, michael@0: set: function (e) { michael@0: ByteArray.DEFAULT_OBJECT_ENCODING = e; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function DomainClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('File', instanceConstructor, C(instanceConstructor)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: instance: { michael@0: init: function (base) { michael@0: this.base = base; michael@0: this.nativeObject = new ApplicationDomain(AVM2.instance, base ? base.nativeObject : null); michael@0: }, michael@0: loadBytes: function (byteArray, swfVersion) { michael@0: this.nativeObject.executeAbc(new AbcFile(byteArray.readRawBytes())); michael@0: }, michael@0: getClass: function (className) { michael@0: return this.nativeObject.getClass(className); michael@0: } michael@0: }, michael@0: static: { michael@0: currentDomain: { michael@0: get: function () { michael@0: var domain = Object.create(instanceConstructor.prototype); michael@0: domain.nativeObject = AVM2.currentDomain(); michael@0: return domain; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function SystemClass(runtime, scope, instanceConstructor, baseClass) { michael@0: var c = new Class('System', instanceConstructor, C(instanceConstructor)); michael@0: c.extend(baseClass); michael@0: c.native = { michael@0: static: { michael@0: swfVersion: { michael@0: get: function () { michael@0: return 19; michael@0: } michael@0: }, michael@0: apiVersion: { michael@0: get: function () { michael@0: return 26; michael@0: } michael@0: }, michael@0: getArgv: function () { michael@0: return []; michael@0: }, michael@0: getRunmode: function () { michael@0: return 'mixed'; michael@0: } michael@0: } michael@0: }; michael@0: return c; michael@0: } michael@0: function bugzilla(n) { michael@0: switch (n) { michael@0: case 574600: michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: return { michael@0: print: constant(print), michael@0: notImplemented: constant(notImplemented), michael@0: debugBreak: constant(debugBreak), michael@0: bugzilla: constant(bugzilla), michael@0: decodeURI: constant(decodeURI), michael@0: decodeURIComponent: constant(decodeURIComponent), michael@0: encodeURI: constant(encodeURI), michael@0: encodeURIComponent: constant(encodeURIComponent), michael@0: isNaN: constant(isNaN), michael@0: isFinite: constant(isFinite), michael@0: parseInt: constant(parseInt), michael@0: parseFloat: constant(parseFloat), michael@0: escape: constant(escape), michael@0: unescape: constant(unescape), michael@0: isXMLName: constant(typeof isXMLName !== 'undefined' ? isXMLName : function () { michael@0: notImplemented('Chrome doesn\'t support isXMLName.'); michael@0: }), michael@0: Function: Function, michael@0: String: String, michael@0: Array: Array, michael@0: Number: Number, michael@0: Boolean: Boolean, michael@0: Math: Math, michael@0: Date: Date, michael@0: RegExp: RegExp, michael@0: Object: Object, michael@0: ObjectClass: ObjectClass, michael@0: Class: ClassClass, michael@0: NamespaceClass: NamespaceClass, michael@0: FunctionClass: FunctionClass, michael@0: MethodClosureClass: MethodClosureClass, michael@0: BooleanClass: BooleanClass, michael@0: StringClass: StringClass, michael@0: NumberClass: NumberClass, michael@0: intClass: intClass, michael@0: uintClass: uintClass, michael@0: ArrayClass: ArrayClass, michael@0: VectorClass: VectorClass, michael@0: ObjectVectorClass: ObjectVectorClass, michael@0: IntVectorClass: IntVectorClass, michael@0: UIntVectorClass: UIntVectorClass, michael@0: DoubleVectorClass: DoubleVectorClass, michael@0: ByteArrayClass: ByteArrayClass, michael@0: ProxyClass: ProxyClass, michael@0: ErrorClass: makeErrorClass('Error'), michael@0: DefinitionErrorClass: makeErrorClass('DefinitionError'), michael@0: EvalErrorClass: makeErrorClass('EvalError'), michael@0: RangeErrorClass: makeErrorClass('RangeError'), michael@0: ReferenceErrorClass: makeErrorClass('ReferenceError'), michael@0: SecurityErrorClass: makeErrorClass('SecurityError'), michael@0: SyntaxErrorClass: makeErrorClass('SyntaxError'), michael@0: TypeErrorClass: makeErrorClass('TypeError'), michael@0: URIErrorClass: makeErrorClass('URIError'), michael@0: VerifyErrorClass: makeErrorClass('VerifyError'), michael@0: UninitializedErrorClass: makeErrorClass('UninitializedError'), michael@0: ArgumentErrorClass: makeErrorClass('ArgumentError'), michael@0: DateClass: DateClass, michael@0: MathClass: MathClass, michael@0: RegExpClass: RegExpClass, michael@0: DictionaryClass: DictionaryClass, michael@0: XMLClass: XMLClass, michael@0: XMLListClass: XMLListClass, michael@0: QNameClass: QNameClass, michael@0: JSONClass: JSONClass, michael@0: ShumwayClass: ShumwayClass, michael@0: CapabilitiesClass: CapabilitiesClass, michael@0: FileClass: FileClass, michael@0: DomainClass: DomainClass, michael@0: SystemClass: SystemClass, michael@0: getQualifiedClassName: constant(function (value) { michael@0: if (value === null) { michael@0: return 'null'; michael@0: } else if (value === undefined) { michael@0: return 'void'; michael@0: } michael@0: switch (typeof value) { michael@0: case 'number': michael@0: if ((value | 0) === value) { michael@0: return 'int'; michael@0: } michael@0: return 'Number'; michael@0: case 'string': michael@0: return 'String'; michael@0: case 'boolean': michael@0: return 'Boolean'; michael@0: case 'object': michael@0: if (value instanceof Date) { michael@0: return 'Date'; michael@0: } michael@0: var cls; michael@0: if (value instanceof Class) { michael@0: cls = value; michael@0: } else if (value.class) { michael@0: cls = value.class; michael@0: } else if (value.classInfo) { michael@0: cls = value; michael@0: } michael@0: if (cls) { michael@0: var name = cls.classInfo.instanceInfo.name; michael@0: var uri = name.namespaces[0].uri; michael@0: if (uri) { michael@0: return uri + '::' + name.name; michael@0: } michael@0: return name.name; michael@0: } michael@0: break; michael@0: } michael@0: return notImplemented(value + ' (' + typeof value + ')'); michael@0: }), michael@0: getQualifiedSuperclassName: constant(function (value) { michael@0: switch (typeof value) { michael@0: case 'number': michael@0: case 'string': michael@0: case 'boolean': michael@0: return 'Object'; michael@0: case 'function': michael@0: return 'Function'; michael@0: case 'object': michael@0: if (value instanceof Date) { michael@0: return 'Object'; michael@0: } michael@0: var cls; michael@0: if (value.class) { michael@0: cls = value.class; michael@0: } else if (value.classInfo) { michael@0: cls = value; michael@0: } michael@0: if (cls && cls.baseClass) { michael@0: var name = cls.baseClass.classInfo.instanceInfo.name; michael@0: var uri = name.namespaces[0].uri; michael@0: if (uri) { michael@0: return uri + '::' + name.name; michael@0: } michael@0: return name.name; michael@0: } michael@0: return 'Object'; michael@0: } michael@0: return notImplemented(value + ' (superOf ' + typeof value + ')'); michael@0: }), michael@0: getDefinitionByName: constant(function (name) { michael@0: var simpleName = String(name).replace('::', '.'); michael@0: return AVM2.currentDomain().getClass(simpleName); michael@0: }), michael@0: describeTypeJSON: constant(describeTypeJSON), michael@0: original: jsGlobal[VM_NATIVE_BUILTIN_ORIGINALS] michael@0: }; michael@0: function describeTypeJSON(o, flags) { michael@0: var Flags = { michael@0: HIDE_NSURI_METHODS: 1, michael@0: INCLUDE_BASES: 2, michael@0: INCLUDE_INTERFACES: 4, michael@0: INCLUDE_VARIABLES: 8, michael@0: INCLUDE_ACCESSORS: 16, michael@0: INCLUDE_METHODS: 32, michael@0: INCLUDE_METADATA: 64, michael@0: INCLUDE_CONSTRUCTOR: 128, michael@0: INCLUDE_TRAITS: 256, michael@0: USE_ITRAITS: 512, michael@0: HIDE_OBJECT: 1024 michael@0: }; michael@0: var declaredByKey = publicName('declaredBy'); michael@0: var metadataKey = publicName('metadata'); michael@0: var accessKey = publicName('access'); michael@0: var uriKey = publicName('uri'); michael@0: var nameKey = publicName('name'); michael@0: var typeKey = publicName('type'); michael@0: var returnTypeKey = publicName('returnType'); michael@0: var valueKey = publicName('value'); michael@0: var keyKey = publicName('key'); michael@0: var parametersKey = publicName('parameters'); michael@0: var optionalKey = publicName('optional'); michael@0: var cls = o.classInfo ? o : Object.getPrototypeOf(o).class; michael@0: true; michael@0: var info = cls.classInfo; michael@0: var description = {}; michael@0: description[nameKey] = unmangledQualifiedName(info.instanceInfo.name); michael@0: description[publicName('isDynamic')] = cls === o ? true : !(info.instanceInfo.flags & CONSTANT_ClassSealed); michael@0: description[publicName('isStatic')] = cls === o; michael@0: description[publicName('isFinal')] = cls === o ? true : !(info.instanceInfo.flags & CONSTANT_ClassFinal); michael@0: if (flags & Flags.INCLUDE_TRAITS) { michael@0: description[publicName('traits')] = addTraits(cls, flags); michael@0: } michael@0: var metadata = null; michael@0: if (info.metadata) { michael@0: metadata = Object.keys(info.metadata).map(function (key) { michael@0: return describeMetadata(info.metadata[key]); michael@0: }); michael@0: } michael@0: description[metadataKey] = metadata; michael@0: return description; michael@0: function publicName(str) { michael@0: return Multiname.getPublicQualifiedName(str); michael@0: } michael@0: function unmangledQualifiedName(mn) { michael@0: var name = mn.name; michael@0: var namespace = mn.namespaces[0]; michael@0: if (namespace && namespace.uri) { michael@0: return namespace.uri + '::' + name; michael@0: } michael@0: return name; michael@0: } michael@0: function describeMetadata(metadata) { michael@0: var result = {}; michael@0: result[nameKey] = metadata.name; michael@0: result[valueKey] = metadata.value.map(function (value) { michael@0: var val = {}; michael@0: val[keyKey] = value.key; michael@0: val[valueKey] = value.value; michael@0: return value; michael@0: }); michael@0: return result; michael@0: } michael@0: function addTraits(cls, flags) { michael@0: var includedMembers = [ michael@0: flags & Flags.INCLUDE_VARIABLES, michael@0: flags & Flags.INCLUDE_METHODS, michael@0: flags & Flags.INCLUDE_ACCESSORS, michael@0: flags & Flags.INCLUDE_ACCESSORS michael@0: ]; michael@0: var includeBases = flags & Flags.INCLUDE_BASES; michael@0: var includeMetadata = flags & Flags.INCLUDE_METADATA; michael@0: var obj = {}; michael@0: var basesVal = obj[publicName('bases')] = includeBases ? [] : null; michael@0: if (flags & Flags.INCLUDE_INTERFACES) { michael@0: var interfacesVal = obj[publicName('interfaces')] = []; michael@0: if (flags & Flags.USE_ITRAITS) { michael@0: for (var key in cls.implementedInterfaces) { michael@0: var ifaceName = cls.implementedInterfaces[key].name; michael@0: interfacesVal.push(unmangledQualifiedName(ifaceName)); michael@0: } michael@0: } michael@0: } else { michael@0: obj[publicName('interfaces')] = null; michael@0: } michael@0: var variablesVal = obj[publicName('variables')] = flags & Flags.INCLUDE_VARIABLES ? [] : null; michael@0: var accessorsVal = obj[publicName('accessors')] = flags & Flags.INCLUDE_ACCESSORS ? [] : null; michael@0: var methodsVal = obj[publicName('methods')] = flags & Flags.INCLUDE_METHODS ? [] : null; michael@0: var encounteredAccessors = {}; michael@0: var addBase = false; michael@0: while (cls) { michael@0: var className = unmangledQualifiedName(cls.classInfo.instanceInfo.name); michael@0: if (includeBases && addBase) { michael@0: basesVal.push(className); michael@0: } else { michael@0: addBase = true; michael@0: } michael@0: if (flags & Flags.USE_ITRAITS) { michael@0: describeTraits(cls.classInfo.instanceInfo.traits); michael@0: } else { michael@0: describeTraits(cls.classInfo.traits); michael@0: } michael@0: cls = cls.baseClass; michael@0: } michael@0: function describeTraits(traits) { michael@0: true; michael@0: for (var i = 0; traits && i < traits.length; i++) { michael@0: var t = traits[i]; michael@0: if (!includedMembers[t.kind] || !t.name.getNamespace().isPublic() && !t.name.uri) { michael@0: continue; michael@0: } michael@0: var name = unmangledQualifiedName(t.name); michael@0: if (encounteredAccessors[name]) { michael@0: var val = encounteredAccessors[name]; michael@0: val[accessKey] = 'readwrite'; michael@0: if (t.kind === TRAIT_Getter) { michael@0: val[typeKey] = unmangledQualifiedName(t.methodInfo.returnType); michael@0: } michael@0: continue; michael@0: } michael@0: var val = {}; michael@0: if (includeMetadata && t.metadata) { michael@0: var metadataVal = val[metadataKey] = []; michael@0: for (var key in t.metadata) { michael@0: metadataVal.push(describeMetadata(t.metadata[key])); michael@0: } michael@0: } else { michael@0: val[metadataKey] = null; michael@0: } michael@0: val[declaredByKey] = className; michael@0: val[uriKey] = t.name.uri === undefined ? null : t.name.uri; michael@0: val[nameKey] = name; michael@0: if (!t.typeName && !(t.methodInfo && t.methodInfo.returnType)) { michael@0: continue; michael@0: } michael@0: val[t.kind === TRAIT_Method ? returnTypeKey : typeKey] = unmangledQualifiedName(t.kind === TRAIT_Slot ? t.typeName : t.methodInfo.returnType); michael@0: switch (t.kind) { michael@0: case TRAIT_Slot: michael@0: val[accessKey] = 'readwrite'; michael@0: variablesVal.push(val); michael@0: break; michael@0: case TRAIT_Method: michael@0: var parametersVal = val[parametersKey] = []; michael@0: var parameters = t.methodInfo.parameters; michael@0: for (var j = 0; j < parameters.length; j++) { michael@0: var param = parameters[j]; michael@0: var paramVal = {}; michael@0: paramVal[typeKey] = param.type ? unmangledQualifiedName(param.type) : '*'; michael@0: paramVal[optionalKey] = 'value' in param; michael@0: parametersVal.push(paramVal); michael@0: } michael@0: methodsVal.push(val); michael@0: break; michael@0: case TRAIT_Getter: michael@0: case TRAIT_Setter: michael@0: val[accessKey] = t.kind === TRAIT_Getter ? 'read' : 'write'; michael@0: accessorsVal.push(val); michael@0: encounteredAccessors[name] = val; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: return obj; michael@0: } michael@0: } michael@0: }(); michael@0: function getNative(path) { michael@0: var chain = path.split('.'); michael@0: var v = natives; michael@0: for (var i = 0, j = chain.length; i < j; i++) { michael@0: v = v && v[chain[i]]; michael@0: } michael@0: true; michael@0: return v; michael@0: } michael@0: var disassemblerOptions = systemOptions.register(new OptionSet('Disassembler Options')); michael@0: var filter = disassemblerOptions.register(new Option('f', 'filter', 'string', 'SpciMsmNtu', '[S]ource, constant[p]ool, [c]lasses, [i]nstances, [M]etadata, [s]cripts, [m]ethods, multi[N]ames, S[t]atistics, [u]tf')); michael@0: function traceArray(writer, name, array, abc) { michael@0: if (array.length === 0) { michael@0: return; michael@0: } michael@0: writer.enter(name + ' {'); michael@0: array.forEach(function (a, idx) { michael@0: a.trace(writer, abc); michael@0: }); michael@0: writer.leave('}'); michael@0: } michael@0: AbcFile.prototype.trace = function trace(writer) { michael@0: if (filter.value.indexOf('p') >= 0) { michael@0: this.constantPool.trace(writer); michael@0: } michael@0: if (filter.value.indexOf('N') >= 0) { michael@0: this.constantPool.traceMultinamesOnly(writer); michael@0: } michael@0: if (filter.value.indexOf('c') >= 0) { michael@0: traceArray(writer, 'classes', this.classes); michael@0: } michael@0: if (filter.value.indexOf('i') >= 0) { michael@0: traceArray(writer, 'instances', this.instances); michael@0: } michael@0: if (filter.value.indexOf('M') >= 0) { michael@0: traceArray(writer, 'metadata', this.metadata); michael@0: } michael@0: if (filter.value.indexOf('s') >= 0) { michael@0: traceArray(writer, 'scripts', this.scripts); michael@0: } michael@0: if (filter.value.indexOf('m') >= 0) { michael@0: traceArray(writer, 'methods', this.methods, this); michael@0: } michael@0: if (filter.value.indexOf('S') >= 0) { michael@0: traceSource(writer, this); michael@0: } michael@0: if (filter.value.indexOf('t') >= 0) { michael@0: traceStatistics(writer, this); michael@0: } michael@0: if (filter.value.indexOf('u') >= 0) { michael@0: print(JSON.stringify({ michael@0: strings: this.constantPool.strings, michael@0: positionAfterUTFStrings: this.constantPool.positionAfterUTFStrings michael@0: }, null, 2)); michael@0: } michael@0: }; michael@0: ConstantPool.prototype.trace = function (writer) { michael@0: writer.enter('constantPool {'); michael@0: for (var key in this) { michael@0: if (key === 'namespaces') { michael@0: writer.enter('namespaces {'); michael@0: this.namespaces.forEach(function (ns, i) { michael@0: writer.writeLn(('' + i).padRight(' ', 3) + (ns ? ns.toString() : '*')); michael@0: }); michael@0: writer.leave('}'); michael@0: } else if (this[key] instanceof Array) { michael@0: writer.enter(key + ' ' + this[key].length + ' {'); michael@0: writer.writeArray(this[key]); michael@0: writer.leave('}'); michael@0: } michael@0: } michael@0: writer.leave('}'); michael@0: }; michael@0: ConstantPool.prototype.traceMultinamesOnly = function (writer) { michael@0: writer.writeArray(this.multinames, null, true); michael@0: }; michael@0: ClassInfo.prototype.trace = function (writer) { michael@0: writer.enter('class ' + this + ' {'); michael@0: traceArray(writer, 'traits', this.traits); michael@0: writer.leave('}'); michael@0: }; michael@0: MetaDataInfo.prototype.trace = function (writer) { michael@0: writer.enter(this + ' {'); michael@0: this.value.forEach(function (item) { michael@0: writer.writeLn((item.key ? item.key + ': ' : '') + '"' + item.value + '"'); michael@0: }); michael@0: writer.leave('}'); michael@0: }; michael@0: InstanceInfo.prototype.trace = function (writer) { michael@0: writer.enter('instance ' + this + ' {'); michael@0: traceArray(writer, 'traits', this.traits); michael@0: writer.leave('}'); michael@0: }; michael@0: ScriptInfo.prototype.trace = function (writer) { michael@0: writer.enter('script ' + this + ' {'); michael@0: traceArray(writer, 'traits', this.traits); michael@0: writer.leave('}'); michael@0: }; michael@0: Trait.prototype.trace = function (writer) { michael@0: if (this.metadata) { michael@0: for (var key in this.metadata) { michael@0: if (this.metadata.hasOwnProperty(key)) { michael@0: this.metadata[key].trace(writer); michael@0: } michael@0: } michael@0: } michael@0: writer.writeLn(this); michael@0: }; michael@0: function traceAbc(writer, abc) { michael@0: abc.trace(writer); michael@0: } michael@0: function traceOperand(operand, abc, code) { michael@0: var value = 0; michael@0: switch (operand.size) { michael@0: case 's08': michael@0: value = code.readS8(); michael@0: break; michael@0: case 'u08': michael@0: value = code.readU8(); michael@0: break; michael@0: case 's16': michael@0: value = code.readS16(); michael@0: break; michael@0: case 's24': michael@0: value = code.readS24(); michael@0: break; michael@0: case 'u30': michael@0: value = code.readU30(); michael@0: break; michael@0: case 'u32': michael@0: value = code.readU32(); michael@0: break; michael@0: default: michael@0: true; michael@0: break; michael@0: } michael@0: var description = ''; michael@0: switch (operand.type) { michael@0: case '': michael@0: break; michael@0: case 'I': michael@0: description = abc.constantPool.ints[value]; michael@0: break; michael@0: case 'U': michael@0: description = abc.constantPool.uints[value]; michael@0: break; michael@0: case 'D': michael@0: description = abc.constantPool.doubles[value]; michael@0: break; michael@0: case 'S': michael@0: description = abc.constantPool.strings[value]; michael@0: break; michael@0: case 'N': michael@0: description = abc.constantPool.namespaces[value]; michael@0: break; michael@0: case 'CI': michael@0: description = abc.classes[value]; michael@0: break; michael@0: case 'M': michael@0: return abc.constantPool.multinames[value]; michael@0: default: michael@0: description = '?'; michael@0: break; michael@0: } michael@0: return operand.name + ':' + value + (description === '' ? '' : ' (' + description + ')'); michael@0: } michael@0: function traceOperands(opcode, abc, code, rewind) { michael@0: rewind = rewind || false; michael@0: var old = code.position; michael@0: var str = ''; michael@0: if (opcode.operands === null) { michael@0: str = 'null'; michael@0: } else { michael@0: opcode.operands.forEach(function (op, i) { michael@0: str += traceOperand(op, abc, code); michael@0: if (i < opcode.operands.length - 1) { michael@0: str += ', '; michael@0: } michael@0: }); michael@0: } michael@0: if (rewind) { michael@0: code.seek(old); michael@0: } michael@0: return str; michael@0: } michael@0: MethodInfo.prototype.trace = function trace(writer) { michael@0: var abc = this.abc; michael@0: writer.enter('method' + (this.name ? ' ' + this.name : '') + ' {'); michael@0: writer.writeLn('flags: ' + getFlags(this.flags, 'NEED_ARGUMENTS|NEED_ACTIVATION|NEED_REST|HAS_OPTIONAL||NATIVE|SET_DXN|HAS_PARAM_NAMES'.split('|'))); michael@0: writer.writeLn('parameters: ' + this.parameters.map(function (x) { michael@0: return (x.type ? Multiname.getQualifiedName(x.type) + '::' : '') + x.name; michael@0: })); michael@0: if (!this.code) { michael@0: writer.leave('}'); michael@0: return; michael@0: } michael@0: var code = new AbcStream(this.code); michael@0: traceArray(writer, 'traits', this.traits); michael@0: writer.enter('code {'); michael@0: while (code.remaining() > 0) { michael@0: var bc = code.readU8(); michael@0: var opcode = opcodeTable[bc]; michael@0: var str, defaultOffset, offset, count; michael@0: str = ('' + code.position).padRight(' ', 6); michael@0: switch (bc) { michael@0: case OP_lookupswitch: michael@0: str += opcode.name + ': defaultOffset: ' + code.readS24(); michael@0: var caseCount = code.readU30(); michael@0: str += ', caseCount: ' + caseCount; michael@0: for (var i = 0; i < caseCount + 1; i++) { michael@0: str += ' offset: ' + code.readS24(); michael@0: } michael@0: writer.writeLn(str); michael@0: break; michael@0: default: michael@0: if (opcode) { michael@0: str += opcode.name.padRight(' ', 20); michael@0: if (!opcode.operands) { michael@0: true; michael@0: } else { michael@0: if (opcode.operands.length > 0) { michael@0: str += traceOperands(opcode, abc, code); michael@0: } michael@0: writer.writeLn(str); michael@0: } michael@0: } else { michael@0: true; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: writer.leave('}'); michael@0: writer.leave('}'); michael@0: }; michael@0: var SourceTracer = function () { michael@0: function literal(value) { michael@0: if (value === undefined) { michael@0: return 'undefined'; michael@0: } else if (value === null) { michael@0: return 'null'; michael@0: } else if (typeof value === 'string') { michael@0: return '"' + value + '"'; michael@0: } else { michael@0: return String(value); michael@0: } michael@0: } michael@0: function getSignature(mi, excludeTypesAndDefaultValues) { michael@0: return mi.parameters.map(function (x) { michael@0: var str = x.name; michael@0: if (!excludeTypesAndDefaultValues) { michael@0: if (x.type) { michael@0: str += ':' + x.type.getName(); michael@0: } michael@0: if (x.value !== undefined) { michael@0: str += ' = ' + literal(x.value); michael@0: } michael@0: } michael@0: return str; michael@0: }).join(', '); michael@0: } michael@0: function SourceTracer(writer) { michael@0: this.writer = writer; michael@0: } michael@0: SourceTracer.prototype = { michael@0: traceTraits: function traceTraits(traits, isStatic, inInterfaceNamespace) { michael@0: var writer = this.writer; michael@0: var tracer = this; michael@0: traits.forEach(function (trait) { michael@0: var str; michael@0: var accessModifier = Multiname.getAccessModifier(trait.name); michael@0: var namespaceName = trait.name.namespaces[0].uri; michael@0: if (namespaceName) { michael@0: if (namespaceName === 'http://adobe.com/AS3/2006/builtin') { michael@0: namespaceName = 'AS3'; michael@0: } michael@0: if (accessModifier === 'public') { michael@0: str = inInterfaceNamespace === namespaceName ? '' : namespaceName; michael@0: } else { michael@0: str = accessModifier; michael@0: } michael@0: } else { michael@0: str = accessModifier; michael@0: } michael@0: if (isStatic) { michael@0: str += ' static'; michael@0: } michael@0: if (trait.isSlot() || trait.isConst()) { michael@0: tracer.traceMetadata(trait.metadata); michael@0: if (trait.isConst()) { michael@0: str += ' const'; michael@0: } else { michael@0: str += ' var'; michael@0: } michael@0: str += ' ' + trait.name.getName(); michael@0: if (trait.typeName) { michael@0: str += ':' + trait.typeName.getName(); michael@0: } michael@0: if (trait.value) { michael@0: str += ' = ' + literal(trait.value); michael@0: } michael@0: writer.writeLn(str + ';'); michael@0: } else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: tracer.traceMetadata(trait.metadata); michael@0: var mi = trait.methodInfo; michael@0: if (trait.attributes & ATTR_Override) { michael@0: str += ' override'; michael@0: } michael@0: if (mi.isNative()) { michael@0: str += ' native'; michael@0: } michael@0: str += ' function'; michael@0: str += trait.isGetter() ? ' get' : trait.isSetter() ? ' set' : ''; michael@0: str += ' ' + trait.name.getName(); michael@0: str += '(' + getSignature(mi) + ')'; michael@0: str += mi.returnType ? ':' + mi.returnType.getName() : ''; michael@0: if (true) { michael@0: var className; michael@0: var prefix = ''; michael@0: if (trait.holder instanceof ClassInfo) { michael@0: className = trait.holder.instanceInfo.name; michael@0: if (className.namespaces[0].uri) { michael@0: prefix += className.namespaces[0].uri + '::'; michael@0: } michael@0: prefix += className.getName(); michael@0: prefix += '$/'; michael@0: } else if (trait.holder instanceof InstanceInfo) { michael@0: className = trait.holder.name; michael@0: if (className.namespaces[0].uri) { michael@0: prefix += className.namespaces[0].uri + '::'; michael@0: } michael@0: prefix += className.getName(); michael@0: prefix += '/'; michael@0: } else { michael@0: prefix = 'global/'; michael@0: } michael@0: var getSet = trait.isGetter() ? 'get ' : trait.isSetter() ? 'set ' : ''; michael@0: if (!mi.isNative()) { michael@0: } michael@0: } michael@0: if (mi.isNative()) { michael@0: writer.writeLn(str + ';'); michael@0: } else { michael@0: if (inInterfaceNamespace) { michael@0: writer.writeLn(str + ';'); michael@0: } else { michael@0: writer.writeLn(str + ' { notImplemented("' + trait.name.getName() + '"); }'); michael@0: } michael@0: } michael@0: } else if (trait.isClass()) { michael@0: var className = trait.classInfo.instanceInfo.name; michael@0: writer.enter('package ' + className.namespaces[0].uri + ' {\n'); michael@0: tracer.traceMetadata(trait.metadata); michael@0: tracer.traceClass(trait.classInfo); michael@0: writer.leave('\n}'); michael@0: tracer.traceClassStub(trait); michael@0: } else { michael@0: notImplemented(); michael@0: } michael@0: }); michael@0: }, michael@0: traceClassStub2: function traceClassStub(trait) { michael@0: var writer = this.writer; michael@0: var ci = trait.classInfo; michael@0: var ii = ci.instanceInfo; michael@0: var name = ii.name.getName(); michael@0: var native = trait.metadata ? trait.metadata.native : null; michael@0: if (!native) { michael@0: return false; michael@0: } michael@0: writer.writeLn('Cut and paste the following into `native.js\' and edit accordingly'); michael@0: writer.writeLn('8< --------------------------------------------------------------'); michael@0: writer.enter('natives.' + native.cls + ' = function ' + native.cls + '(runtime, scope, instanceConstructor, baseClass) {'); michael@0: writer.writeLn('var c = new Class("' + name + '", instanceConstructor, ApplicationDomain.passthroughCallable(instanceConstructor));'); michael@0: writer.writeLn('c.extend(baseClass);\n'); michael@0: function traceTraits(traits, isStatic) { michael@0: var nativeMethodTraits = []; michael@0: traits.forEach(function (trait, i) { michael@0: if (trait.isMethod() || trait.isGetter() || trait.isSetter()) { michael@0: if (trait.methodInfo.isNative()) { michael@0: nativeMethodTraits.push(trait); michael@0: } michael@0: } michael@0: }); michael@0: nativeMethodTraits.forEach(function (trait, i) { michael@0: var mi = trait.methodInfo; michael@0: var traitName = trait.name.getName(); michael@0: writer.writeLn('// ' + traitName + ' :: ' + (mi.parameters.length ? getSignature(mi) : 'void') + ' -> ' + (mi.returnType ? mi.returnType.getName() : 'any')); michael@0: var prop; michael@0: if (trait.isGetter()) { michael@0: prop = '"get ' + traitName + '"'; michael@0: } else if (trait.isSetter()) { michael@0: prop = '"set ' + traitName + '"'; michael@0: } else { michael@0: prop = traitName; michael@0: } michael@0: writer.enter(prop + ': function ' + traitName + '(' + getSignature(mi, true) + ') {'); michael@0: writer.writeLn(' notImplemented("' + name + '.' + traitName + '");'); michael@0: writer.leave('}' + (i === nativeMethodTraits.length - 1 ? '' : ',\n')); michael@0: }); michael@0: } michael@0: writer.enter('c.nativeStatics = {'); michael@0: traceTraits(ci.traits, true); michael@0: writer.leave('};\n'); michael@0: writer.enter('c.nativeMethods = {'); michael@0: traceTraits(ii.traits); michael@0: writer.leave('};\n'); michael@0: writer.writeLn('return c;'); michael@0: writer.leave('};'); michael@0: writer.writeLn('-------------------------------------------------------------- >8'); michael@0: return true; michael@0: }, michael@0: traceClassStub: function traceClassStub(trait) { michael@0: var writer = this.writer; michael@0: var ci = trait.classInfo; michael@0: var ii = ci.instanceInfo; michael@0: var className = ii.name.getName(); michael@0: var native = trait.metadata ? trait.metadata.native : null; michael@0: writer.writeLn('Cut and paste the following glue and edit accordingly.'); michael@0: writer.writeLn('Class ' + ii); michael@0: writer.writeLn('8< --------------------------------------------------------------'); michael@0: var uri = ii.name.namespaces[0].uri; michael@0: writer.enter('var ' + className + 'Definition = (function () {'); michael@0: function maxTraitNameLength(traits) { michael@0: var length = 0; michael@0: traits.forEach(function (t) { michael@0: length = Math.max(t.name.name.length, length); michael@0: }); michael@0: return length; michael@0: } michael@0: function quote(s) { michael@0: return '\'' + s + '\''; michael@0: } michael@0: function filterTraits(traits, isNative) { michael@0: function isMethod(x) { michael@0: return x.isMethod() || x.isGetter() || x.isSetter(); michael@0: } michael@0: return { michael@0: properties: traits.filter(function (trait) { michael@0: return !isNative && !isMethod(trait); michael@0: }), michael@0: methods: traits.filter(function (trait) { michael@0: return isMethod(trait) && isNative === trait.methodInfo.isNative(); michael@0: }) michael@0: }; michael@0: } michael@0: function writeTraits(traits, isNative, isStatic) { michael@0: traits = filterTraits(traits, isNative); michael@0: var methods = []; michael@0: var gettersAndSetters = createEmptyObject(); michael@0: traits.methods.forEach(function (trait, i) { michael@0: var traitName = trait.name.getName(); michael@0: if (trait.isGetter() || trait.isSetter()) { michael@0: if (!gettersAndSetters[traitName]) { michael@0: gettersAndSetters[traitName] = []; michael@0: } michael@0: gettersAndSetters[traitName].push(trait); michael@0: } else { michael@0: methods.push(trait); michael@0: } michael@0: }); michael@0: function writeTrait(trait, writeComma) { michael@0: var mi = trait.methodInfo; michael@0: var traitName = trait.name.getName(); michael@0: var signature = '// (' + (mi.parameters.length ? getSignature(mi) : 'void') + ') -> ' + (mi.returnType ? mi.returnType.getName() : 'any'); michael@0: var propertyName = traitName; michael@0: if (trait.isGetter()) { michael@0: propertyName = 'get'; michael@0: } else if (trait.isSetter()) { michael@0: propertyName = 'set'; michael@0: } michael@0: writer.enter(propertyName + ': function ' + traitName + '(' + getSignature(mi, true) + ') { ' + signature); michael@0: writer.writeLn('notImplemented("' + className + '.' + traitName + '");'); michael@0: if (!isStatic) { michael@0: if (trait.isGetter()) { michael@0: writer.writeLn('return this._' + traitName + ';'); michael@0: } else if (trait.isSetter()) { michael@0: writer.writeLn('this._' + traitName + ' = ' + mi.parameters[0].name + ';'); michael@0: } michael@0: } michael@0: writer.leave('}' + (writeComma ? ',' : '')); michael@0: } michael@0: for (var i = 0; i < methods.length; i++) { michael@0: writeTrait(methods[i], i < methods.length - 1); michael@0: } michael@0: var keyValues = toKeyValueArray(gettersAndSetters); michael@0: for (var j = 0; j < keyValues.length; j++) { michael@0: writer.enter(keyValues[j][0] + ': {'); michael@0: var list = keyValues[j][1]; michael@0: for (var i = 0; i < list.length; i++) { michael@0: writeTrait(list[i], i < list.length - 1); michael@0: } michael@0: writer.leave('}' + (j < keyValues.length - 1 ? ',' : '')); michael@0: } michael@0: traits.properties.forEach(function (trait, i) { michael@0: var traitName = trait.name.getName(); michael@0: var last = i === traits.properties.length - 1; michael@0: if (trait.name.getNamespace().isPublic()) { michael@0: writer.writeLn(traitName + ': ' + quote('public ' + trait.name.name) + (last ? '' : ',')); michael@0: } michael@0: }); michael@0: } michael@0: writer.enter('return {'); michael@0: writer.writeLn('// (' + getSignature(ii.init, false) + ')'); michael@0: writer.writeLn('__class__: "' + uri + '.' + className + '",'); michael@0: writer.enter('initialize: function () {'); michael@0: writer.leave('},'); michael@0: writer.enter('__glue__: {'); michael@0: writer.enter('native: {'); michael@0: writer.enter('static: {'); michael@0: writeTraits(ci.traits, true, true); michael@0: writer.leave('},'); michael@0: writer.enter('instance: {'); michael@0: writeTraits(ii.traits, true); michael@0: writer.leave('}'); michael@0: writer.leave('},'); michael@0: writer.enter('script: {'); michael@0: writer.writeLn('instance: Glue.ALL'); michael@0: writer.leave('}'); michael@0: writer.leave('}'); michael@0: writer.leave('};'); michael@0: writer.leave('}).call(this);'); michael@0: writer.writeLn('-------------------------------------------------------------- >8'); michael@0: return true; michael@0: }, michael@0: traceClass: function traceClass(ci) { michael@0: var writer = this.writer; michael@0: var ii = ci.instanceInfo; michael@0: var name = ii.name; michael@0: var str = Multiname.getAccessModifier(name); michael@0: if (ii.isFinal()) { michael@0: str += ' final'; michael@0: } michael@0: if (!ii.isSealed()) { michael@0: str += ' dynamic'; michael@0: } michael@0: str += ii.isInterface() ? ' interface ' : ' class '; michael@0: str += name.getName(); michael@0: if (ii.superName && ii.superName.getName() !== 'Object') { michael@0: str += ' extends ' + ii.superName.getName(); michael@0: } michael@0: if (ii.interfaces.length) { michael@0: str += ' implements ' + ii.interfaces.map(function (x) { michael@0: return x.getName(); michael@0: }).join(', '); michael@0: } michael@0: writer.enter(str + ' {'); michael@0: if (!ii.isInterface()) { michael@0: writer.writeLn('public function ' + name.getName() + '(' + getSignature(ii.init) + ') {}'); michael@0: } michael@0: var interfaceNamespace; michael@0: if (ii.isInterface()) { michael@0: interfaceNamespace = name.namespaces[0].uri + ':' + name.name; michael@0: } michael@0: this.traceTraits(ci.traits, true, interfaceNamespace); michael@0: this.traceTraits(ii.traits, false, interfaceNamespace); michael@0: writer.leave('}'); michael@0: }, michael@0: traceMetadata: function traceMetadata(metadata) { michael@0: var writer = this.writer; michael@0: for (var key in metadata) { michael@0: if (metadata.hasOwnProperty(key)) { michael@0: if (key.indexOf('__') === 0) { michael@0: continue; michael@0: } michael@0: writer.writeLn('[' + key + '(' + metadata[key].value.map(function (m) { michael@0: var str = m.key ? m.key + '=' : ''; michael@0: return str + '"' + m.value + '"'; michael@0: }).join(', ') + ')]'); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return SourceTracer; michael@0: }(); michael@0: function traceSource(writer, abc) { michael@0: var tracer = new SourceTracer(writer); michael@0: abc.scripts.forEach(function (script) { michael@0: tracer.traceTraits(script.traits); michael@0: }); michael@0: } michael@0: function traceStatistics(writer, abc) { michael@0: var libraryClassCounter = new Shumway.Metrics.Counter(true); michael@0: var librarySuperClassCounter = new Shumway.Metrics.Counter(true); michael@0: var libraryMethodCounter = new Shumway.Metrics.Counter(true); michael@0: var libraryProperties = new Shumway.Metrics.Counter(true); michael@0: var definedClasses = {}; michael@0: var definedMethods = {}; michael@0: var definedProperties = {}; michael@0: abc.classes.forEach(function (x) { michael@0: var className = x.instanceInfo.name.name; michael@0: definedClasses[className] = true; michael@0: }); michael@0: abc.scripts.forEach(function (s) { michael@0: s.traits.forEach(function (t) { michael@0: if (t.isClass()) { michael@0: var superClassName = t.classInfo.instanceInfo.superName ? t.classInfo.instanceInfo.superName.name : '?'; michael@0: if (!(superClassName in definedClasses)) { michael@0: librarySuperClassCounter.count(superClassName); michael@0: } michael@0: t.classInfo.traits.forEach(function (st) { michael@0: if (st.isMethod()) { michael@0: definedMethods[st.name.name] = true; michael@0: } else { michael@0: definedProperties[st.name.name] = true; michael@0: } michael@0: }); michael@0: t.classInfo.instanceInfo.traits.forEach(function (it) { michael@0: if (it.isMethod() && !(it.attributes & ATTR_Override)) { michael@0: definedMethods[it.name.name] = true; michael@0: } else { michael@0: definedProperties[it.name.name] = true; michael@0: } michael@0: }); michael@0: } michael@0: }); michael@0: }); michael@0: var opCounter = new Shumway.Metrics.Counter(true); michael@0: abc.methods.forEach(function (m) { michael@0: if (!m.code) { michael@0: return; michael@0: } michael@0: function readOperand(operand) { michael@0: var value = 0; michael@0: switch (operand.size) { michael@0: case 's08': michael@0: value = code.readS8(); michael@0: break; michael@0: case 'u08': michael@0: value = code.readU8(); michael@0: break; michael@0: case 's16': michael@0: value = code.readS16(); michael@0: break; michael@0: case 's24': michael@0: value = code.readS24(); michael@0: break; michael@0: case 'u30': michael@0: value = code.readU30(); michael@0: break; michael@0: case 'u32': michael@0: value = code.readU32(); michael@0: break; michael@0: default: michael@0: true; michael@0: break; michael@0: } michael@0: var description = ''; michael@0: switch (operand.type) { michael@0: case '': michael@0: break; michael@0: case 'I': michael@0: description = abc.constantPool.ints[value]; michael@0: break; michael@0: case 'U': michael@0: description = abc.constantPool.uints[value]; michael@0: break; michael@0: case 'D': michael@0: description = abc.constantPool.doubles[value]; michael@0: break; michael@0: case 'S': michael@0: description = abc.constantPool.strings[value]; michael@0: break; michael@0: case 'N': michael@0: description = abc.constantPool.namespaces[value]; michael@0: break; michael@0: case 'CI': michael@0: description = abc.classes[value]; michael@0: break; michael@0: case 'M': michael@0: description = abc.constantPool.multinames[value]; michael@0: break; michael@0: default: michael@0: description = '?'; michael@0: break; michael@0: } michael@0: return description; michael@0: } michael@0: var code = new AbcStream(m.code); michael@0: while (code.remaining() > 0) { michael@0: var bc = code.readU8(); michael@0: var op = opcodeTable[bc]; michael@0: var operands = null; michael@0: if (op) { michael@0: opCounter.count(op.name); michael@0: if (op.operands) { michael@0: operands = op.operands.map(readOperand); michael@0: } michael@0: switch (bc) { michael@0: case OP_call: michael@0: case OP_callmethod: michael@0: continue; michael@0: case OP_callproperty: michael@0: case OP_callproplex: michael@0: case OP_callpropvoid: michael@0: case OP_callstatic: michael@0: case OP_callsuper: michael@0: case OP_callsupervoid: michael@0: if (operands[0] && !(operands[0].name in definedMethods)) { michael@0: libraryMethodCounter.count(operands[0].name); michael@0: } michael@0: break; michael@0: case OP_constructprop: michael@0: if (operands[0] && !(operands[0].name in definedClasses)) { michael@0: libraryClassCounter.count(operands[0].name); michael@0: } michael@0: break; michael@0: case OP_getproperty: michael@0: case OP_setproperty: michael@0: if (operands[0] && !(operands[0].name in definedProperties)) { michael@0: libraryProperties.count(operands[0].name); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: }); michael@0: writer.writeLn(JSON.stringify({ michael@0: definedClasses: definedClasses, michael@0: definedMethods: definedMethods, michael@0: definedProperties: definedProperties, michael@0: libraryClasses: libraryClassCounter.counts, michael@0: librarySuperClasses: librarySuperClassCounter.counts, michael@0: libraryMethods: libraryMethodCounter.counts, michael@0: libraryProperties: libraryProperties.counts, michael@0: operations: opCounter.counts michael@0: }, null, 2)); michael@0: } michael@0: var Shumway; michael@0: (function (Shumway) { michael@0: (function (AVM2) { michael@0: var OP = Shumway.AVM2.ABC.OP; michael@0: var Scope = Shumway.AVM2.Runtime.Scope; michael@0: var asCoerceByMultiname = Shumway.AVM2.Runtime.asCoerceByMultiname; michael@0: var asGetSlot = Shumway.AVM2.Runtime.asGetSlot; michael@0: var asSetSlot = Shumway.AVM2.Runtime.asSetSlot; michael@0: var asHasNext2 = Shumway.AVM2.Runtime.asHasNext2; michael@0: var asCoerce = Shumway.AVM2.Runtime.asCoerce; michael@0: var asCoerceString = Shumway.AVM2.Runtime.asCoerceString; michael@0: var asAsType = Shumway.AVM2.Runtime.asAsType; michael@0: var asTypeOf = Shumway.AVM2.Runtime.asTypeOf; michael@0: var asIsInstanceOf = Shumway.AVM2.Runtime.asIsInstanceOf; michael@0: var asIsType = Shumway.AVM2.Runtime.asIsType; michael@0: var applyType = Shumway.AVM2.Runtime.applyType; michael@0: var createFunction = Shumway.AVM2.Runtime.createFunction; michael@0: var createClass = Shumway.AVM2.Runtime.createClass; michael@0: var getDescendants = Shumway.AVM2.Runtime.getDescendants; michael@0: var checkFilter = Shumway.AVM2.Runtime.checkFilter; michael@0: var asAdd = Shumway.AVM2.Runtime.asAdd; michael@0: var translateError = Shumway.AVM2.Runtime.translateError; michael@0: var asCreateActivation = Shumway.AVM2.Runtime.asCreateActivation; michael@0: var sliceArguments = Shumway.AVM2.Runtime.sliceArguments; michael@0: var boxValue = Shumway.ObjectUtilities.boxValue; michael@0: var popManyInto = Shumway.ArrayUtilities.popManyInto; michael@0: var construct = Shumway.AVM2.Runtime.construct; michael@0: var Multiname = Shumway.AVM2.ABC.Multiname; michael@0: var ScopeStack = function () { michael@0: function ScopeStack(parent) { michael@0: this.parent = parent; michael@0: this.stack = []; michael@0: this.isWith = []; michael@0: } michael@0: ScopeStack.prototype.push = function (object, isWith) { michael@0: this.stack.push(object); michael@0: this.isWith.push(!(!isWith)); michael@0: }; michael@0: ScopeStack.prototype.get = function (index) { michael@0: return this.stack[index]; michael@0: }; michael@0: ScopeStack.prototype.clear = function () { michael@0: this.stack.length = 0; michael@0: this.isWith.length = 0; michael@0: }; michael@0: ScopeStack.prototype.pop = function () { michael@0: this.isWith.pop(); michael@0: this.stack.pop(); michael@0: }; michael@0: ScopeStack.prototype.topScope = function () { michael@0: if (!this.scopes) { michael@0: this.scopes = []; michael@0: } michael@0: var parent = this.parent; michael@0: for (var i = 0; i < this.stack.length; i++) { michael@0: var object = this.stack[i], isWith = this.isWith[i], scope = this.scopes[i]; michael@0: if (!scope || scope.parent !== parent || scope.object !== object || scope.isWith !== isWith) { michael@0: scope = this.scopes[i] = new Scope(parent, object, isWith); michael@0: } michael@0: parent = scope; michael@0: } michael@0: return parent; michael@0: }; michael@0: return ScopeStack; michael@0: }(); michael@0: function popNameInto(stack, mn, out) { michael@0: out.flags = mn.flags; michael@0: if (mn.isRuntimeName()) { michael@0: out.name = stack.pop(); michael@0: } else { michael@0: out.name = mn.name; michael@0: } michael@0: if (mn.isRuntimeNamespace()) { michael@0: out.namespaces = [ michael@0: stack.pop() michael@0: ]; michael@0: } else { michael@0: out.namespaces = mn.namespaces; michael@0: } michael@0: } michael@0: var Interpreter = function () { michael@0: function Interpreter() { michael@0: } michael@0: Interpreter.interpretMethod = function ($this, method, savedScope, methodArgs) { michael@0: true; michael@0: Counter.count('Interpret Method'); michael@0: var abc = method.abc; michael@0: var ints = abc.constantPool.ints; michael@0: var uints = abc.constantPool.uints; michael@0: var doubles = abc.constantPool.doubles; michael@0: var strings = abc.constantPool.strings; michael@0: var methods = abc.methods; michael@0: var multinames = abc.constantPool.multinames; michael@0: var domain = abc.applicationDomain; michael@0: var exceptions = method.exceptions; michael@0: var locals = [ michael@0: $this michael@0: ]; michael@0: var stack = [], scopeStack = new ScopeStack(savedScope); michael@0: var parameterCount = method.parameters.length; michael@0: var argCount = methodArgs.length; michael@0: var value; michael@0: for (var i = 0; i < parameterCount; i++) { michael@0: var parameter = method.parameters[i]; michael@0: if (i < argCount) { michael@0: value = methodArgs[i]; michael@0: } else { michael@0: value = parameter.value; michael@0: } michael@0: if (parameter.type && !parameter.type.isAnyName()) { michael@0: value = asCoerceByMultiname(domain, parameter.type, value); michael@0: } michael@0: locals.push(value); michael@0: } michael@0: if (method.needsRest()) { michael@0: locals.push(sliceArguments(methodArgs, parameterCount)); michael@0: } else if (method.needsArguments()) { michael@0: locals.push(sliceArguments(methodArgs, 0)); michael@0: } michael@0: var bytecodes = method.analysis.bytecodes; michael@0: var object, index, multiname, result, a, b, args = [], mn = Multiname.TEMPORARY; michael@0: interpretLabel: michael@0: for (var pc = 0, end = bytecodes.length; pc < end;) { michael@0: try { michael@0: var bc = bytecodes[pc]; michael@0: var op = bc.op; michael@0: switch (op | 0) { michael@0: case 3: michael@0: throw stack.pop(); michael@0: case 4: michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack.push(stack.pop().asGetSuper(savedScope, mn.namespaces, mn.name, mn.flags)); michael@0: break; michael@0: case 5: michael@0: value = stack.pop(); michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack.pop().asSetSuper(savedScope, mn.namespaces, mn.name, mn.flags, value); michael@0: break; michael@0: case 8: michael@0: locals[bc.index] = undefined; michael@0: break; michael@0: case 12: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = !(a < b) ? bc.offset : pc + 1; michael@0: continue; michael@0: case 24: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a >= b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 13: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = !(a <= b) ? bc.offset : pc + 1; michael@0: continue; michael@0: case 23: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a > b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 14: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = !(a > b) ? bc.offset : pc + 1; michael@0: continue; michael@0: case 22: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a <= b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 15: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = !(a >= b) ? bc.offset : pc + 1; michael@0: continue; michael@0: case 21: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a < b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 16: michael@0: pc = bc.offset; michael@0: continue; michael@0: case 17: michael@0: pc = !(!stack.pop()) ? bc.offset : pc + 1; michael@0: continue; michael@0: case 18: michael@0: pc = !stack.pop() ? bc.offset : pc + 1; michael@0: continue; michael@0: case 19: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a == b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 20: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a != b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 25: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a === b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 26: michael@0: b = stack.pop(); michael@0: a = stack.pop(); michael@0: pc = a !== b ? bc.offset : pc + 1; michael@0: continue; michael@0: case 27: michael@0: index = stack.pop(); michael@0: if (index < 0 || index >= bc.offsets.length) { michael@0: index = bc.offsets.length - 1; michael@0: } michael@0: pc = bc.offsets[index]; michael@0: continue; michael@0: case 28: michael@0: scopeStack.push(boxValue(stack.pop()), true); michael@0: break; michael@0: case 29: michael@0: scopeStack.pop(); michael@0: break; michael@0: case 30: michael@0: index = stack.pop(); michael@0: stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextName(index); michael@0: break; michael@0: case 35: michael@0: index = stack.pop(); michael@0: stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextValue(index); michael@0: break; michael@0: case 50: michael@0: result = asHasNext2(locals[bc.object], locals[bc.index]); michael@0: locals[bc.object] = result.object; michael@0: locals[bc.index] = result.index; michael@0: stack.push(!(!result.index)); michael@0: break; michael@0: case 32: michael@0: stack.push(null); michael@0: break; michael@0: case 33: michael@0: stack.push(undefined); michael@0: break; michael@0: case 36: michael@0: case 37: michael@0: stack.push(bc.value); michael@0: break; michael@0: case 44: michael@0: stack.push(strings[bc.index]); michael@0: break; michael@0: case 45: michael@0: stack.push(ints[bc.index]); michael@0: break; michael@0: case 46: michael@0: stack.push(uints[bc.index]); michael@0: break; michael@0: case 47: michael@0: stack.push(doubles[bc.index]); michael@0: break; michael@0: case 38: michael@0: stack.push(true); michael@0: break; michael@0: case 39: michael@0: stack.push(false); michael@0: break; michael@0: case 40: michael@0: stack.push(NaN); michael@0: break; michael@0: case 41: michael@0: stack.pop(); michael@0: break; michael@0: case 42: michael@0: stack.push(stack[stack.length - 1]); michael@0: break; michael@0: case 43: michael@0: object = stack[stack.length - 1]; michael@0: stack[stack.length - 1] = stack[stack.length - 2]; michael@0: stack[stack.length - 2] = object; michael@0: break; michael@0: case 48: michael@0: scopeStack.push(boxValue(stack.pop()), false); michael@0: break; michael@0: case 64: michael@0: stack.push(createFunction(methods[bc.index], scopeStack.topScope(), true)); michael@0: break; michael@0: case 65: michael@0: popManyInto(stack, bc.argCount, args); michael@0: object = stack.pop(); michael@0: stack[stack.length - 1] = stack[stack.length - 1].apply(object, args); michael@0: break; michael@0: case 66: michael@0: popManyInto(stack, bc.argCount, args); michael@0: stack[stack.length - 1] = construct(stack[stack.length - 1], args); michael@0: break; michael@0: case 71: michael@0: return; michael@0: case 72: michael@0: if (method.returnType) { michael@0: return asCoerceByMultiname(domain, method.returnType, stack.pop()); michael@0: } michael@0: return stack.pop(); michael@0: case 73: michael@0: popManyInto(stack, bc.argCount, args); michael@0: object = stack.pop(); michael@0: savedScope.object.baseClass.instanceConstructorNoInitialize.apply(object, args); michael@0: break; michael@0: case 74: michael@0: popManyInto(stack, bc.argCount, args); michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: object = boxValue(stack[stack.length - 1]); michael@0: object = object.asConstructProperty(mn.namespaces, mn.name, mn.flags, args); michael@0: stack[stack.length - 1] = object; michael@0: break; michael@0: case 75: michael@0: Shumway.Debug.notImplemented('OP.callsuperid'); michael@0: break; michael@0: case 76: michael@0: case 70: michael@0: case 79: michael@0: popManyInto(stack, bc.argCount, args); michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: result = boxValue(stack.pop()).asCallProperty(mn.namespaces, mn.name, mn.flags, op === 76, args); michael@0: if (op !== 79) { michael@0: stack.push(result); michael@0: } michael@0: break; michael@0: case 69: michael@0: case 78: michael@0: popManyInto(stack, bc.argCount, args); michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: result = stack.pop().asCallSuper(savedScope, mn.namespaces, mn.name, mn.flags, args); michael@0: if (op !== 78) { michael@0: stack.push(result); michael@0: } michael@0: break; michael@0: case 83: michael@0: popManyInto(stack, bc.argCount, args); michael@0: stack[stack.length - 1] = applyType(domain, stack[stack.length - 1], args); michael@0: break; michael@0: case 85: michael@0: object = {}; michael@0: for (var i = 0; i < bc.argCount; i++) { michael@0: value = stack.pop(); michael@0: object[Multiname.getPublicQualifiedName(stack.pop())] = value; michael@0: } michael@0: stack.push(object); michael@0: break; michael@0: case 86: michael@0: object = []; michael@0: popManyInto(stack, bc.argCount, args); michael@0: object.push.apply(object, args); michael@0: stack.push(object); michael@0: break; michael@0: case 87: michael@0: true; michael@0: stack.push(asCreateActivation(method)); michael@0: break; michael@0: case 88: michael@0: stack[stack.length - 1] = createClass(abc.classes[bc.index], stack[stack.length - 1], scopeStack.topScope()); michael@0: break; michael@0: case 89: michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack.push(getDescendants(stack.pop(), mn)); michael@0: break; michael@0: case 90: michael@0: true; michael@0: stack.push(exceptions[bc.index].scopeObject); michael@0: break; michael@0: case 94: michael@0: case 93: michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack.push(scopeStack.topScope().findScopeProperty(mn.namespaces, mn.name, mn.flags, domain, op === 93, false)); michael@0: break; michael@0: case 96: michael@0: multiname = multinames[bc.index]; michael@0: object = scopeStack.topScope().findScopeProperty(multiname.namespaces, multiname.name, multiname.flags, domain, true, false); michael@0: stack.push(object.asGetProperty(multiname.namespaces, multiname.name, multiname.flags)); michael@0: break; michael@0: case 104: michael@0: case 97: michael@0: value = stack.pop(); michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: boxValue(stack.pop()).asSetProperty(mn.namespaces, mn.name, mn.flags, value); michael@0: break; michael@0: case 98: michael@0: stack.push(locals[bc.index]); michael@0: break; michael@0: case 99: michael@0: locals[bc.index] = stack.pop(); michael@0: break; michael@0: case 100: michael@0: stack.push(savedScope.global.object); michael@0: break; michael@0: case 101: michael@0: stack.push(scopeStack.get(bc.index)); michael@0: break; michael@0: case 102: michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asGetProperty(mn.namespaces, mn.name, mn.flags); michael@0: break; michael@0: case 106: michael@0: popNameInto(stack, multinames[bc.index], mn); michael@0: stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asDeleteProperty(mn.namespaces, mn.name, mn.flags); michael@0: break; michael@0: case 108: michael@0: stack[stack.length - 1] = asGetSlot(stack[stack.length - 1], bc.index); michael@0: break; michael@0: case 109: michael@0: value = stack.pop(); michael@0: object = stack.pop(); michael@0: asSetSlot(object, bc.index, value); michael@0: break; michael@0: case 112: michael@0: stack[stack.length - 1] = stack[stack.length - 1] + ''; michael@0: break; michael@0: case 131: michael@0: case 115: michael@0: stack[stack.length - 1] |= 0; michael@0: break; michael@0: case 136: michael@0: case 116: michael@0: stack[stack.length - 1] >>>= 0; michael@0: break; michael@0: case 132: michael@0: case 117: michael@0: stack[stack.length - 1] = +stack[stack.length - 1]; michael@0: break; michael@0: case 129: michael@0: case 118: michael@0: stack[stack.length - 1] = !(!stack[stack.length - 1]); michael@0: break; michael@0: case 120: michael@0: stack[stack.length - 1] = checkFilter(stack[stack.length - 1]); michael@0: break; michael@0: case 128: michael@0: stack[stack.length - 1] = asCoerce(domain.getType(multinames[bc.index]), stack[stack.length - 1]); michael@0: break; michael@0: case 130: michael@0: break; michael@0: case 133: michael@0: stack[stack.length - 1] = asCoerceString(stack[stack.length - 1]); michael@0: break; michael@0: case 135: michael@0: stack[stack.length - 2] = asAsType(stack.pop(), stack[stack.length - 1]); michael@0: break; michael@0: case 137: michael@0: object = stack[stack.length - 1]; michael@0: stack[stack.length - 1] = object == undefined ? null : object; michael@0: break; michael@0: case 144: michael@0: stack[stack.length - 1] = -stack[stack.length - 1]; michael@0: break; michael@0: case 145: michael@0: ++stack[stack.length - 1]; michael@0: break; michael@0: case 146: michael@0: ++locals[bc.index]; michael@0: break; michael@0: case 147: michael@0: --stack[stack.length - 1]; michael@0: break; michael@0: case 148: michael@0: --locals[bc.index]; michael@0: break; michael@0: case 149: michael@0: stack[stack.length - 1] = asTypeOf(stack[stack.length - 1]); michael@0: break; michael@0: case 150: michael@0: stack[stack.length - 1] = !stack[stack.length - 1]; michael@0: break; michael@0: case 151: michael@0: stack[stack.length - 1] = ~stack[stack.length - 1]; michael@0: break; michael@0: case 160: michael@0: stack[stack.length - 2] = asAdd(stack[stack.length - 2], stack.pop()); michael@0: break; michael@0: case 161: michael@0: stack[stack.length - 2] -= stack.pop(); michael@0: break; michael@0: case 162: michael@0: stack[stack.length - 2] *= stack.pop(); michael@0: break; michael@0: case 163: michael@0: stack[stack.length - 2] /= stack.pop(); michael@0: break; michael@0: case 164: michael@0: stack[stack.length - 2] %= stack.pop(); michael@0: break; michael@0: case 165: michael@0: stack[stack.length - 2] <<= stack.pop(); michael@0: break; michael@0: case 166: michael@0: stack[stack.length - 2] >>= stack.pop(); michael@0: break; michael@0: case 167: michael@0: stack[stack.length - 2] >>>= stack.pop(); michael@0: break; michael@0: case 168: michael@0: stack[stack.length - 2] &= stack.pop(); michael@0: break; michael@0: case 169: michael@0: stack[stack.length - 2] |= stack.pop(); michael@0: break; michael@0: case 170: michael@0: stack[stack.length - 2] ^= stack.pop(); michael@0: break; michael@0: case 171: michael@0: stack[stack.length - 2] = stack[stack.length - 2] == stack.pop(); michael@0: break; michael@0: case 172: michael@0: stack[stack.length - 2] = stack[stack.length - 2] === stack.pop(); michael@0: break; michael@0: case 173: michael@0: stack[stack.length - 2] = stack[stack.length - 2] < stack.pop(); michael@0: break; michael@0: case 174: michael@0: stack[stack.length - 2] = stack[stack.length - 2] <= stack.pop(); michael@0: break; michael@0: case 175: michael@0: stack[stack.length - 2] = stack[stack.length - 2] > stack.pop(); michael@0: break; michael@0: case 176: michael@0: stack[stack.length - 2] = stack[stack.length - 2] >= stack.pop(); michael@0: break; michael@0: case 177: michael@0: stack[stack.length - 2] = asIsInstanceOf(stack.pop(), stack[stack.length - 1]); michael@0: break; michael@0: case 178: michael@0: stack[stack.length - 1] = asIsType(domain.getType(multinames[bc.index]), stack[stack.length - 1]); michael@0: break; michael@0: case 179: michael@0: stack[stack.length - 2] = asIsType(stack.pop(), stack[stack.length - 1]); michael@0: break; michael@0: case 180: michael@0: stack[stack.length - 2] = boxValue(stack.pop()).asHasProperty(null, stack[stack.length - 1]); michael@0: break; michael@0: case 192: michael@0: stack[stack.length - 1] = (stack[stack.length - 1] | 0) + 1; michael@0: break; michael@0: case 193: michael@0: stack[stack.length - 1] = (stack[stack.length - 1] | 0) - 1; michael@0: break; michael@0: case 194: michael@0: locals[bc.index] = (locals[bc.index] | 0) + 1; michael@0: break; michael@0: case 195: michael@0: locals[bc.index] = (locals[bc.index] | 0) - 1; michael@0: break; michael@0: case 196: michael@0: stack[stack.length - 1] = ~stack[stack.length - 1]; michael@0: break; michael@0: case 197: michael@0: stack[stack.length - 2] = stack[stack.length - 2] + stack.pop() | 0; michael@0: break; michael@0: case 198: michael@0: stack[stack.length - 2] = stack[stack.length - 2] - stack.pop() | 0; michael@0: break; michael@0: case 199: michael@0: stack[stack.length - 2] = stack[stack.length - 2] * stack.pop() | 0; michael@0: break; michael@0: case 208: michael@0: case 209: michael@0: case 210: michael@0: case 211: michael@0: stack.push(locals[op - 208]); michael@0: break; michael@0: case 212: michael@0: case 213: michael@0: case 214: michael@0: case 215: michael@0: locals[op - 212] = stack.pop(); michael@0: break; michael@0: case 239: michael@0: case 240: michael@0: case 241: michael@0: break; michael@0: default: michael@0: Shumway.Debug.notImplemented(Shumway.AVM2.opcodeName(op)); michael@0: } michael@0: pc++; michael@0: } catch (e) { michael@0: if (exceptions.length < 1) { michael@0: throw e; michael@0: } michael@0: e = translateError(domain, e); michael@0: for (var i = 0, j = exceptions.length; i < j; i++) { michael@0: var handler = exceptions[i]; michael@0: if (pc >= handler.start && pc <= handler.end && (!handler.typeName || domain.getType(handler.typeName).isInstance(e))) { michael@0: stack.length = 0; michael@0: stack.push(e); michael@0: scopeStack.clear(); michael@0: pc = handler.offset; michael@0: continue interpretLabel; michael@0: } michael@0: } michael@0: throw e; michael@0: } michael@0: } michael@0: }; michael@0: return Interpreter; michael@0: }(); michael@0: AVM2.Interpreter = Interpreter; michael@0: }(Shumway.AVM2 || (Shumway.AVM2 = {}))); michael@0: var AVM2 = Shumway.AVM2; michael@0: }(Shumway || (Shumway = {}))); michael@0: Shumway.AVM2.Runtime.enableVerifier.value = true; michael@0: release = true; michael@0: var avm2Root = SHUMWAY_ROOT + 'avm2/'; michael@0: var builtinPath = avm2Root + 'generated/builtin/builtin.abc'; michael@0: var avm1Path = avm2Root + 'generated/avm1lib/avm1lib.abc'; michael@0: var BinaryFileReader = function binaryFileReader() { michael@0: function constructor(url, responseType) { michael@0: this.url = url; michael@0: this.responseType = responseType || 'arraybuffer'; michael@0: } michael@0: constructor.prototype = { michael@0: readAll: function (progress, complete) { michael@0: var url = this.url; michael@0: var xhr = new XMLHttpRequest(); michael@0: var async = true; michael@0: xhr.open('GET', this.url, async); michael@0: xhr.responseType = this.responseType; michael@0: if (progress) { michael@0: xhr.onprogress = function (event) { michael@0: progress(xhr.response, event.loaded, event.total); michael@0: }; michael@0: } michael@0: xhr.onreadystatechange = function (event) { michael@0: if (xhr.readyState === 4) { michael@0: if (xhr.status !== 200 && xhr.status !== 0) { michael@0: unexpected('Path: ' + url + ' not found.'); michael@0: complete(null, xhr.statusText); michael@0: return; michael@0: } michael@0: complete(xhr.response); michael@0: } michael@0: }; michael@0: xhr.send(null); michael@0: }, michael@0: readAsync: function (ondata, onerror, onopen, oncomplete, onhttpstatus) { michael@0: var xhr = new XMLHttpRequest({ michael@0: mozSystem: true michael@0: }); michael@0: var url = this.url; michael@0: xhr.open(this.method || 'GET', url, true); michael@0: var isNotProgressive; michael@0: try { michael@0: xhr.responseType = 'moz-chunked-arraybuffer'; michael@0: isNotProgressive = xhr.responseType !== 'moz-chunked-arraybuffer'; michael@0: } catch (e) { michael@0: isNotProgressive = true; michael@0: } michael@0: if (isNotProgressive) { michael@0: xhr.responseType = 'arraybuffer'; michael@0: } michael@0: xhr.onprogress = function (e) { michael@0: if (isNotProgressive) michael@0: return; michael@0: ondata(new Uint8Array(xhr.response), { michael@0: loaded: e.loaded, michael@0: total: e.total michael@0: }); michael@0: }; michael@0: xhr.onreadystatechange = function (event) { michael@0: if (xhr.readyState === 2 && onhttpstatus) { michael@0: onhttpstatus(url, xhr.status, xhr.getAllResponseHeaders()); michael@0: } michael@0: if (xhr.readyState === 4) { michael@0: if (xhr.status !== 200 && xhr.status !== 0) { michael@0: onerror(xhr.statusText); michael@0: } michael@0: if (isNotProgressive) { michael@0: var buffer = xhr.response; michael@0: ondata(new Uint8Array(buffer), { michael@0: loaded: buffer.byteLength, michael@0: total: buffer.byteLength michael@0: }); michael@0: } michael@0: if (oncomplete) { michael@0: oncomplete(); michael@0: } michael@0: } else if (xhr.readyState === 2 && onopen) { michael@0: onopen(); michael@0: } michael@0: }; michael@0: xhr.send(null); michael@0: } michael@0: }; michael@0: return constructor; michael@0: }(); michael@0: var libraryAbcs; michael@0: function grabAbc(abcName) { michael@0: var entry = libraryScripts[abcName]; michael@0: if (entry) { michael@0: var offset = entry.offset; michael@0: var length = entry.length; michael@0: return new AbcFile(new Uint8Array(libraryAbcs, offset, length), abcName); michael@0: } michael@0: return null; michael@0: } michael@0: var avm2; michael@0: function createAVM2(builtinPath, libraryPath, avm1Path, sysMode, appMode, next) { michael@0: avm2 = new AVM2(sysMode, appMode, loadAVM1); michael@0: var builtinAbc, avm1Abc; michael@0: AVM2.loadPlayerglobal(libraryPath.abcs, libraryPath.catalog).then(function () { michael@0: new BinaryFileReader(builtinPath).readAll(null, function (buffer) { michael@0: builtinAbc = new AbcFile(new Uint8Array(buffer), 'builtin.abc'); michael@0: executeAbc(); michael@0: }); michael@0: }); michael@0: function loadAVM1(next) { michael@0: new BinaryFileReader(avm1Path).readAll(null, function (buffer) { michael@0: avm1Abc = new AbcFile(new Uint8Array(buffer), 'avm1.abc'); michael@0: ; michael@0: avm2.systemDomain.executeAbc(avm1Abc); michael@0: next(); michael@0: }); michael@0: } michael@0: function executeAbc() { michael@0: avm2.builtinsLoaded = false; michael@0: avm2.systemDomain.onMessage.register('classCreated', Stubs.onClassCreated); michael@0: avm2.systemDomain.executeAbc(builtinAbc); michael@0: avm2.builtinsLoaded = true; michael@0: console.info(JSON.stringify(Counter.toJSON())); michael@0: console.timeEnd('Load AVM2'); michael@0: next(avm2); michael@0: } michael@0: } michael@0: { michael@0: var MAX_SNAP_DRAW_SCALE_TO_CACHE = 8; michael@0: var CACHE_SNAP_DRAW_AFTER = 3; michael@0: var BitmapDefinition = function () { michael@0: function setBitmapData(value) { michael@0: if (this._bitmapData) { michael@0: this._bitmapData._changeNotificationTarget = null; michael@0: } michael@0: this._bitmapData = value; michael@0: if (this._bitmapData) { michael@0: this._bitmapData._changeNotificationTarget = this; michael@0: } michael@0: if (value) { michael@0: var canvas = value._drawable; michael@0: this._bbox = { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: canvas.width * 20, michael@0: yMax: canvas.height * 20 michael@0: }; michael@0: } else { michael@0: this._bbox = { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: 0, michael@0: yMax: 0 michael@0: }; michael@0: } michael@0: this._drawableChanged(); michael@0: this._invalidateBounds(); michael@0: this._invalidateTransform(); michael@0: } michael@0: return { michael@0: __class__: 'flash.display.Bitmap', michael@0: draw: function (ctx, ratio, colorTransform) { michael@0: if (!this._bitmapData) { michael@0: return; michael@0: } michael@0: var scaledImage; michael@0: ctx.save(); michael@0: if (this._pixelSnapping === 'auto' || this._pixelSnapping === 'always') { michael@0: var transform = this._getConcatenatedTransform(null, true); michael@0: var EPSILON = 0.001; michael@0: var aInt = Math.abs(Math.round(transform.a)); michael@0: var dInt = Math.abs(Math.round(transform.d)); michael@0: var snapPixels; michael@0: if (aInt >= 1 && aInt <= MAX_SNAP_DRAW_SCALE_TO_CACHE && dInt >= 1 && dInt <= MAX_SNAP_DRAW_SCALE_TO_CACHE && Math.abs(Math.abs(transform.a) / aInt - 1) <= EPSILON && Math.abs(Math.abs(transform.d) / dInt - 1) <= EPSILON && Math.abs(transform.b) <= EPSILON && Math.abs(transform.c) <= EPSILON) { michael@0: if (aInt === 1 && dInt === 1) { michael@0: snapPixels = true; michael@0: } else { michael@0: var sizeKey = aInt + 'x' + dInt; michael@0: if (this._snapImageCache.size !== sizeKey) { michael@0: this._snapImageCache.size = sizeKey; michael@0: this._snapImageCache.hits = 0; michael@0: this._snapImageCache.image = null; michael@0: } michael@0: if (++this._snapImageCache.hits === CACHE_SNAP_DRAW_AFTER) { michael@0: this._cacheSnapImage(sizeKey, aInt, dInt); michael@0: } michael@0: scaledImage = this._snapImageCache.image; michael@0: snapPixels = !(!scaledImage); michael@0: } michael@0: } else { michael@0: snapPixels = false; michael@0: } michael@0: if (snapPixels) { michael@0: ctx.setTransform(transform.a < 0 ? -1 : 1, 0, 0, transform.d < 0 ? -1 : 1, transform.tx / 20 | 0, transform.ty / 20 | 0); michael@0: } michael@0: } michael@0: colorTransform.setAlpha(ctx, true); michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = this._smoothing; michael@0: ctx.drawImage(scaledImage || this._bitmapData._getDrawable(), 0, 0); michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false; michael@0: ctx.restore(); michael@0: traceRenderer.value && frameWriter.writeLn('Bitmap.draw() snapping: ' + this._pixelSnapping + ', dimensions: ' + this._bitmapData._drawable.width + ' x ' + this._bitmapData._drawable.height); michael@0: }, michael@0: _drawableChanged: function () { michael@0: this._invalidate(); michael@0: this._snapImageCache.image = null; michael@0: this._snapImageCache.hints = 0; michael@0: }, michael@0: _cacheSnapImage: function (sizeKey, xScale, yScale) { michael@0: Counter.count('Cache scaled image'); michael@0: var original = this._bitmapData._getDrawable(); michael@0: var canvas = document.createElement('canvas'); michael@0: canvas.width = xScale * original.width; michael@0: canvas.height = yScale * original.height; michael@0: var ctx = canvas.getContext('2d'); michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = this._smoothing; michael@0: ctx.drawImage(original, 0, 0, original.width, original.height, 0, 0, canvas.width, canvas.height); michael@0: var cache = this._snapImageCache; michael@0: var image = document.createElement('img'); michael@0: cache._tmp = [ michael@0: canvas, michael@0: image michael@0: ]; michael@0: if ('toBlob' in canvas) { michael@0: canvas.toBlob(function (blob) { michael@0: if (cache.size !== sizeKey) { michael@0: return; michael@0: } michael@0: image.onload = function () { michael@0: URL.revokeObjectURL(blob); michael@0: if (cache.size === sizeKey) { michael@0: cache.image = image; michael@0: } michael@0: }; michael@0: image.src = URL.createObjectURL(blob); michael@0: }); michael@0: } else { michael@0: image.onload = function () { michael@0: if (cache.size === sizeKey) { michael@0: cache.image = image; michael@0: } michael@0: }; michael@0: image.src = canvas.toDataURL(); michael@0: } michael@0: }, michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: ctor: function (bitmapData, pixelSnapping, smoothing) { michael@0: if (pixelSnapping === 'never' || pixelSnapping === 'always') { michael@0: this._pixelSnapping = pixelSnapping; michael@0: } else { michael@0: this._pixelSnapping = 'auto'; michael@0: } michael@0: this._smoothing = !(!smoothing); michael@0: this._snapImageCache = { michael@0: hits: 0, michael@0: size: '', michael@0: image: null michael@0: }; michael@0: if (!bitmapData && this.symbol) { michael@0: var symbol = this.symbol; michael@0: bitmapData = new flash.display.BitmapData(symbol.width, symbol.height, true, 0); michael@0: bitmapData._ctx.imageSmoothingEnabled = this._smoothing; michael@0: bitmapData._ctx.mozImageSmoothingEnabled = this._smoothing; michael@0: bitmapData._ctx.drawImage(symbol.img, 0, 0); michael@0: bitmapData._ctx.imageSmoothingEnabled = false; michael@0: bitmapData._ctx.mozImageSmoothingEnabled = false; michael@0: } michael@0: setBitmapData.call(this, bitmapData || null); michael@0: }, michael@0: pixelSnapping: { michael@0: get: function pixelSnapping() { michael@0: return this._pixelSnapping; michael@0: }, michael@0: set: function pixelSnapping(value) { michael@0: this._pixelSnapping = value; michael@0: } michael@0: }, michael@0: smoothing: { michael@0: get: function smoothing() { michael@0: return this._smoothing; michael@0: }, michael@0: set: function smoothing(value) { michael@0: this._smoothing = value; michael@0: } michael@0: }, michael@0: bitmapData: { michael@0: get: function bitmapData() { michael@0: return this._bitmapData; michael@0: }, michael@0: set: setBitmapData michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var CACHE_DRAWABLE_AFTER = 10; michael@0: var BitmapDataDefinition = function () { michael@0: function replaceRect(ctx, x, y, w, h, alpha) { michael@0: if (alpha < 255) { michael@0: ctx.clearRect(x, y, w, h); michael@0: } michael@0: if (alpha > 0) { michael@0: ctx.fillRect(x, y, w, h); michael@0: } michael@0: } michael@0: var def = { michael@0: __class__: 'flash.display.BitmapData', michael@0: initialize: function () { michael@0: this._changeNotificationTarget = null; michael@0: this._locked = false; michael@0: this._requested = 0; michael@0: this._cache = null; michael@0: if (this.symbol) { michael@0: this._img = this.symbol.img; michael@0: this._skipCopyToCanvas = this.symbol.skipCopyToCanvas; michael@0: } michael@0: }, michael@0: _checkCanvas: function () { michael@0: if (this._drawable === null) michael@0: throw ArgumentError(); michael@0: }, michael@0: ctor: function (width, height, transparent, backgroundColor) { michael@0: if (this._img) { michael@0: width = this._img.naturalWidth || this._img.width; michael@0: height = this._img.naturalHeight || this._img.height; michael@0: } else if (isNaN(width + height) || width <= 0 || height <= 0) { michael@0: throwError('ArgumentError', Errors.ArgumentError); michael@0: } michael@0: this._transparent = transparent === undefined ? true : !(!transparent); michael@0: this._backgroundColor = backgroundColor === undefined ? 4294967295 : backgroundColor; michael@0: if (!this._transparent) { michael@0: this._backgroundColor |= 4278190080; michael@0: } michael@0: if (this._skipCopyToCanvas) { michael@0: this._drawable = this._img; michael@0: } else { michael@0: var canvas = document.createElement('canvas'); michael@0: this._ctx = canvas.getContext('2d'); michael@0: canvas.width = width | 0; michael@0: canvas.height = height | 0; michael@0: this._drawable = canvas; michael@0: if (!this._transparent || !this._img && this._backgroundColor) { michael@0: this.fillRect(new flash.geom.Rectangle(0, 0, width | 0, height | 0), this._backgroundColor); michael@0: } michael@0: if (this._img) { michael@0: this._ctx.drawImage(this._img, 0, 0); michael@0: } michael@0: } michael@0: }, michael@0: dispose: function () { michael@0: this._ctx = null; michael@0: this._drawable.width = 0; michael@0: this._drawable.height = 0; michael@0: this._drawable = null; michael@0: }, michael@0: draw: function (source, matrix, colorTransform, blendMode, clipRect, smoothing) { michael@0: this._checkCanvas(); michael@0: var ctx = this._ctx; michael@0: ctx.save(); michael@0: ctx.beginPath(); michael@0: if (clipRect && clipRect.width > 0 && clipRect.height > 0) { michael@0: ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); michael@0: ctx.clip(); michael@0: } michael@0: if (matrix) { michael@0: ctx.transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); michael@0: } michael@0: ctx.globalCompositeOperation = getBlendModeName(blendMode); michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = !(!smoothing); michael@0: if (flash.display.BitmapData.class.isInstanceOf(source)) { michael@0: ctx.drawImage(source._drawable, 0, 0); michael@0: } else { michael@0: new RenderVisitor(source, ctx, null, true).startFragment(matrix); michael@0: } michael@0: ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false; michael@0: ctx.restore(); michael@0: this._invalidate(); michael@0: }, michael@0: fillRect: function (rect, color) { michael@0: this._checkCanvas(); michael@0: if (!this._transparent) { michael@0: color |= 4278190080; michael@0: } michael@0: var ctx = this._ctx; michael@0: ctx.fillStyle = argbUintToStr(color); michael@0: replaceRect(ctx, rect.x, rect.y, rect.width, rect.height, color >>> 24 & 255); michael@0: this._invalidate(); michael@0: }, michael@0: getPixel: function (x, y) { michael@0: this._checkCanvas(); michael@0: var data = this._ctx.getImageData(x, y, 1, 1).data; michael@0: return dataToRGB(data); michael@0: }, michael@0: getPixel32: function (x, y) { michael@0: this._checkCanvas(); michael@0: var data = this._ctx.getImageData(x, y, 1, 1).data; michael@0: return dataToARGB(data); michael@0: }, michael@0: _invalidate: function (changeRect) { michael@0: if (changeRect) { michael@0: somewhatImplemented('BitmapData._invalidate(changeRect)'); michael@0: } michael@0: if (this._locked) { michael@0: return; michael@0: } michael@0: if (this._changeNotificationTarget) { michael@0: this._changeNotificationTarget._drawableChanged(); michael@0: } michael@0: this._requested = 0; michael@0: this._cache = null; michael@0: }, michael@0: _getDrawable: function () { michael@0: if (this._img === this._drawable) { michael@0: return this._drawable; michael@0: } michael@0: this._requested++; michael@0: if (this._requested >= CACHE_DRAWABLE_AFTER) { michael@0: if (!this._cache) { michael@0: Counter.count('Cache drawable'); michael@0: var img = document.createElement('img'); michael@0: if ('toBlob' in this._drawable) { michael@0: this._drawable.toBlob(function (blob) { michael@0: img.src = URL.createObjectURL(blob); michael@0: img.onload = function () { michael@0: URL.revokeObjectURL(blob); michael@0: }; michael@0: }); michael@0: } else { michael@0: img.src = this._drawable.toDataURL(); michael@0: } michael@0: this._cache = img; michael@0: } michael@0: if (this._cache.width > 0) { michael@0: return this._cache; michael@0: } michael@0: } michael@0: return this._drawable; michael@0: }, michael@0: setPixel: function (x, y, color) { michael@0: this.fillRect({ michael@0: x: x, michael@0: y: y, michael@0: width: 1, michael@0: height: 1 michael@0: }, color | 4278190080); michael@0: this._invalidate(); michael@0: }, michael@0: setPixel32: function (x, y, color) { michael@0: this.fillRect({ michael@0: x: x, michael@0: y: y, michael@0: width: 1, michael@0: height: 1 michael@0: }, color); michael@0: this._invalidate(); michael@0: }, michael@0: copyPixels: function copyPixels(sourceBitmapData, sourceRect, destPoint, alphaBitmapData, alphaPoint, mergeAlpha) { michael@0: if (alphaBitmapData) { michael@0: notImplemented('BitmapData.copyPixels w/ alpha'); michael@0: } michael@0: var w = sourceRect.width; michael@0: var h = sourceRect.height; michael@0: var sx = sourceRect.x; michael@0: var sy = sourceRect.y; michael@0: var dx = destPoint.x; michael@0: var dy = destPoint.y; michael@0: var offsetx = -Math.min(0, sx, dx); michael@0: var offsety = -Math.min(0, sy, dy); michael@0: var correctionw = Math.min(0, this._ctx.canvas.width - dx - w, sourceBitmapData._drawable.width - sx - w) - offsetx; michael@0: var correctionh = Math.min(0, this._ctx.canvas.height - dy - h, sourceBitmapData._drawable.height - sy - h) - offsety; michael@0: if (!mergeAlpha) { michael@0: this._ctx.clearRect(dx, dy, w, h); michael@0: } michael@0: if (w + correctionw > 0 && h + correctionh > 0) { michael@0: this._ctx.drawImage(sourceBitmapData._drawable, sx + offsetx, sy + offsety, w + correctionw, h + correctionh, dx + offsetx, dy + offsety, w + correctionw, h + correctionh); michael@0: } michael@0: this._invalidate(); michael@0: }, michael@0: lock: function lock() { michael@0: this._locked = true; michael@0: }, michael@0: unlock: function unlock(changeRect) { michael@0: this._locked = false; michael@0: this._invalidate(changeRect); michael@0: }, michael@0: clone: function () { michael@0: this._checkCanvas(); michael@0: var bd = new flash.display.BitmapData(this._drawable.width, this._drawable.height, true, 0); michael@0: bd._ctx.drawImage(this._drawable, 0, 0); michael@0: return bd; michael@0: }, michael@0: scroll: function (x, y) { michael@0: this._checkCanvas(); michael@0: this._ctx.draw(this._drawable, x, y); michael@0: this._ctx.save(); michael@0: var color = this._img ? 0 : this._backgroundColor; michael@0: if (!this._transparent) { michael@0: color |= 4278190080; michael@0: } michael@0: var alpha = color >>> 24 & 255; michael@0: this._ctx.fillStyle = argbUintToStr(color); michael@0: var w = this._drawable.width; michael@0: var h = this._drawable.height; michael@0: if (x > 0) { michael@0: replaceRect(this._ctx, 0, 0, x, h, alpha); michael@0: } else if (x < 0) { michael@0: replaceRect(this._ctx, w + x, 0, -x, h, alpha); michael@0: } michael@0: if (y > 0) { michael@0: replaceRect(this._ctx, 0, 0, w, y, alpha); michael@0: } else if (y < 0) { michael@0: replaceRect(this._ctx, h + y, w, -y, alpha); michael@0: } michael@0: this._ctx.restore(); michael@0: this._invalidate(); michael@0: }, michael@0: get width() { michael@0: return this._drawable.width; michael@0: }, michael@0: get height() { michael@0: return this._drawable.height; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: ctor: def.ctor, michael@0: fillRect: def.fillRect, michael@0: dispose: def.dispose, michael@0: getPixel: def.getPixel, michael@0: getPixel32: def.getPixel32, michael@0: setPixel: def.setPixel, michael@0: setPixel32: def.setPixel32, michael@0: copyPixels: def.copyPixels, michael@0: lock: def.lock, michael@0: unlock: def.unlock, michael@0: draw: def.draw, michael@0: clone: def.clone, michael@0: scroll: def.scroll, michael@0: width: desc(def, 'width'), michael@0: height: desc(def, 'height') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: function dataToRGB(data) { michael@0: return data[0] << 16 | data[1] << 8 | data[2]; michael@0: } michael@0: function dataToARGB(data) { michael@0: return data[3] << 24 | dataToRGB(data); michael@0: } michael@0: var DisplayObjectDefinition = function () { michael@0: var blendModes; michael@0: var nextInstanceId = 1; michael@0: function generateName() { michael@0: return 'instance' + nextInstanceId++; michael@0: } michael@0: var broadcastedEvents = { michael@0: advanceFrame: false, michael@0: enterFrame: true, michael@0: constructChildren: false, michael@0: frameConstructed: true, michael@0: executeFrame: false, michael@0: exitFrame: true, michael@0: render: true michael@0: }; michael@0: var point = { michael@0: x: 0, michael@0: y: 0 michael@0: }; michael@0: var def = { michael@0: __class__: 'flash.display.DisplayObject', michael@0: initialize: function () { michael@0: var blendModeClass = flash.display.BlendMode.class; michael@0: this._alpha = 1; michael@0: this._animated = false; michael@0: this._bbox = null; michael@0: this._bitmap = null; michael@0: this._blendMode = blendModeClass.NORMAL; michael@0: this._bounds = { michael@0: xMin: 0, michael@0: xMax: 0, michael@0: yMin: 0, michael@0: yMax: 0, michael@0: invalid: true michael@0: }; michael@0: this._cacheAsBitmap = false; michael@0: this._children = []; michael@0: this._clipDepth = null; michael@0: this._currentTransform = { michael@0: a: 1, michael@0: b: 0, michael@0: c: 0, michael@0: d: 1, michael@0: tx: 0, michael@0: ty: 0 michael@0: }; michael@0: this._concatenatedTransform = { michael@0: a: 1, michael@0: b: 0, michael@0: c: 0, michael@0: d: 1, michael@0: tx: 0, michael@0: ty: 0, michael@0: invalid: true michael@0: }; michael@0: this._current3DTransform = null; michael@0: this._cxform = null; michael@0: this._graphics = null; michael@0: this._filters = []; michael@0: this._loader = null; michael@0: this._mouseChildren = true; michael@0: this._mouseOver = false; michael@0: this._mouseX = 0; michael@0: this._mouseY = 0; michael@0: this._name = null; michael@0: this._opaqueBackground = null; michael@0: this._owned = false; michael@0: this._parent = null; michael@0: this._rotation = 0; michael@0: this._rotationCos = 1; michael@0: this._rotationSin = 0; michael@0: this._scale9Grid = null; michael@0: this._scaleX = 1; michael@0: this._scaleY = 1; michael@0: this._stage = null; michael@0: this._visible = true; michael@0: this._hidden = false; michael@0: this._wasCachedAsBitmap = false; michael@0: this._destroyed = false; michael@0: this._maskedObject = null; michael@0: this._scrollRect = null; michael@0: this._invalid = false; michael@0: this._region = null; michael@0: this._level = -1; michael@0: this._index = -1; michael@0: this._depth = -1; michael@0: this._isContainer = false; michael@0: this._invisible = false; michael@0: this._zindex = 0; michael@0: blendModes = [ michael@0: blendModeClass.NORMAL, michael@0: blendModeClass.NORMAL, michael@0: blendModeClass.LAYER, michael@0: blendModeClass.MULTIPLY, michael@0: blendModeClass.SCREEN, michael@0: blendModeClass.LIGHTEN, michael@0: blendModeClass.DARKEN, michael@0: blendModeClass.DIFFERENCE, michael@0: blendModeClass.ADD, michael@0: blendModeClass.SUBTRACT, michael@0: blendModeClass.INVERT, michael@0: blendModeClass.ALPHA, michael@0: blendModeClass.ERASE, michael@0: blendModeClass.OVERLAY, michael@0: blendModeClass.HARDLIGHT, michael@0: blendModeClass.SHADER michael@0: ]; michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this._animated = s.animated || false; michael@0: this._bbox = s.bbox || null; michael@0: this._blendMode = this._resolveBlendMode(s.blendMode); michael@0: this._children = s.children || []; michael@0: this._clipDepth = s.clipDepth || null; michael@0: this._cxform = s.cxform || null; michael@0: this._loader = s.loader || null; michael@0: this._name = s.name || null; michael@0: this._owned = s.owned || false; michael@0: this._parent = s.parent || null; michael@0: this._level = isNaN(s.level) ? -1 : s.level; michael@0: this._index = isNaN(s.index) ? -1 : s.index; michael@0: this._depth = isNaN(s.depth) ? -1 : s.depth; michael@0: this._root = s.root || null; michael@0: this._stage = s.stage || null; michael@0: var scale9Grid = s.scale9Grid; michael@0: if (scale9Grid) { michael@0: this._scale9Grid = new flash.geom.Rectangle(scale9Grid.left, scale9Grid.top, scale9Grid.right - scale9Grid.left, scale9Grid.bottom - scale9Grid.top); michael@0: } michael@0: var matrix = s.currentTransform; michael@0: if (matrix) { michael@0: this._setTransformMatrix(matrix, false); michael@0: } michael@0: } michael@0: this._accessibilityProperties = null; michael@0: var self = this; michael@0: this._onBroadcastMessage = function (type) { michael@0: var listeners = self._listeners; michael@0: if (listeners[type]) { michael@0: self._dispatchEvent(type); michael@0: } michael@0: }; michael@0: }, michael@0: _addEventListener: function addEventListener(type, listener, useCapture, priority) { michael@0: if (broadcastedEvents[type] === false) { michael@0: avm2.systemDomain.onMessage.register(type, listener); michael@0: return; michael@0: } michael@0: if (type in broadcastedEvents && !this._listeners[type]) { michael@0: avm2.systemDomain.onMessage.register(type, this._onBroadcastMessage); michael@0: } michael@0: this._addEventListenerImpl(type, listener, useCapture, priority); michael@0: }, michael@0: _removeEventListener: function addEventListener(type, listener, useCapture) { michael@0: if (broadcastedEvents[type] === false) { michael@0: avm2.systemDomain.onMessage.unregister(type, listener); michael@0: return; michael@0: } michael@0: this._removeEventListenerImpl(type, listener, useCapture); michael@0: if (type in broadcastedEvents && !this._listeners[type]) { michael@0: avm2.systemDomain.onMessage.unregister(type, this._onBroadcastMessage); michael@0: } michael@0: }, michael@0: _resolveBlendMode: function (blendModeNumeric) { michael@0: return blendModes[blendModeNumeric] || flash.display.BlendMode.class.NORMAL; michael@0: }, michael@0: _getConcatenatedTransform: function (targetCoordSpace, toDeviceSpace) { michael@0: var stage = this._stage; michael@0: if (this === this._stage) { michael@0: return toDeviceSpace ? this._concatenatedTransform : this._currentTransform; michael@0: } michael@0: if (targetCoordSpace === this._parent) { michael@0: return this._currentTransform; michael@0: } michael@0: var invalidNode = null; michael@0: var m, m2, targetCoordMatrix; michael@0: var currentNode = this; michael@0: while (currentNode !== stage) { michael@0: if (currentNode._concatenatedTransform.invalid) { michael@0: invalidNode = currentNode; michael@0: } michael@0: if (currentNode === targetCoordSpace) { michael@0: targetCoordMatrix = currentNode._concatenatedTransform; michael@0: } michael@0: currentNode = currentNode._parent; michael@0: } michael@0: if (invalidNode) { michael@0: if (this._parent === stage) { michael@0: m = this._concatenatedTransform; michael@0: m2 = this._currentTransform; michael@0: m.a = m2.a; michael@0: m.b = m2.b; michael@0: m.c = m2.c; michael@0: m.d = m2.d; michael@0: m.tx = m2.tx; michael@0: m.ty = m2.ty; michael@0: } else { michael@0: var stack = []; michael@0: var currentNode = this; michael@0: while (currentNode !== invalidNode) { michael@0: stack.push(currentNode); michael@0: currentNode = currentNode._parent; michael@0: } michael@0: var node = invalidNode; michael@0: do { michael@0: var parent = node._parent; michael@0: m = node._concatenatedTransform; michael@0: m2 = node._currentTransform; michael@0: if (parent) { michael@0: if (parent !== stage) { michael@0: var m3 = parent._concatenatedTransform; michael@0: m.a = m2.a * m3.a + m2.b * m3.c; michael@0: m.b = m2.a * m3.b + m2.b * m3.d; michael@0: m.c = m2.c * m3.a + m2.d * m3.c; michael@0: m.d = m2.d * m3.d + m2.c * m3.b; michael@0: m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c; michael@0: m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b; michael@0: } michael@0: } else { michael@0: m.a = m2.a; michael@0: m.b = m2.b; michael@0: m.c = m2.c; michael@0: m.d = m2.d; michael@0: m.tx = m2.tx; michael@0: m.ty = m2.ty; michael@0: } michael@0: m.invalid = false; michael@0: var nextNode = stack.pop(); michael@0: var children = node._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var child = children[i]; michael@0: if (child !== nextNode) { michael@0: child._concatenatedTransform.invalid = true; michael@0: } michael@0: } michael@0: node = nextNode; michael@0: } while (node); michael@0: } michael@0: } else { michael@0: m = this._concatenatedTransform; michael@0: } michael@0: if (targetCoordSpace && targetCoordSpace !== this._stage) { michael@0: m2 = targetCoordMatrix || targetCoordSpace._getConcatenatedTransform(null, false); michael@0: var a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0; michael@0: if (m2.b || m2.c) { michael@0: var det = 1 / (m2.a * m2.d - m2.b * m2.c); michael@0: a = m2.d * det; michael@0: b = -m2.b * det; michael@0: c = -m2.c * det; michael@0: d = m2.a * det; michael@0: tx = -(a * m2.tx + c * m2.ty); michael@0: ty = -(b * m2.tx + d * m2.ty); michael@0: } else { michael@0: a = 1 / m2.a; michael@0: d = 1 / m2.d; michael@0: tx = m2.tx * -a; michael@0: ty = m2.ty * -d; michael@0: } michael@0: return { michael@0: a: a * m.a + c * m.b, michael@0: b: b * m.a + d * m.b, michael@0: c: a * m.c + c * m.d, michael@0: d: b * m.c + d * m.d, michael@0: tx: a * m.tx + c * m.ty + tx, michael@0: ty: b * m.tx + d * m.ty + ty michael@0: }; michael@0: } michael@0: if (toDeviceSpace && stage) { michael@0: m2 = stage._concatenatedTransform; michael@0: return { michael@0: a: m.a * m2.a, michael@0: b: m.b * m2.d, michael@0: c: m.c * m2.a, michael@0: d: m.d * m2.d, michael@0: tx: m.tx * m2.a + m2.tx, michael@0: ty: m.ty * m2.d + m2.ty michael@0: }; michael@0: } michael@0: return m; michael@0: }, michael@0: _applyCurrentTransform: function (pt) { michael@0: var m = this._getConcatenatedTransform(null, false); michael@0: var x = pt.x; michael@0: var y = pt.y; michael@0: pt.x = m.a * x + m.c * y + m.tx | 0; michael@0: pt.y = m.d * y + m.b * x + m.ty | 0; michael@0: }, michael@0: _applyConcatenatedInverseTransform: function (pt) { michael@0: var m = this._getConcatenatedTransform(null, false); michael@0: var det = 1 / (m.a * m.d - m.b * m.c); michael@0: var x = pt.x - m.tx; michael@0: var y = pt.y - m.ty; michael@0: pt.x = (m.d * x - m.c * y) * det | 0; michael@0: pt.y = (m.a * y - m.b * x) * det | 0; michael@0: }, michael@0: _hitTest: function (use_xy, x, y, useShape, hitTestObject) { michael@0: if (use_xy) { michael@0: point.x = x; michael@0: point.y = y; michael@0: this._applyConcatenatedInverseTransform(point); michael@0: var b = this._getContentBounds(); michael@0: if (!(point.x >= b.xMin && point.x < b.xMax && point.y >= b.yMin && point.y < b.yMax)) { michael@0: return false; michael@0: } michael@0: if (!useShape || !this._graphics) { michael@0: return true; michael@0: } michael@0: if (this._graphics) { michael@0: var subpaths = this._graphics._paths; michael@0: for (var i = 0, n = subpaths.length; i < n; i++) { michael@0: var path = subpaths[i]; michael@0: if (path.isPointInPath(point.x, point.y)) { michael@0: return true; michael@0: } michael@0: if (path.strokeStyle) { michael@0: var strokePath = path._strokePath; michael@0: if (!strokePath) { michael@0: strokePath = path.strokePath(path.drawingStyles); michael@0: path._strokePath = strokePath; michael@0: } michael@0: if (strokePath.isPointInPath(point.x, point.y)) { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: var children = this._children; michael@0: for (var i = 0, n = children.length; i < n; i++) { michael@0: var child = children[i]; michael@0: if (child._hitTest && child._hitTest(true, x, y, true, null)) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: var b1 = this.getBounds(this._stage); michael@0: var b2 = hitTestObject.getBounds(hitTestObject._stage); michael@0: x = Math.max(b1.xMin, b2.xMin); michael@0: y = Math.max(b1.yMin, b2.yMin); michael@0: var width = Math.min(b1.xMax, b2.xMax) - x; michael@0: var height = Math.min(b1.yMax, b2.yMax) - y; michael@0: return width > 0 && height > 0; michael@0: }, michael@0: _invalidate: function () { michael@0: this._invalid = true; michael@0: }, michael@0: _invalidateBounds: function () { michael@0: var currentNode = this; michael@0: while (currentNode && !currentNode._bounds.invalid) { michael@0: currentNode._bounds.invalid = true; michael@0: currentNode = currentNode._parent; michael@0: } michael@0: }, michael@0: _invalidateTransform: function () { michael@0: this._concatenatedTransform.invalid = true; michael@0: if (this._parent) { michael@0: this._parent._invalidateBounds(); michael@0: } michael@0: }, michael@0: _setTransformMatrix: function (matrix, convertToTwips) { michael@0: var a = matrix.a; michael@0: var b = matrix.b; michael@0: var c = matrix.c; michael@0: var d = matrix.d; michael@0: var tx, ty; michael@0: if (convertToTwips) { michael@0: tx = matrix.tx * 20 | 0; michael@0: ty = matrix.ty * 20 | 0; michael@0: } else { michael@0: tx = matrix.tx; michael@0: ty = matrix.ty; michael@0: } michael@0: var angle = a !== 0 ? Math.atan(b / a) : b > 0 ? Math.PI / 2 : -Math.PI / 2; michael@0: this._rotation = angle * 180 / Math.PI; michael@0: this._rotationCos = Math.cos(angle); michael@0: this._rotationSin = Math.sin(angle); michael@0: var sx = Math.sqrt(a * a + b * b); michael@0: this._scaleX = a > 0 ? sx : -sx; michael@0: var sy = Math.sqrt(d * d + c * c); michael@0: this._scaleY = d > 0 ? sy : -sy; michael@0: var transform = this._currentTransform; michael@0: transform.a = a; michael@0: transform.b = b; michael@0: transform.c = c; michael@0: transform.d = d; michael@0: transform.tx = tx; michael@0: transform.ty = ty; michael@0: this._invalidateTransform(); michael@0: }, michael@0: get accessibilityProperties() { michael@0: return this._accessibilityProperties; michael@0: }, michael@0: set accessibilityProperties(val) { michael@0: this._accessibilityProperties = val; michael@0: }, michael@0: get alpha() { michael@0: return this._alpha; michael@0: }, michael@0: set alpha(val) { michael@0: if (val === this._alpha) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: this._alpha = val; michael@0: this._animated = false; michael@0: }, michael@0: get blendMode() { michael@0: return this._blendMode; michael@0: }, michael@0: set blendMode(val) { michael@0: if (blendModes.indexOf(val) >= 0) { michael@0: this._blendMode = val; michael@0: } else { michael@0: throwError('ArgumentError', Errors.InvalidEnumError, 'blendMode'); michael@0: } michael@0: this._animated = false; michael@0: }, michael@0: get cacheAsBitmap() { michael@0: return this._cacheAsBitmap; michael@0: }, michael@0: set cacheAsBitmap(val) { michael@0: this._cacheAsBitmap = this._filters.length ? true : val; michael@0: this._animated = false; michael@0: }, michael@0: get filters() { michael@0: return this._filters; michael@0: }, michael@0: set filters(val) { michael@0: if (val.length) { michael@0: if (!this._filters.length) michael@0: this._wasCachedAsBitmap = this._cacheAsBitmap; michael@0: this._cacheAsBitmap = true; michael@0: } else { michael@0: this._cacheAsBitmap = this._wasCachedAsBitmap; michael@0: } michael@0: this._filters = val; michael@0: this._animated = false; michael@0: }, michael@0: get height() { michael@0: var bounds = this._getContentBounds(); michael@0: var t = this._currentTransform; michael@0: return Math.abs(t.b) * (bounds.xMax - bounds.xMin) + Math.abs(t.d) * (bounds.yMax - bounds.yMin) | 0; michael@0: }, michael@0: set height(val) { michael@0: if (val < 0) { michael@0: return; michael@0: } michael@0: var u = Math.abs(this._rotationCos); michael@0: var v = Math.abs(this._rotationSin); michael@0: var bounds = this._getContentBounds(); michael@0: var baseHeight = v * (bounds.xMax - bounds.xMin) + u * (bounds.yMax - bounds.yMin); michael@0: if (!baseHeight) { michael@0: return; michael@0: } michael@0: var baseWidth = u * (bounds.xMax - bounds.xMin) + v * (bounds.yMax - bounds.yMin); michael@0: this.scaleX = this.width / baseWidth; michael@0: this.scaleY = val / baseHeight; michael@0: }, michael@0: get loaderInfo() { michael@0: return this._loader && this._loader._contentLoaderInfo || this._parent.loaderInfo; michael@0: }, michael@0: get mask() { michael@0: return this._mask; michael@0: }, michael@0: set mask(val) { michael@0: if (this._mask === val) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: if (val && val._maskedObject) { michael@0: val._maskedObject.mask = null; michael@0: } michael@0: this._mask = val; michael@0: if (val) { michael@0: val._maskedObject = this; michael@0: } michael@0: this._animated = false; michael@0: }, michael@0: get name() { michael@0: return this._name || (this._name = generateName()); michael@0: }, michael@0: set name(val) { michael@0: this._name = val; michael@0: }, michael@0: get mouseX() { michael@0: if (!this._stage) { michael@0: return 0; michael@0: } michael@0: point.x = this._stage._mouseX; michael@0: point.y = this._stage._mouseY; michael@0: this._applyConcatenatedInverseTransform(point); michael@0: return point.x; michael@0: }, michael@0: get mouseY() { michael@0: if (!this._stage) { michael@0: return 0; michael@0: } michael@0: point.x = this._stage._mouseX; michael@0: point.y = this._stage._mouseY; michael@0: this._applyConcatenatedInverseTransform(point); michael@0: return point.y; michael@0: }, michael@0: get opaqueBackground() { michael@0: return this._opaqueBackground; michael@0: }, michael@0: set opaqueBackground(val) { michael@0: this._opaqueBackground = val; michael@0: this._animated = false; michael@0: }, michael@0: get parent() { michael@0: return this._index > -1 ? this._parent : null; michael@0: }, michael@0: get root() { michael@0: return this._stage && this._stage._root; michael@0: }, michael@0: get rotation() { michael@0: return this._rotation; michael@0: }, michael@0: set rotation(val) { michael@0: val %= 360; michael@0: if (val > 180) { michael@0: val -= 360; michael@0: } michael@0: if (val === this._rotation) michael@0: return; michael@0: this._invalidate(); michael@0: this._invalidateTransform(); michael@0: this._rotation = val; michael@0: var u, v; michael@0: switch (val) { michael@0: case 0: michael@0: case 360: michael@0: u = 1, v = 0; michael@0: break; michael@0: case 90: michael@0: case -270: michael@0: u = 0, v = 1; michael@0: break; michael@0: case 180: michael@0: case -180: michael@0: u = -1, v = 0; michael@0: break; michael@0: case 270: michael@0: case -90: michael@0: u = 0, v = -1; michael@0: break; michael@0: default: michael@0: var angle = this._rotation / 180 * Math.PI; michael@0: u = Math.cos(angle); michael@0: v = Math.sin(angle); michael@0: break; michael@0: } michael@0: this._rotationCos = u; michael@0: this._rotationSin = v; michael@0: var m = this._currentTransform; michael@0: m.a = u * this._scaleX; michael@0: m.b = v * this._scaleX; michael@0: m.c = -v * this._scaleY; michael@0: m.d = u * this._scaleY; michael@0: this._animated = false; michael@0: }, michael@0: get rotationX() { michael@0: return 0; michael@0: }, michael@0: set rotationX(val) { michael@0: somewhatImplemented('DisplayObject.rotationX'); michael@0: }, michael@0: get rotationY() { michael@0: return 0; michael@0: }, michael@0: set rotationY(val) { michael@0: somewhatImplemented('DisplayObject.rotationY'); michael@0: }, michael@0: get rotationZ() { michael@0: return this.rotation; michael@0: }, michael@0: set rotationZ(val) { michael@0: this.rotation = val; michael@0: somewhatImplemented('DisplayObject.rotationZ'); michael@0: }, michael@0: get stage() { michael@0: return this._stage; michael@0: }, michael@0: get scaleX() { michael@0: return this._scaleX; michael@0: }, michael@0: set scaleX(val) { michael@0: if (val === this._scaleX) michael@0: return; michael@0: this._invalidate(); michael@0: this._invalidateTransform(); michael@0: this._scaleX = val; michael@0: var m = this._currentTransform; michael@0: m.a = this._rotationCos * val; michael@0: m.b = this._rotationSin * val; michael@0: this._animated = false; michael@0: }, michael@0: get scaleY() { michael@0: return this._scaleY; michael@0: }, michael@0: set scaleY(val) { michael@0: if (val === this._scaleY) michael@0: return; michael@0: this._invalidate(); michael@0: this._invalidateTransform(); michael@0: this._scaleY = val; michael@0: var m = this._currentTransform; michael@0: m.c = -this._rotationSin * val; michael@0: m.d = this._rotationCos * val; michael@0: this._animated = false; michael@0: }, michael@0: get scaleZ() { michael@0: return 1; michael@0: }, michael@0: set scaleZ(val) { michael@0: somewhatImplemented('DisplayObject.scaleZ'); michael@0: }, michael@0: get scale9Grid() { michael@0: return this._scale9Grid; michael@0: }, michael@0: set scale9Grid(val) { michael@0: somewhatImplemented('DisplayObject.scale9Grid'); michael@0: this._scale9Grid = val; michael@0: this._animated = false; michael@0: }, michael@0: get scrollRect() { michael@0: return this._scrollRect; michael@0: }, michael@0: set scrollRect(val) { michael@0: somewhatImplemented('DisplayObject.scrollRect'); michael@0: this._scrollRect = val; michael@0: }, michael@0: get transform() { michael@0: return new flash.geom.Transform(this); michael@0: }, michael@0: set transform(val) { michael@0: var transform = this.transform; michael@0: transform.colorTransform = val.colorTransform; michael@0: if (val.matrix3D) { michael@0: transform.matrix3D = val.matrix3D; michael@0: } else { michael@0: transform.matrix = val.matrix; michael@0: } michael@0: }, michael@0: get visible() { michael@0: return this._visible; michael@0: }, michael@0: set visible(val) { michael@0: if (val === this._visible) michael@0: return; michael@0: this._invalidate(); michael@0: this._visible = val; michael@0: this._animated = false; michael@0: }, michael@0: get width() { michael@0: var bounds = this._getContentBounds(); michael@0: var t = this._currentTransform; michael@0: return Math.abs(t.a) * (bounds.xMax - bounds.xMin) + Math.abs(t.c) * (bounds.yMax - bounds.yMin) | 0; michael@0: }, michael@0: set width(val) { michael@0: if (val < 0) { michael@0: return; michael@0: } michael@0: var u = Math.abs(this._rotationCos); michael@0: var v = Math.abs(this._rotationSin); michael@0: var bounds = this._getContentBounds(); michael@0: var baseWidth = u * (bounds.xMax - bounds.xMin) + v * (bounds.yMax - bounds.yMin); michael@0: if (!baseWidth) { michael@0: return; michael@0: } michael@0: var baseHeight = v * (bounds.xMax - bounds.xMin) + u * (bounds.yMax - bounds.yMin); michael@0: this.scaleY = this.height / baseHeight; michael@0: this.scaleX = val / baseWidth; michael@0: }, michael@0: get x() { michael@0: return this._currentTransform.tx; michael@0: }, michael@0: set x(val) { michael@0: if (val === this._currentTransform.tx) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: this._invalidateTransform(); michael@0: this._currentTransform.tx = val; michael@0: this._animated = false; michael@0: }, michael@0: get y() { michael@0: return this._currentTransform.ty; michael@0: }, michael@0: set y(val) { michael@0: if (val === this._currentTransform.ty) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: this._invalidateTransform(); michael@0: this._currentTransform.ty = val; michael@0: this._animated = false; michael@0: }, michael@0: get z() { michael@0: return 0; michael@0: }, michael@0: set z(val) { michael@0: somewhatImplemented('DisplayObject.z'); michael@0: }, michael@0: _getContentBounds: function () { michael@0: var bounds = this._bounds; michael@0: if (bounds.invalid) { michael@0: var bbox = this._bbox; michael@0: var xMin = Number.MAX_VALUE; michael@0: var xMax = Number.MIN_VALUE; michael@0: var yMin = Number.MAX_VALUE; michael@0: var yMax = Number.MIN_VALUE; michael@0: if (bbox) { michael@0: xMin = bbox.xMin; michael@0: xMax = bbox.xMax; michael@0: yMin = bbox.yMin; michael@0: yMax = bbox.yMax; michael@0: } else { michael@0: var children = this._children; michael@0: var numChildren = children.length; michael@0: for (var i = 0; i < numChildren; i++) { michael@0: var child = children[i]; michael@0: if (!flash.display.DisplayObject.class.isInstanceOf(child)) { michael@0: continue; michael@0: } michael@0: var b = child.getBounds(this); michael@0: var x1 = b.xMin; michael@0: var y1 = b.yMin; michael@0: var x2 = b.xMax; michael@0: var y2 = b.yMax; michael@0: xMin = Math.min(xMin, x1, x2); michael@0: xMax = Math.max(xMax, x1, x2); michael@0: yMin = Math.min(yMin, y1, y2); michael@0: yMax = Math.max(yMax, y1, y2); michael@0: } michael@0: if (this._graphics) { michael@0: var b = this._graphics._getBounds(true); michael@0: if (b.xMin !== b.xMax && b.yMin !== b.yMax) { michael@0: var x1 = b.xMin; michael@0: var y1 = b.yMin; michael@0: var x2 = b.xMax; michael@0: var y2 = b.yMax; michael@0: xMin = Math.min(xMin, x1, x2); michael@0: xMax = Math.max(xMax, x1, x2); michael@0: yMin = Math.min(yMin, y1, y2); michael@0: yMax = Math.max(yMax, y1, y2); michael@0: } michael@0: } michael@0: } michael@0: if (xMin === Number.MAX_VALUE) { michael@0: xMin = xMax = yMin = yMax = 0; michael@0: } michael@0: bounds.xMin = xMin; michael@0: bounds.xMax = xMax; michael@0: bounds.yMin = yMin; michael@0: bounds.yMax = yMax; michael@0: bounds.invalid = false; michael@0: } michael@0: return bounds; michael@0: }, michael@0: _getRegion: function getRegion(targetCoordSpace) { michael@0: var b; michael@0: var filters = this._filters; michael@0: if (filters.length) { michael@0: var xMin = Number.MAX_VALUE; michael@0: var xMax = Number.MIN_VALUE; michael@0: var yMin = Number.MAX_VALUE; michael@0: var yMax = Number.MIN_VALUE; michael@0: if (this._graphics) { michael@0: b = this._graphics._getBounds(true); michael@0: if (b) { michael@0: xMin = b.xMin; michael@0: xMax = b.xMax; michael@0: yMin = b.yMin; michael@0: yMax = b.yMax; michael@0: } michael@0: } michael@0: var children = this._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var child = children[i]; michael@0: b = children[i]._getRegion(this); michael@0: if (b.xMin < xMin) { michael@0: xMin = b.xMin; michael@0: } michael@0: if (b.xMax > xMax) { michael@0: xMax = b.xMax; michael@0: } michael@0: if (b.yMin < yMin) { michael@0: yMin = b.yMin; michael@0: } michael@0: if (b.yMax > yMax) { michael@0: yMax = b.yMax; michael@0: } michael@0: } michael@0: if (xMin === Number.MAX_VALUE) { michael@0: return { michael@0: xMin: 0, michael@0: xMax: 0, michael@0: yMin: 0, michael@0: yMax: 0 michael@0: }; michael@0: } michael@0: b = { michael@0: xMin: xMin, michael@0: xMax: xMax, michael@0: yMin: yMin, michael@0: yMax: yMax michael@0: }; michael@0: for (var i = 0; i < filters.length; i++) { michael@0: filters[i]._updateFilterBounds(b); michael@0: } michael@0: } else { michael@0: b = this._graphics ? this._graphics._getBounds(true) : this._getContentBounds(); michael@0: } michael@0: return this._getTransformedRect(b, targetCoordSpace); michael@0: }, michael@0: getBounds: function (targetCoordSpace) { michael@0: return this._getTransformedRect(this._getContentBounds(), targetCoordSpace); michael@0: }, michael@0: _getTransformedRect: function (rect, targetCoordSpace) { michael@0: if (!targetCoordSpace || targetCoordSpace === this) { michael@0: return rect; michael@0: } michael@0: var xMin = rect.xMin; michael@0: var xMax = rect.xMax; michael@0: var yMin = rect.yMin; michael@0: var yMax = rect.yMax; michael@0: if (xMax - xMin === 0 || yMax - yMin === 0) { michael@0: return { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: 0, michael@0: yMax: 0 michael@0: }; michael@0: } michael@0: var m = targetCoordSpace && !flash.display.DisplayObject.class.isInstanceOf(targetCoordSpace) ? targetCoordSpace : this._getConcatenatedTransform(targetCoordSpace, false); michael@0: var x0 = m.a * xMin + m.c * yMin + m.tx | 0; michael@0: var y0 = m.b * xMin + m.d * yMin + m.ty | 0; michael@0: var x1 = m.a * xMax + m.c * yMin + m.tx | 0; michael@0: var y1 = m.b * xMax + m.d * yMin + m.ty | 0; michael@0: var x2 = m.a * xMax + m.c * yMax + m.tx | 0; michael@0: var y2 = m.b * xMax + m.d * yMax + m.ty | 0; michael@0: var x3 = m.a * xMin + m.c * yMax + m.tx | 0; michael@0: var y3 = m.b * xMin + m.d * yMax + m.ty | 0; michael@0: var tmp = 0; michael@0: if (x0 > x1) { michael@0: tmp = x0; michael@0: x0 = x1; michael@0: x1 = tmp; michael@0: } michael@0: if (x2 > x3) { michael@0: tmp = x2; michael@0: x2 = x3; michael@0: x3 = tmp; michael@0: } michael@0: xMin = x0 < x2 ? x0 : x2; michael@0: xMax = x1 > x3 ? x1 : x3; michael@0: if (y0 > y1) { michael@0: tmp = y0; michael@0: y0 = y1; michael@0: y1 = tmp; michael@0: } michael@0: if (y2 > y3) { michael@0: tmp = y2; michael@0: y2 = y3; michael@0: y3 = tmp; michael@0: } michael@0: yMin = y0 < y2 ? y0 : y2; michael@0: yMax = y1 > y3 ? y1 : y3; michael@0: return { michael@0: xMin: xMin, michael@0: yMin: yMin, michael@0: xMax: xMax, michael@0: yMax: yMax michael@0: }; michael@0: }, michael@0: hitTestObject: function (obj) { michael@0: return this._hitTest(false, 0, 0, false, obj); michael@0: }, michael@0: hitTestPoint: function (x, y, shapeFlag) { michael@0: return this._hitTest(true, x, y, shapeFlag, null); michael@0: }, michael@0: destroy: function () { michael@0: if (this._destroyed) { michael@0: return; michael@0: } michael@0: this._destroyed = true; michael@0: this.cleanupBroadcastListeners(); michael@0: }, michael@0: cleanupBroadcastListeners: function () { michael@0: var listenerLists = this._listeners; michael@0: for (var type in listenerLists) { michael@0: avm2.systemDomain.onMessage.unregister(type, this._onBroadcastMessage); michael@0: } michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: root: desc(def, 'root'), michael@0: stage: desc(def, 'stage'), michael@0: name: desc(def, 'name'), michael@0: parent: desc(def, 'parent'), michael@0: mask: desc(def, 'mask'), michael@0: visible: desc(def, 'visible'), michael@0: x: { michael@0: get: function x() { michael@0: return this.x / 20; michael@0: }, michael@0: set: function x(value) { michael@0: this.x = value * 20 | 0; michael@0: } michael@0: }, michael@0: y: { michael@0: get: function y() { michael@0: return this.y / 20; michael@0: }, michael@0: set: function y(value) { michael@0: this.y = value * 20 | 0; michael@0: } michael@0: }, michael@0: z: { michael@0: get: function z() { michael@0: return this.z / 20; michael@0: }, michael@0: set: function z(value) { michael@0: this.z = value * 20 | 0; michael@0: } michael@0: }, michael@0: scaleX: desc(def, 'scaleX'), michael@0: scaleY: desc(def, 'scaleY'), michael@0: scaleZ: desc(def, 'scaleZ'), michael@0: mouseX: { michael@0: get: function mouseX() { michael@0: return this.mouseX / 20; michael@0: }, michael@0: set: function mouseX(value) { michael@0: this.mouseX = value * 20 | 0; michael@0: } michael@0: }, michael@0: mouseY: { michael@0: get: function mouseY() { michael@0: return this.mouseY / 20; michael@0: }, michael@0: set: function mouseY(value) { michael@0: this.mouseY = value * 20 | 0; michael@0: } michael@0: }, michael@0: rotation: desc(def, 'rotation'), michael@0: rotationX: desc(def, 'rotationX'), michael@0: rotationY: desc(def, 'rotationY'), michael@0: rotationZ: desc(def, 'rotationZ'), michael@0: alpha: desc(def, 'alpha'), michael@0: width: { michael@0: get: function width() { michael@0: return this.width / 20; michael@0: }, michael@0: set: function width(value) { michael@0: this.width = value * 20 | 0; michael@0: } michael@0: }, michael@0: height: { michael@0: get: function height() { michael@0: return this.height / 20; michael@0: }, michael@0: set: function height(value) { michael@0: this.height = value * 20 | 0; michael@0: } michael@0: }, michael@0: _hitTest: function (use_xy, x, y, useShape, hitTestObject) { michael@0: x = x * 20 | 0; michael@0: y = y * 20 | 0; michael@0: return this._hitTest(use_xy, x, y, useShape, hitTestObject); michael@0: }, michael@0: cacheAsBitmap: desc(def, 'cacheAsBitmap'), michael@0: opaqueBackground: desc(def, 'opaqueBackground'), michael@0: scrollRect: desc(def, 'scrollRect'), michael@0: filters: desc(def, 'filters'), michael@0: blendMode: desc(def, 'blendMode'), michael@0: transform: desc(def, 'transform'), michael@0: scale9Grid: desc(def, 'scale9Grid'), michael@0: loaderInfo: desc(def, 'loaderInfo'), michael@0: accessibilityProperties: desc(def, 'accessibilityProperties'), michael@0: globalToLocal: function (pt) { michael@0: point.x = pt.x * 20 | 0; michael@0: point.y = pt.y * 20 | 0; michael@0: this._applyConcatenatedInverseTransform(point); michael@0: return new flash.geom.Point(point.x / 20, point.y / 20); michael@0: }, michael@0: localToGlobal: function (pt) { michael@0: point.x = pt.x * 20 | 0; michael@0: point.y = pt.y * 20 | 0; michael@0: this._applyCurrentTransform(point); michael@0: return new flash.geom.Point(point.x / 20, point.y / 20); michael@0: }, michael@0: getBounds: function (targetCoordSpace) { michael@0: var bounds = this.getBounds(targetCoordSpace); michael@0: return new flash.geom.Rectangle(bounds.xMin / 20, bounds.yMin / 20, (bounds.xMax - bounds.xMin) / 20, (bounds.yMax - bounds.yMin) / 20); michael@0: }, michael@0: getRect: function (targetCoordSpace) { michael@0: somewhatImplemented('DisplayObject.getRect'); michael@0: var bounds = this.getBounds(targetCoordSpace); michael@0: return new flash.geom.Rectangle(bounds.xMin / 20, bounds.yMin / 20, (bounds.xMax - bounds.xMin) / 20, (bounds.yMax - bounds.yMin) / 20); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var DisplayObjectContainerDefinition = function () { michael@0: var def = { michael@0: get mouseChildren() { michael@0: return this._mouseChildren; michael@0: }, michael@0: set mouseChildren(val) { michael@0: this._mouseChildren = val; michael@0: }, michael@0: get numChildren() { michael@0: return this._children.length; michael@0: }, michael@0: get tabChildren() { michael@0: return this._tabChildren; michael@0: }, michael@0: set tabChildren(val) { michael@0: this._tabChildren = val; michael@0: }, michael@0: get textSnapshot() { michael@0: notImplemented(); michael@0: }, michael@0: addChild: function (child) { michael@0: return this.addChildAt(child, this._children.length); michael@0: }, michael@0: addChildAt: function (child, index) { michael@0: if (child === this) { michael@0: throwError('ArgumentError', Errors.CantAddSelfError); michael@0: } michael@0: if (child._parent === this) { michael@0: return this.setChildIndex(child, index); michael@0: } michael@0: var children = this._children; michael@0: if (index < 0 || index > children.length) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: if (child._index > -1) { michael@0: var LoaderClass = avm2.systemDomain.getClass('flash.display.Loader'); michael@0: if (LoaderClass.isInstanceOf(child._parent)) { michael@0: def.removeChild.call(child._parent, child); michael@0: } else { michael@0: child._parent.removeChild(child); michael@0: } michael@0: } michael@0: if (!this._sparse) { michael@0: for (var i = children.length; i && i > index; i--) { michael@0: children[i - 1]._index++; michael@0: } michael@0: } michael@0: children.splice(index, 0, child); michael@0: child._invalidateTransform(); michael@0: child._owned = false; michael@0: child._parent = this; michael@0: child._stage = this._stage; michael@0: child._index = index; michael@0: child._dispatchEvent('added', undefined, true); michael@0: if (this._stage) { michael@0: this._stage._addToStage(child); michael@0: } michael@0: return child; michael@0: }, michael@0: areInaccessibleObjectsUnderPoint: function (pt) { michael@0: notImplemented(); michael@0: }, michael@0: contains: function (child) { michael@0: return child._parent === this; michael@0: }, michael@0: getChildAt: function (index) { michael@0: var children = this._children; michael@0: if (index < 0 || index > children.length) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: var child = children[index]; michael@0: if (!flash.display.DisplayObject.class.isInstanceOf(child)) { michael@0: return null; michael@0: } michael@0: return child; michael@0: }, michael@0: getChildByName: function (name) { michael@0: var children = this._children; michael@0: for (var i = 0, n = children.length; i < n; i++) { michael@0: var child = children[i]; michael@0: if (child.name === name) { michael@0: return this.getChildAt(i); michael@0: } michael@0: } michael@0: return null; michael@0: }, michael@0: getChildIndex: function (child) { michael@0: if (child._parent !== this) { michael@0: throwError('ArgumentError', Errors.NotAChildError); michael@0: } michael@0: return this._sparse ? this._children.indexOf(child) : child._index; michael@0: }, michael@0: getObjectsUnderPoint: function (pt) { michael@0: notImplemented(); michael@0: }, michael@0: removeChild: function (child) { michael@0: if (child._parent !== this) { michael@0: throwError('ArgumentError', Errors.NotAChildError); michael@0: } michael@0: return this.removeChildAt(this.getChildIndex(child)); michael@0: }, michael@0: removeChildAt: function (index) { michael@0: var children = this._children; michael@0: if (index < 0 || index >= children.length) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: var child = children[index]; michael@0: child._dispatchEvent('removed', undefined, true); michael@0: if (this._stage) { michael@0: this._stage._removeFromStage(child); michael@0: } michael@0: if (!this._sparse) { michael@0: for (var i = children.length; i && i > index; i--) { michael@0: children[i - 1]._index--; michael@0: } michael@0: } michael@0: children.splice(index, 1); michael@0: child._invalidateTransform(); michael@0: child._owned = false; michael@0: child._parent = null; michael@0: child._index = -1; michael@0: return child; michael@0: }, michael@0: setChildIndex: function (child, index) { michael@0: if (child._parent !== this) { michael@0: throwError('ArgumentError', Errors.NotAChildError); michael@0: } michael@0: var currentIndex = this.getChildIndex(child); michael@0: if (currentIndex === index) { michael@0: return; michael@0: } michael@0: var children = this._children; michael@0: if (index < 0 || index > children.length) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: children.splice(currentIndex, 1); michael@0: children.splice(index, 0, child); michael@0: if (!this._sparse) { michael@0: var i = currentIndex < index ? currentIndex : index; michael@0: while (i < children.length) { michael@0: children[i]._index = i++; michael@0: } michael@0: } michael@0: child._owned = false; michael@0: child._invalidate(); michael@0: return child; michael@0: }, michael@0: removeChildren: function (beginIndex, endIndex) { michael@0: beginIndex = arguments.length < 1 ? 0 : beginIndex | 0; michael@0: endIndex = arguments.length < 2 ? 2147483647 : endIndex | 0; michael@0: var numChildren = this._children.length; michael@0: if (beginIndex < 0 || endIndex < 0 || endIndex < beginIndex) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: if (numChildren === 0) { michael@0: return; michael@0: } michael@0: if (endIndex > numChildren - 1) { michael@0: endIndex = numChildren - 1; michael@0: } michael@0: var count = endIndex - beginIndex + 1; michael@0: while (count--) { michael@0: this.removeChildAt(beginIndex); michael@0: } michael@0: }, michael@0: swapChildren: function (child1, child2) { michael@0: if (child1._parent !== this || child2._parent !== this) { michael@0: throwError('ArgumentError', Errors.NotAChildError); michael@0: } michael@0: this.swapChildrenAt(this.getChildIndex(child1), this.getChildIndex(child2)); michael@0: }, michael@0: swapChildrenAt: function (index1, index2) { michael@0: var children = this._children; michael@0: var numChildren = children.length; michael@0: if (index1 < 0 || index1 > numChildren || index2 < 0 || index2 > numChildren) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: var child1 = children[index1]; michael@0: var child2 = children[index2]; michael@0: children[index1] = child2; michael@0: children[index2] = child1; michael@0: child1._index = index2; michael@0: child2._index = index1; michael@0: child1._owned = false; michael@0: child2._owned = false; michael@0: child1._invalidate(); michael@0: child2._invalidate(); michael@0: }, michael@0: destroy: function () { michael@0: if (this._destroyed) { michael@0: return; michael@0: } michael@0: this._destroyed = true; michael@0: this._children.forEach(function (child) { michael@0: if (child.destroy) { michael@0: child.destroy(); michael@0: } michael@0: }); michael@0: this.cleanupBroadcastListeners(); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.initialize = function () { michael@0: this._mouseChildren = true; michael@0: this._tabChildren = true; michael@0: this._sparse = false; michael@0: this._isContainer = true; michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: numChildren: desc(def, 'numChildren'), michael@0: tabChildren: desc(def, 'tabChildren'), michael@0: mouseChildren: desc(def, 'mouseChildren'), michael@0: textSnapshot: desc(def, 'textSnapshot'), michael@0: addChild: def.addChild, michael@0: addChildAt: def.addChildAt, michael@0: removeChild: def.removeChild, michael@0: removeChildAt: def.removeChildAt, michael@0: getChildIndex: def.getChildIndex, michael@0: setChildIndex: def.setChildIndex, michael@0: getChildAt: def.getChildAt, michael@0: getChildByName: def.getChildByName, michael@0: contains: def.contains, michael@0: swapChildrenAt: def.swapChildrenAt, michael@0: swapChildren: def.swapChildren, michael@0: removeChildren: def.removeChildren michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var FrameLabelDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.FrameLabel', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: ctor: function ctor(name, frame) { michael@0: this._name = name; michael@0: this._frame = frame; michael@0: }, michael@0: name: { michael@0: get: function name() { michael@0: return this._name; michael@0: } michael@0: }, michael@0: frame: { michael@0: get: function frame() { michael@0: return this._frame; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var GraphicsDefinition = function () { michael@0: var GRAPHICS_PATH_WINDING_EVEN_ODD = 'evenOdd'; michael@0: var GRAPHICS_PATH_WINDING_NON_ZERO = 'nonZero'; michael@0: var def = { michael@0: __class__: 'flash.display.Graphics', michael@0: initialize: function () { michael@0: this._paths = []; michael@0: this.beginPath(); michael@0: this._bitmap = null; michael@0: this._parent = 0; michael@0: this.bbox = null; michael@0: this.strokeBbox = null; michael@0: }, michael@0: _invalidate: function () { michael@0: this.bbox = null; michael@0: this.strokeBbox = null; michael@0: this._parent._invalidate(); michael@0: this._parent._invalidateBounds(); michael@0: }, michael@0: beginPath: function () { michael@0: var oldPath = this._currentPath; michael@0: if (oldPath && (oldPath.commands.length === 0 || oldPath.commands.length === 1 && oldPath.commands[0] === SHAPE_MOVE_TO)) { michael@0: return; michael@0: } michael@0: var path = this._currentPath = new ShapePath(null, null); michael@0: this._paths.push(path); michael@0: if (oldPath) { michael@0: path.fillStyle = oldPath.fillStyle; michael@0: path.lineStyle = oldPath.lineStyle; michael@0: path.fillRule = oldPath.fillRule; michael@0: } michael@0: }, michael@0: _drawPathObject: function (path) { michael@0: if (path.__class__ === 'flash.display.GraphicsPath') michael@0: this.drawPath(path.commands, path.data, path.winding); michael@0: else if (path.__class__ === 'flash.display.GraphicsTrianglePath') michael@0: this.drawTriangles(path.vertices, path.indices, path.uvtData, path.culling); michael@0: }, michael@0: draw: function (ctx, clip, ratio, colorTransform) { michael@0: var paths = this._paths; michael@0: for (var i = 0; i < paths.length; i++) { michael@0: paths[i].draw(ctx, clip, ratio, colorTransform); michael@0: } michael@0: }, michael@0: beginFill: function (color, alpha) { michael@0: if (alpha === undefined) michael@0: alpha = 1; michael@0: this.beginPath(); michael@0: this._currentPath.fillStyle = alpha ? { michael@0: style: rgbIntAlphaToStr(color, alpha) michael@0: } : null; michael@0: }, michael@0: beginGradientFill: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) { michael@0: var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos); michael@0: this.beginPath(); michael@0: this._currentPath.fillStyle = style; michael@0: }, michael@0: beginBitmapFill: function (bitmap, matrix, repeat, smooth) { michael@0: this.beginPath(); michael@0: repeat = repeat !== false; michael@0: this._currentPath.fillStyle = createPatternStyle(bitmap, matrix, repeat, !(!smooth)); michael@0: }, michael@0: clear: function () { michael@0: this._invalidate(); michael@0: this._paths = []; michael@0: this._currentPath = null; michael@0: this.beginPath(); michael@0: }, michael@0: copyFrom: function (sourceGraphics) { michael@0: notImplemented('Graphics#copyFrom'); michael@0: }, michael@0: cubicCurveTo: function (cp1x, cp1y, cp2x, cp2y, x, y) { michael@0: this._invalidate(); michael@0: this._currentPath.cubicCurveTo(cp1x * 20 | 0, cp1y * 20 | 0, cp2x * 20 | 0, cp2y * 20 | 0, x * 20 | 0, y * 20 | 0); michael@0: }, michael@0: curveTo: function (cpx, cpy, x, y) { michael@0: this._invalidate(); michael@0: this._currentPath.curveTo(cpx * 20 | 0, cpy * 20 | 0, x * 20 | 0, y * 20 | 0); michael@0: }, michael@0: drawCircle: function (x, y, radius) { michael@0: var radius2 = radius * 2; michael@0: this.drawRoundRect(x - radius, y - radius, radius2, radius2, radius2, radius2); michael@0: }, michael@0: drawEllipse: function (x, y, width, height) { michael@0: this.drawRoundRect(x, y, width, height, width, height); michael@0: }, michael@0: drawPath: function (commands, data, winding) { michael@0: this._invalidate(); michael@0: this.beginPath(); michael@0: this._currentPath.fillRule = winding || GRAPHICS_PATH_WINDING_EVEN_ODD; michael@0: this._currentPath.commands = commands; michael@0: this._currentPath.data = data; michael@0: }, michael@0: drawRect: function (x, y, w, h) { michael@0: if (isNaN(w + h)) michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: this._invalidate(); michael@0: this._currentPath.rect(x * 20 | 0, y * 20 | 0, w * 20 | 0, h * 20 | 0); michael@0: }, michael@0: drawRoundRect: function (x, y, w, h, ellipseWidth, ellipseHeight) { michael@0: if (isNaN(w + h + ellipseWidth) || ellipseHeight !== undefined && isNaN(ellipseHeight)) { michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: } michael@0: this._invalidate(); michael@0: if (ellipseHeight === undefined) { michael@0: ellipseHeight = ellipseWidth; michael@0: } michael@0: x = x * 20 | 0; michael@0: y = y * 20 | 0; michael@0: w = w * 20 | 0; michael@0: h = h * 20 | 0; michael@0: if (!ellipseHeight || !ellipseWidth) { michael@0: this._currentPath.rect(x, y, w, h); michael@0: return; michael@0: } michael@0: var radiusX = ellipseWidth / 2 * 20 | 0; michael@0: var radiusY = ellipseHeight / 2 * 20 | 0; michael@0: var hw = w / 2 | 0; michael@0: var hh = h / 2 | 0; michael@0: if (radiusX > hw) { michael@0: radiusX = hw; michael@0: } michael@0: if (radiusY > hh) { michael@0: radiusY = hh; michael@0: } michael@0: if (hw === radiusX && hh === radiusY) { michael@0: if (radiusX === radiusY) michael@0: this._currentPath.circle(x + radiusX, y + radiusY, radiusX); michael@0: else michael@0: this._currentPath.ellipse(x + radiusX, y + radiusY, radiusX, radiusY); michael@0: return; michael@0: } michael@0: var right = x + w; michael@0: var bottom = y + h; michael@0: var xlw = x + radiusX; michael@0: var xrw = right - radiusX; michael@0: var ytw = y + radiusY; michael@0: var ybw = bottom - radiusY; michael@0: this._currentPath.moveTo(right, ybw); michael@0: this._currentPath.curveTo(right, bottom, xrw, bottom); michael@0: this._currentPath.lineTo(xlw, bottom); michael@0: this._currentPath.curveTo(x, bottom, x, ybw); michael@0: this._currentPath.lineTo(x, ytw); michael@0: this._currentPath.curveTo(x, y, xlw, y); michael@0: this._currentPath.lineTo(xrw, y); michael@0: this._currentPath.curveTo(right, y, right, ytw); michael@0: this._currentPath.lineTo(right, ybw); michael@0: }, michael@0: drawRoundRectComplex: function (x, y, w, h, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius) { michael@0: if (isNaN(w + h + topLeftRadius + topRightRadius + bottomLeftRadius + bottomRightRadius)) { michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: } michael@0: this._invalidate(); michael@0: x = x * 20 | 0; michael@0: y = y * 20 | 0; michael@0: w = w * 20 | 0; michael@0: h = h * 20 | 0; michael@0: if (!topLeftRadius && !topRightRadius && !bottomLeftRadius && !bottomRightRadius) { michael@0: this._currentPath.rect(x, y, w, h); michael@0: return; michael@0: } michael@0: topLeftRadius = topLeftRadius * 20 | 0; michael@0: topRightRadius = topRightRadius * 20 | 0; michael@0: bottomLeftRadius = bottomLeftRadius * 20 | 0; michael@0: bottomRightRadius = bottomRightRadius * 20 | 0; michael@0: var right = x + w; michael@0: var bottom = y + h; michael@0: var xtl = x + topLeftRadius; michael@0: this._currentPath.moveTo(right, bottom - bottomRightRadius); michael@0: this._currentPath.curveTo(right, bottom, right - bottomRightRadius, bottom); michael@0: this._currentPath.lineTo(x + bottomLeftRadius, bottom); michael@0: this._currentPath.curveTo(x, bottom, x, bottom - bottomLeftRadius); michael@0: this._currentPath.lineTo(x, y + topLeftRadius); michael@0: this._currentPath.curveTo(x, y, xtl, y); michael@0: this._currentPath.lineTo(right - topRightRadius, y); michael@0: this._currentPath.curveTo(right, y, right, y + topRightRadius); michael@0: this._currentPath.lineTo(right, bottom - bottomRightRadius); michael@0: }, michael@0: drawTriangles: function (vertices, indices, uvtData, cullingStr) { michael@0: if (vertices === null || vertices.length === 0) { michael@0: return; michael@0: } michael@0: var numVertices = vertices.length / 2; michael@0: var numTriangles = 0; michael@0: if (indices) { michael@0: if (indices.length % 3) { michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: } else { michael@0: numTriangles = indices.length / 3; michael@0: } michael@0: } else { michael@0: if (vertices.length % 6) { michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: } else { michael@0: numTriangles = vertices.length / 6; michael@0: } michael@0: } michael@0: var numStrides = 0; michael@0: if (uvtData) { michael@0: if (uvtData.length == numVertices * 2) { michael@0: numStrides = 2; michael@0: } else if (uvtData.length == numVertices * 3) { michael@0: numStrides = 3; michael@0: } else { michael@0: throwError('ArgumentError', Errors.InvalidParamError); michael@0: } michael@0: } michael@0: var culling = 0; michael@0: if (cullingStr === 'none') { michael@0: culling = 0; michael@0: } else if (cullingStr === 'negative') { michael@0: culling = -1; michael@0: } else if (cullingStr === 'positive') { michael@0: culling = 1; michael@0: } else { michael@0: throwError('ArgumentError', Errors.InvalidEnumError, 'culling'); michael@0: } michael@0: notImplemented('Graphics#drawTriangles'); michael@0: }, michael@0: endFill: function () { michael@0: this.beginPath(); michael@0: this._currentPath.fillStyle = null; michael@0: }, michael@0: lineBitmapStyle: function (bitmap, matrix, repeat, smooth) { michael@0: this.beginPath(); michael@0: this._currentPath.lineStyle = createPatternStyle(bitmap, matrix, repeat, smooth); michael@0: }, michael@0: lineGradientStyle: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) { michael@0: var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos); michael@0: this.beginPath(); michael@0: this._currentPath.lineStyle = style; michael@0: }, michael@0: lineStyle: function (width, color, alpha, pxHinting, scale, cap, joint, mlimit) { michael@0: this.beginPath(); michael@0: if (width) { michael@0: if (alpha === undefined) michael@0: alpha = 1; michael@0: if (mlimit === undefined) michael@0: mlimit = 3; michael@0: this._currentPath.lineStyle = { michael@0: style: rgbIntAlphaToStr(color, alpha), michael@0: lineCap: cap || 'round', michael@0: lineJoin: cap || 'round', michael@0: width: width * 20 | 0, michael@0: miterLimit: mlimit * 2 michael@0: }; michael@0: } else { michael@0: this._currentPath.lineStyle = null; michael@0: } michael@0: }, michael@0: lineTo: function (x, y) { michael@0: this._invalidate(); michael@0: this._currentPath.lineTo(x * 20 | 0, y * 20 | 0); michael@0: }, michael@0: moveTo: function (x, y) { michael@0: this._currentPath.moveTo(x * 20 | 0, y * 20 | 0); michael@0: }, michael@0: _getBounds: function (includeStroke) { michael@0: var bbox = includeStroke ? this.strokeBbox : this.bbox; michael@0: if (bbox) { michael@0: return bbox; michael@0: } michael@0: var subpaths = this._paths; michael@0: var xMins = [], yMins = [], xMaxs = [], yMaxs = []; michael@0: for (var i = 0, n = subpaths.length; i < n; i++) { michael@0: var path = subpaths[i]; michael@0: if (path.commands.length) { michael@0: var b = path.getBounds(includeStroke); michael@0: if (b) { michael@0: xMins.push(b.xMin); michael@0: yMins.push(b.yMin); michael@0: xMaxs.push(b.xMax); michael@0: yMaxs.push(b.yMax); michael@0: } michael@0: } michael@0: } michael@0: if (xMins.length === 0) { michael@0: bbox = { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: 0, michael@0: yMax: 0 michael@0: }; michael@0: } else { michael@0: bbox = { michael@0: xMin: Math.min.apply(Math, xMins), michael@0: yMin: Math.min.apply(Math, yMins), michael@0: xMax: Math.max.apply(Math, xMaxs), michael@0: yMax: Math.max.apply(Math, yMaxs) michael@0: }; michael@0: } michael@0: if (includeStroke) { michael@0: this.strokeBbox = bbox; michael@0: } else { michael@0: this.bbox = bbox; michael@0: } michael@0: return bbox; michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: beginFill: def.beginFill, michael@0: beginGradientFill: def.beginGradientFill, michael@0: beginBitmapFill: def.beginBitmapFill, michael@0: beginFillObject: def.beginFillObject, michael@0: beginStrokeObject: def.beginStrokeObject, michael@0: clear: def.clear, michael@0: copyFrom: def.copyFrom, michael@0: cubicCurveTo: def.cubicCurveTo, michael@0: curveTo: def.curveTo, michael@0: drawCircle: def.drawCircle, michael@0: drawEllipse: def.drawEllipse, michael@0: drawPath: def.drawPath, michael@0: drawRect: def.drawRect, michael@0: drawRoundRect: def.drawRoundRect, michael@0: drawRoundRectComplex: def.drawRoundRectComplex, michael@0: drawTriangles: def.drawTriangles, michael@0: endFill: def.endFill, michael@0: lineBitmapStyle: def.lineBitmapStyle, michael@0: lineGradientStyle: def.lineGradientStyle, michael@0: lineStyle: def.lineStyle, michael@0: moveTo: def.moveTo, michael@0: lineTo: def.lineTo michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: function createPatternStyle(bitmap, matrix, repeat, smooth) { michael@0: var repeatStyle = repeat === false ? 'no-repeat' : 'repeat'; michael@0: var pattern = factoryCtx.createPattern(bitmap._drawable, repeatStyle); michael@0: var transform = matrix ? { michael@0: a: matrix.a, michael@0: b: matrix.b, michael@0: c: matrix.c, michael@0: d: matrix.d, michael@0: e: matrix.tx, michael@0: f: matrix.ty michael@0: } : { michael@0: a: 1, michael@0: b: 0, michael@0: c: 0, michael@0: d: 1, michael@0: e: 0, michael@0: f: 0 michael@0: }; michael@0: return { michael@0: style: pattern, michael@0: transform: transform, michael@0: smooth: smooth michael@0: }; michael@0: } michael@0: function createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) { michael@0: type === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'type'); michael@0: colors === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'colors'); michael@0: if (!(type === 'linear' || type === 'radial')) { michael@0: throwError('ArgumentError', Errors.InvalidEnumError, 'type'); michael@0: } michael@0: var colorStops = []; michael@0: for (var i = 0, n = colors.length; i < n; i++) { michael@0: colorStops.push({ michael@0: ratio: ratios[i] / 255, michael@0: color: rgbIntAlphaToStr(colors[i], alphas[i]) michael@0: }); michael@0: } michael@0: var gradientConstructor; michael@0: if (type === 'linear') { michael@0: gradientConstructor = buildLinearGradientFactory(colorStops); michael@0: } else { michael@0: gradientConstructor = buildRadialGradientFactory(focalPos || 0, colorStops); michael@0: } michael@0: var scale = 819.2; michael@0: var transform = matrix ? { michael@0: a: scale * matrix.a, michael@0: b: scale * matrix.b, michael@0: c: scale * matrix.c, michael@0: d: scale * matrix.d, michael@0: e: matrix.tx, michael@0: f: matrix.ty michael@0: } : { michael@0: a: scale, michael@0: b: 0, michael@0: c: 0, michael@0: d: scale, michael@0: e: 0, michael@0: f: 0 michael@0: }; michael@0: return { michael@0: style: gradientConstructor, michael@0: transform: transform michael@0: }; michael@0: } michael@0: function drawGraphicsData(data) { michael@0: if (data === null) { michael@0: return; michael@0: } michael@0: for (var i = 0; i < data.length; i++) { michael@0: var item = data[i]; michael@0: if (flash.display.IGraphicsPath.class.isInstanceOf(item)) { michael@0: this._drawPathObject(item); michael@0: } else if (flash.display.IGraphicsStroke.class.isInstanceOf(item)) { michael@0: this.beginStrokeObject(item); michael@0: } else if (flash.display.IGraphicsFill.class.isInstanceOf(item)) { michael@0: this.beginFillObject(item); michael@0: } michael@0: } michael@0: } michael@0: var InteractiveObjectDefinition = function () { michael@0: var def = { michael@0: initialize: function () { michael@0: this._contextMenu = null; michael@0: this._doubleClickEnabled = false; michael@0: this._focusRect = null; michael@0: this._mouseEnabled = true; michael@0: this._tabEnabled = false; michael@0: }, michael@0: get accessibilityImplementation() { michael@0: return null; michael@0: }, michael@0: set accessibilityImplementation(val) { michael@0: somewhatImplemented('accessibilityImplementation'); michael@0: }, michael@0: get contextMenu() { michael@0: somewhatImplemented('contextMenu'); michael@0: return this._contextMenu; michael@0: }, michael@0: set contextMenu(val) { michael@0: somewhatImplemented('contextMenu'); michael@0: this._contextMenu = val; michael@0: }, michael@0: get doubleClickEnabled() { michael@0: return this._doubleClickEnabled; michael@0: }, michael@0: set doubleClickEnabled(val) { michael@0: this._doubleClickEnabled = val; michael@0: }, michael@0: get focusRect() { michael@0: return this._focusRect; michael@0: }, michael@0: set focusRect(val) { michael@0: this._focusRect = val; michael@0: }, michael@0: get mouseEnabled() { michael@0: return this._mouseEnabled; michael@0: }, michael@0: set mouseEnabled(val) { michael@0: this._mouseEnabled = val; michael@0: }, michael@0: get needsSoftKeyboard() { michael@0: return false; michael@0: }, michael@0: set needsSoftKeyboard(val) { michael@0: notImplemented(); michael@0: }, michael@0: get softKeyboardInputAreaOfInterest() { michael@0: return null; michael@0: }, michael@0: set softKeyboardInputAreaOfInterest(val) { michael@0: notImplemented(); michael@0: }, michael@0: get tabEnabled() { michael@0: return this._tabEnabled; michael@0: }, michael@0: set tabEnabled(val) { michael@0: var old = this._tabEnabled; michael@0: this._tabEnabled = val; michael@0: if (old !== val) { michael@0: var Event = flash.events.Event; michael@0: this._dispatchEvent(new Event('tabEnabledChange', false, false)); michael@0: } michael@0: }, michael@0: requestSoftKeyboard: function () { michael@0: notImplemented(); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: tabEnabled: desc(def, 'tabEnabled'), michael@0: tabIndex: { michael@0: get: function tabIndex() { michael@0: return this._tabIndex; michael@0: }, michael@0: set: function tabIndex(index) { michael@0: this._tabIndex = index; michael@0: } michael@0: }, michael@0: focusRect: desc(def, 'focusRect'), michael@0: mouseEnabled: desc(def, 'mouseEnabled'), michael@0: doubleClickEnabled: desc(def, 'doubleClickEnabled'), michael@0: accessibilityImplementation: desc(def, 'accessibilityImplementation'), michael@0: softKeyboardInputAreaOfInterest: desc(def, 'softKeyboardInputAreaOfInterest'), michael@0: needsSoftKeyboard: desc(def, 'needsSoftKeyboard'), michael@0: contextMenu: desc(def, 'contextMenu'), michael@0: requestSoftKeyboard: def.requestSoftKeyboard michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var $RELEASE = false; michael@0: var LoaderDefinition = function () { michael@0: var WORKERS_ENABLED = true; michael@0: var LOADER_PATH = true ? 'shumway-worker.js' : 'swf/resourceloader.js'; michael@0: var head = document.head; michael@0: head.insertBefore(document.createElement('style'), head.firstChild); michael@0: var style = document.styleSheets[0]; michael@0: var def = { michael@0: __class__: 'flash.display.Loader', michael@0: initialize: function () { michael@0: this._contentLoaderInfo = new flash.display.LoaderInfo(); michael@0: this._contentLoaderInfo._loader = this; michael@0: this._dictionary = {}; michael@0: this._dictionaryResolved = {}; michael@0: this._displayList = null; michael@0: this._timeline = []; michael@0: this._lastPromise = null; michael@0: this._uncaughtErrorEvents = null; michael@0: this._worker = null; michael@0: var abc = AVM2.currentAbc(); michael@0: if (abc && abc.env.loader) { michael@0: this._contentLoaderInfo._loaderURL = abc.env.loader._contentLoaderInfo._url; michael@0: } michael@0: }, michael@0: _commitData: function (data) { michael@0: switch (data.command) { michael@0: case 'init': michael@0: this._init(data.result); michael@0: break; michael@0: case 'progress': michael@0: this._updateProgress(data.result); michael@0: break; michael@0: case 'complete': michael@0: var frameConstructed = new Promise(function (resolve) { michael@0: avm2.systemDomain.onMessage.register('frameConstructed', function waitForFrame(type) { michael@0: if (type === 'frameConstructed') { michael@0: resolve(); michael@0: avm2.systemDomain.onMessage.unregister('frameConstructed', waitForFrame); michael@0: } michael@0: }); michael@0: }); michael@0: this._contentLoaderInfo._dispatchEvent('parsed'); michael@0: Promise.all([ michael@0: frameConstructed, michael@0: this._lastPromise michael@0: ]).then(function () { michael@0: this._content._complete = true; michael@0: this._contentLoaderInfo._dispatchEvent('complete'); michael@0: }.bind(this)); michael@0: var stats = data.stats; michael@0: if (stats) { michael@0: TelemetryService.reportTelemetry(stats); michael@0: } michael@0: this._worker && this._worker.terminate(); michael@0: break; michael@0: case 'empty': michael@0: this._lastPromise = Promise.resolve(); michael@0: break; michael@0: case 'error': michael@0: this._contentLoaderInfo._dispatchEvent('ioError', flash.events.IOErrorEvent); michael@0: break; michael@0: default: michael@0: if (data.id === 0) michael@0: break; michael@0: if (data.isSymbol) michael@0: this._commitSymbol(data); michael@0: else if (data.type === 'frame') michael@0: this._commitFrame(data); michael@0: else if (data.type === 'image') michael@0: this._commitImage(data); michael@0: break; michael@0: } michael@0: }, michael@0: _updateProgress: function (state) { michael@0: var loaderInfo = this._contentLoaderInfo; michael@0: loaderInfo._bytesLoaded = state.bytesLoaded || 0; michael@0: loaderInfo._bytesTotal = state.bytesTotal || 0; michael@0: var event = new flash.events.ProgressEvent('progress', false, false, loaderInfo._bytesLoaded, loaderInfo._bytesTotal); michael@0: loaderInfo._dispatchEvent(event); michael@0: }, michael@0: _buildFrame: function (currentDisplayList, timeline, promiseQueue, frame, frameNum) { michael@0: var loader = this; michael@0: var dictionary = loader._dictionary; michael@0: var dictionaryResolved = loader._dictionaryResolved; michael@0: var displayList = {}; michael@0: var depths = []; michael@0: var cmds = frame.depths; michael@0: if (currentDisplayList) { michael@0: var currentDepths = currentDisplayList.depths; michael@0: for (var i = 0; i < currentDepths.length; i++) { michael@0: var depth = currentDepths[i]; michael@0: if (cmds[depth] === null) { michael@0: continue; michael@0: } michael@0: displayList[depth] = currentDisplayList[depth]; michael@0: depths.push(depth); michael@0: } michael@0: } michael@0: for (var depth in cmds) { michael@0: var cmd = cmds[depth]; michael@0: if (!cmd) { michael@0: continue; michael@0: } michael@0: if (cmd.move) { michael@0: var oldCmd = cmd; michael@0: cmd = cloneObject(currentDisplayList[depth]); michael@0: for (var prop in oldCmd) { michael@0: var val = oldCmd[prop]; michael@0: if (val) { michael@0: cmd[prop] = val; michael@0: } michael@0: } michael@0: } michael@0: if (cmd.symbolId) { michael@0: var itemPromise = dictionary[cmd.symbolId]; michael@0: if (itemPromise && !dictionaryResolved[cmd.symbolId]) { michael@0: promiseQueue.push(itemPromise); michael@0: } michael@0: cmd = cloneObject(cmd); michael@0: Object.defineProperty(cmd, 'symbolInfo', { michael@0: get: function (dictionaryResolved, symbolId) { michael@0: return function () { michael@0: return dictionaryResolved[symbolId]; michael@0: }; michael@0: }(dictionaryResolved, cmd.symbolId) michael@0: }); michael@0: } michael@0: if (!displayList[depth]) { michael@0: depths.push(depth); michael@0: } michael@0: displayList[depth] = cmd; michael@0: } michael@0: depths.sort(sortNumeric); michael@0: displayList.depths = depths; michael@0: var i = frame.repeat; michael@0: while (i--) { michael@0: timeline.push(displayList); michael@0: } michael@0: return displayList; michael@0: }, michael@0: _commitFrame: function (frame) { michael@0: var abcBlocks = frame.abcBlocks; michael@0: var actionBlocks = frame.actionBlocks; michael@0: var initActionBlocks = frame.initActionBlocks; michael@0: var exports = frame.exports; michael@0: var symbolClasses = frame.symbolClasses; michael@0: var sceneData = frame.sceneData; michael@0: var loader = this; michael@0: var dictionary = loader._dictionary; michael@0: var loaderInfo = loader._contentLoaderInfo; michael@0: var timeline = loader._timeline; michael@0: var frameNum = timeline.length + 1; michael@0: var framePromiseResolve; michael@0: var framePromise = new Promise(function (resolve) { michael@0: framePromiseResolve = resolve; michael@0: }); michael@0: var labelName = frame.labelName; michael@0: var prevPromise = this._lastPromise; michael@0: this._lastPromise = framePromise; michael@0: var promiseQueue = [ michael@0: prevPromise michael@0: ]; michael@0: this._displayList = this._buildFrame(this._displayList, timeline, promiseQueue, frame, frameNum); michael@0: var framesLoaded = timeline.length; michael@0: if (frame.bgcolor) michael@0: loaderInfo._backgroundColor = frame.bgcolor; michael@0: else if (isNullOrUndefined(loaderInfo._backgroundColor)) michael@0: loaderInfo._backgroundColor = { michael@0: red: 255, michael@0: green: 255, michael@0: blue: 255, michael@0: alpha: 255 michael@0: }; michael@0: Promise.all(promiseQueue).then(function () { michael@0: if (abcBlocks && loader._isAvm2Enabled) { michael@0: var appDomain = avm2.applicationDomain; michael@0: for (var i = 0, n = abcBlocks.length; i < n; i++) { michael@0: var abc = new AbcFile(abcBlocks[i].data, 'abc_block_' + i); michael@0: abc.env.loader = loader; michael@0: if (abcBlocks[i].flags) { michael@0: appDomain.loadAbc(abc); michael@0: } else { michael@0: appDomain.executeAbc(abc); michael@0: } michael@0: } michael@0: } michael@0: if (symbolClasses && loader._isAvm2Enabled) { michael@0: var symbolClassesPromises = []; michael@0: for (var i = 0, n = symbolClasses.length; i < n; i++) { michael@0: var asset = symbolClasses[i]; michael@0: var symbolPromise = dictionary[asset.symbolId]; michael@0: if (!symbolPromise) michael@0: continue; michael@0: symbolPromise.then(function (className) { michael@0: return function symbolPromiseResolved(symbolInfo) { michael@0: symbolInfo.className = className; michael@0: avm2.applicationDomain.getClass(className).setSymbol(symbolInfo.props); michael@0: }; michael@0: }(asset.className)); michael@0: symbolClassesPromises.push(symbolPromise); michael@0: } michael@0: return Promise.all(symbolClassesPromises); michael@0: } michael@0: if (exports && !loader._isAvm2Enabled) { michael@0: var exportPromises = []; michael@0: for (var i = 0, n = exports.length; i < n; i++) { michael@0: var asset = exports[i]; michael@0: var symbolPromise = dictionary[asset.symbolId]; michael@0: if (!symbolPromise) michael@0: continue; michael@0: symbolPromise.then(function (className) { michael@0: return function symbolPromiseResolved(symbolInfo) { michael@0: loader._avm1Context.addAsset(className, symbolInfo.props); michael@0: }; michael@0: }(asset.className)); michael@0: exportPromises.push(symbolPromise); michael@0: } michael@0: return Promise.all(exportPromises); michael@0: } michael@0: }).then(function () { michael@0: var root = loader._content; michael@0: var labelMap; michael@0: if (!root) { michael@0: var parent = loader._parent; michael@0: true; michael@0: var rootInfo = loader._dictionaryResolved[0]; michael@0: var rootClass = avm2.applicationDomain.getClass(rootInfo.className); michael@0: root = rootClass.createAsSymbol({ michael@0: framesLoaded: framesLoaded, michael@0: loader: loader, michael@0: parent: parent || loader, michael@0: index: parent ? 0 : -1, michael@0: level: parent ? 0 : -1, michael@0: timeline: timeline, michael@0: totalFrames: rootInfo.props.totalFrames, michael@0: stage: loader._stage, michael@0: complete: frame.complete michael@0: }); michael@0: if (!loader._isAvm2Enabled) { michael@0: var avm1Context = loader._avm1Context; michael@0: var _root = root; michael@0: if (parent && parent !== loader._stage) { michael@0: var parentLoader = parent.loaderInfo._loader; michael@0: while (parentLoader._parent && parentLoader._parent !== loader._stage) { michael@0: parentLoader = parentLoader._parent.loaderInfo._loader; michael@0: } michael@0: if (parentLoader._isAvm2Enabled) { michael@0: somewhatImplemented('AVM1Movie'); michael@0: this._worker && this._worker.terminate(); michael@0: return; michael@0: } michael@0: _root = parentLoader._content; michael@0: } michael@0: var as2Object = _root._getAS2Object(); michael@0: avm1Context.globals.asSetPublicProperty('_root', as2Object); michael@0: avm1Context.globals.asSetPublicProperty('_level0', as2Object); michael@0: avm1Context.globals.asSetPublicProperty('_level1', as2Object); michael@0: var parameters = loader.loaderInfo._parameters; michael@0: for (var paramName in parameters) { michael@0: if (!(paramName in as2Object)) { michael@0: as2Object[paramName] = parameters[paramName]; michael@0: } michael@0: } michael@0: } michael@0: var isRootMovie = parent && parent == loader._stage && loader._stage._children.length === 0; michael@0: if (isRootMovie) { michael@0: parent._frameRate = loaderInfo._frameRate; michael@0: parent._stageHeight = loaderInfo._height; michael@0: parent._stageWidth = loaderInfo._width; michael@0: parent._root = root; michael@0: parent._setup(); michael@0: } else { michael@0: loader._children.push(root); michael@0: } michael@0: var labels; michael@0: labelMap = root.symbol.labelMap = createEmptyObject(); michael@0: if (sceneData) { michael@0: var scenes = []; michael@0: var startFrame; michael@0: var endFrame = root.symbol.totalFrames - 1; michael@0: var sd = sceneData.scenes; michael@0: var ld = sceneData.labels; michael@0: var i = sd.length; michael@0: while (i--) { michael@0: var s = sd[i]; michael@0: startFrame = s.offset; michael@0: labels = []; michael@0: var j = ld.length; michael@0: while (j--) { michael@0: var lbl = ld[j]; michael@0: if (lbl.frame >= startFrame && lbl.frame <= endFrame) { michael@0: labelMap[lbl.name] = lbl.frame + 1; michael@0: labels.unshift(new flash.display.FrameLabel(lbl.name, lbl.frame - startFrame + 1)); michael@0: } michael@0: } michael@0: var scene = new flash.display.Scene(s.name, labels, endFrame - startFrame + 1); michael@0: scene._startFrame = startFrame + 1; michael@0: scene._endFrame = endFrame + 1; michael@0: scenes.unshift(scene); michael@0: endFrame = startFrame - 1; michael@0: } michael@0: root.symbol.scenes = scenes; michael@0: } else { michael@0: labels = []; michael@0: if (labelName) { michael@0: labelMap[labelName] = frameNum; michael@0: labels.push(new flash.display.FrameLabel(labelName, frameNum)); michael@0: } michael@0: var scene = new flash.display.Scene('Scene 1', labels, root.symbol.totalFrames); michael@0: scene._startFrame = 1; michael@0: scene._endFrame = root.symbol.totalFrames; michael@0: root.symbol.scenes = [ michael@0: scene michael@0: ]; michael@0: } michael@0: if (loader._stage) { michael@0: loader._stage._children[0] = root; michael@0: } michael@0: rootClass.instanceConstructor.call(root); michael@0: loader._content = root; michael@0: } else { michael@0: root._framesLoaded = framesLoaded; michael@0: if (labelName && root._labelMap) { michael@0: if (root._labelMap[labelName] === undefined) { michael@0: root._labelMap[labelName] = frameNum; michael@0: for (var i = 0, n = root.symbol.scenes.length; i < n; i++) { michael@0: var scene = root.symbol.scenes[i]; michael@0: if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) { michael@0: scene.labels.push(new flash.display.FrameLabel(labelName, frameNum - scene._startFrame)); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if (frame.startSounds) { michael@0: root._registerStartSounds(frameNum, frame.startSounds); michael@0: } michael@0: if (frame.soundStream) { michael@0: root._initSoundStream(frame.soundStream); michael@0: } michael@0: if (frame.soundStreamBlock) { michael@0: root._addSoundStreamBlock(frameNum, frame.soundStreamBlock); michael@0: } michael@0: if (!loader._isAvm2Enabled) { michael@0: var avm1Context = loader._avm1Context; michael@0: if (initActionBlocks) { michael@0: for (var i = 0; i < initActionBlocks.length; i++) { michael@0: var spriteId = initActionBlocks[i].spriteId; michael@0: var actionsData = initActionBlocks[i].actionsData; michael@0: root.addFrameScript(frameNum - 1, function (actionsData, spriteId, state) { michael@0: if (state.executed) michael@0: return; michael@0: state.executed = true; michael@0: return executeActions(actionsData, avm1Context, this._getAS2Object()); michael@0: }.bind(root, actionsData, spriteId, { michael@0: executed: false michael@0: })); michael@0: } michael@0: } michael@0: if (actionBlocks) { michael@0: for (var i = 0; i < actionBlocks.length; i++) { michael@0: var block = actionBlocks[i]; michael@0: root.addFrameScript(frameNum - 1, function (block) { michael@0: return function () { michael@0: return executeActions(block, avm1Context, this._getAS2Object()); michael@0: }; michael@0: }(block)); michael@0: } michael@0: } michael@0: } michael@0: if (frameNum === 1) michael@0: loaderInfo._dispatchEvent(new flash.events.Event('init', false, false)); michael@0: framePromiseResolve(frame); michael@0: }); michael@0: }, michael@0: _commitImage: function (imageInfo) { michael@0: var loader = this; michael@0: var imgPromiseResolve; michael@0: var imgPromise = this._lastPromise = new Promise(function (resolve) { michael@0: imgPromiseResolve = resolve; michael@0: }); michael@0: var img = new Image(); michael@0: imageInfo.props.img = img; michael@0: img.onload = function () { michael@0: var Bitmap = avm2.systemDomain.getClass('flash.display.Bitmap'); michael@0: var BitmapData = avm2.systemDomain.getClass('flash.display.BitmapData'); michael@0: var props = imageInfo.props; michael@0: props.parent = loader._parent; michael@0: props.stage = loader._stage; michael@0: props.skipCopyToCanvas = true; michael@0: var bitmapData = BitmapData.createAsSymbol(props); michael@0: BitmapData.instanceConstructor.call(bitmapData, 0, 0, true, 4294967295); michael@0: var image = Bitmap.createAsSymbol(bitmapData); michael@0: Bitmap.instanceConstructor.call(image, bitmapData); michael@0: image._parent = loader; michael@0: loader._children.push(image); michael@0: loader._invalidateBounds(); michael@0: loader._content = image; michael@0: imgPromiseResolve(imageInfo); michael@0: var loaderInfo = loader._contentLoaderInfo; michael@0: loaderInfo._width = image.width; michael@0: loaderInfo._height = image.height; michael@0: loaderInfo._dispatchEvent('init'); michael@0: }; michael@0: img.src = URL.createObjectURL(imageInfo.data); michael@0: imageInfo.data = null; michael@0: }, michael@0: _commitSymbol: function (symbol) { michael@0: var dictionary = this._dictionary; michael@0: var dictionaryResolved = this._dictionaryResolved; michael@0: if ('updates' in symbol) { michael@0: dictionary[symbol.id].then(function (s) { michael@0: for (var i in symbol.updates) { michael@0: s.props[i] = symbol.updates[i]; michael@0: } michael@0: }); michael@0: return; michael@0: } michael@0: var className = 'flash.display.DisplayObject'; michael@0: var dependencies = symbol.require; michael@0: var promiseQueue = []; michael@0: var props = { michael@0: symbolId: symbol.id, michael@0: loader: this michael@0: }; michael@0: var symbolPromiseResolve; michael@0: var symbolPromise = new Promise(function (resolve) { michael@0: symbolPromiseResolve = resolve; michael@0: }); michael@0: if (dependencies && dependencies.length) { michael@0: for (var i = 0, n = dependencies.length; i < n; i++) { michael@0: var dependencyId = dependencies[i]; michael@0: var dependencyPromise = dictionary[dependencyId]; michael@0: if (dependencyPromise && !dictionaryResolved[dependencyId]) michael@0: promiseQueue.push(dependencyPromise); michael@0: } michael@0: } michael@0: switch (symbol.type) { michael@0: case 'button': michael@0: var states = {}; michael@0: for (var stateName in symbol.states) { michael@0: var characters = []; michael@0: var displayList = {}; michael@0: var state = symbol.states[stateName]; michael@0: var depths = Object.keys(state); michael@0: for (var i = 0; i < depths.length; i++) { michael@0: var depth = depths[i]; michael@0: var cmd = state[depth]; michael@0: var characterPromise = dictionary[cmd.symbolId]; michael@0: if (characterPromise && !dictionaryResolved[cmd.symbolId]) { michael@0: promiseQueue.push(characterPromise); michael@0: } michael@0: characters.push(characterPromise); michael@0: displayList[depth] = Object.create(cmd, { michael@0: symbolInfo: { michael@0: get: function (dictionaryResolved, symbolId) { michael@0: return function () { michael@0: return dictionaryResolved[symbolId]; michael@0: }; michael@0: }(dictionaryResolved, cmd.symbolId) michael@0: } michael@0: }); michael@0: } michael@0: depths.sort(sortNumeric); michael@0: displayList.depths = depths; michael@0: states[stateName] = { michael@0: className: 'flash.display.Sprite', michael@0: props: { michael@0: loader: this, michael@0: timeline: [ michael@0: displayList michael@0: ] michael@0: } michael@0: }; michael@0: } michael@0: className = 'flash.display.SimpleButton'; michael@0: props.states = states; michael@0: props.buttonActions = symbol.buttonActions; michael@0: break; michael@0: case 'font': michael@0: var charset = fromCharCode.apply(null, symbol.codes); michael@0: if (charset) { michael@0: style.insertRule('@font-face{font-family:"' + symbol.uniqueName + '";' + 'src:url(data:font/opentype;base64,' + btoa(symbol.data) + ')' + '}', style.cssRules.length); michael@0: if (!/Mozilla\/5.0.*?rv:(\d+).*? Gecko/.test(window.navigator.userAgent)) { michael@0: var testDiv = document.createElement('div'); michael@0: testDiv.setAttribute('style', 'position: absolute; top: 0; right: 0;visibility: hidden; z-index: -500;font-family:"' + symbol.uniqueName + '";'); michael@0: testDiv.textContent = 'font test'; michael@0: document.body.appendChild(testDiv); michael@0: var fontPromise = new Promise(function (resolve) { michael@0: setTimeout(function () { michael@0: resolve(); michael@0: document.body.removeChild(testDiv); michael@0: }, 200); michael@0: }); michael@0: promiseQueue.push(fontPromise); michael@0: } michael@0: } michael@0: className = 'flash.text.Font'; michael@0: props.name = symbol.name; michael@0: props.uniqueName = symbol.uniqueName; michael@0: props.charset = symbol.charset; michael@0: props.bold = symbol.bold; michael@0: props.italic = symbol.italic; michael@0: props.metrics = symbol.metrics; michael@0: this._registerFont(className, props); michael@0: break; michael@0: case 'image': michael@0: var img = new Image(); michael@0: var imgPromiseResolve; michael@0: var imgPromise = new Promise(function (resolve) { michael@0: imgPromiseResolve = resolve; michael@0: }); michael@0: img.onload = function () { michael@0: if (symbol.mask) { michael@0: var maskCanvas = document.createElement('canvas'); michael@0: maskCanvas.width = symbol.width; michael@0: maskCanvas.height = symbol.height; michael@0: var maskContext = maskCanvas.getContext('2d'); michael@0: maskContext.drawImage(img, 0, 0); michael@0: var maskImageData = maskContext.getImageData(0, 0, symbol.width, symbol.height); michael@0: var maskImageDataBytes = maskImageData.data; michael@0: var symbolMaskBytes = symbol.mask; michael@0: var length = maskImageData.width * maskImageData.height; michael@0: for (var i = 0, j = 3; i < length; i++, j += 4) { michael@0: maskImageDataBytes[j] = symbolMaskBytes[i]; michael@0: } michael@0: maskContext.putImageData(maskImageData, 0, 0); michael@0: props.img = maskCanvas; michael@0: } michael@0: imgPromiseResolve(); michael@0: }; michael@0: img.src = URL.createObjectURL(symbol.data); michael@0: promiseQueue.push(imgPromise); michael@0: className = 'flash.display.Bitmap'; michael@0: props.img = img; michael@0: props.width = symbol.width; michael@0: props.height = symbol.height; michael@0: break; michael@0: case 'label': michael@0: var drawFn = new Function('c,r,ct', symbol.data); michael@0: className = 'flash.text.StaticText'; michael@0: props.bbox = symbol.bbox; michael@0: props.draw = drawFn; michael@0: break; michael@0: case 'text': michael@0: props.bbox = symbol.bbox; michael@0: props.html = symbol.html; michael@0: if (symbol.type === 'label') { michael@0: className = 'flash.text.StaticText'; michael@0: } else { michael@0: className = 'flash.text.TextField'; michael@0: props.tag = symbol.tag; michael@0: props.variableName = symbol.variableName; michael@0: } michael@0: break; michael@0: case 'shape': michael@0: className = symbol.morph ? 'flash.display.MorphShape' : 'flash.display.Shape'; michael@0: props.bbox = symbol.bbox; michael@0: props.strokeBbox = symbol.strokeBbox; michael@0: props.paths = symbol.paths; michael@0: props.dictionaryResolved = dictionaryResolved; michael@0: break; michael@0: case 'sound': michael@0: if (!symbol.pcm && !PLAY_USING_AUDIO_TAG) { michael@0: var decodePromiseResolve; michael@0: var decodePromise = new Promise(function (resolve) { michael@0: decodePromiseResolve = resolve; michael@0: }); michael@0: MP3DecoderSession.processAll(symbol.packaged.data, function (props, pcm, id3tags, error) { michael@0: props.pcm = pcm || new Uint8Array(0); michael@0: decodePromiseResolve(); michael@0: if (error) { michael@0: console.error('ERROR: ' + error); michael@0: } michael@0: }.bind(null, props)); michael@0: promiseQueue.push(decodePromise); michael@0: } michael@0: className = 'flash.media.Sound'; michael@0: props.sampleRate = symbol.sampleRate; michael@0: props.channels = symbol.channels; michael@0: props.pcm = symbol.pcm; michael@0: props.packaged = symbol.packaged; michael@0: break; michael@0: case 'binary': michael@0: props.data = symbol.data; michael@0: break; michael@0: case 'sprite': michael@0: var displayList = null; michael@0: var frameCount = symbol.frameCount; michael@0: var labelMap = {}; michael@0: var frameNum = 1; michael@0: var frames = symbol.frames; michael@0: var timeline = []; michael@0: var startSoundRegistrations = []; michael@0: for (var i = 0, n = frames.length; i < n; i++) { michael@0: var frame = frames[i]; michael@0: var frameNum = timeline.length + 1; michael@0: if (frame.labelName) { michael@0: labelMap[frame.labelName] = frameNum; michael@0: } michael@0: if (frame.startSounds) { michael@0: startSoundRegistrations[frameNum] = frame.startSounds; michael@0: for (var j = 0; j < frame.startSounds.length; j++) { michael@0: var soundId = frame.startSounds[j].soundId; michael@0: var itemPromise = dictionary[soundId]; michael@0: if (itemPromise && !dictionaryResolved[soundId]) { michael@0: promiseQueue.push(itemPromise); michael@0: } michael@0: } michael@0: } michael@0: displayList = this._buildFrame(displayList, timeline, promiseQueue, frame, frameNum); michael@0: } michael@0: var frameScripts = {}; michael@0: if (!this._isAvm2Enabled) { michael@0: if (symbol.frameScripts) { michael@0: var data = symbol.frameScripts; michael@0: for (var i = 0; i < data.length; i += 2) { michael@0: var frameNum = data[i] + 1; michael@0: var block = data[i + 1]; michael@0: var script = function (block, loader) { michael@0: return function () { michael@0: var avm1Context = loader._avm1Context; michael@0: return executeActions(block, avm1Context, this._getAS2Object()); michael@0: }; michael@0: }(block, this); michael@0: if (!frameScripts[frameNum]) michael@0: frameScripts[frameNum] = [ michael@0: script michael@0: ]; michael@0: else michael@0: frameScripts[frameNum].push(script); michael@0: } michael@0: } michael@0: } michael@0: className = 'flash.display.MovieClip'; michael@0: props.timeline = timeline; michael@0: props.framesLoaded = frameCount; michael@0: props.labelMap = labelMap; michael@0: props.frameScripts = frameScripts; michael@0: props.totalFrames = frameCount; michael@0: props.startSoundRegistrations = startSoundRegistrations; michael@0: break; michael@0: } michael@0: dictionary[symbol.id] = symbolPromise; michael@0: Promise.all(promiseQueue).then(function () { michael@0: var symbolInfo = { michael@0: className: className, michael@0: props: props michael@0: }; michael@0: dictionaryResolved[symbol.id] = symbolInfo; michael@0: symbolPromiseResolve(symbolInfo); michael@0: }); michael@0: }, michael@0: _registerFont: function (className, props) { michael@0: this._vmPromise.then(function () { michael@0: var fontClass = avm2.applicationDomain.getClass(className); michael@0: var font = fontClass.createAsSymbol(props); michael@0: fontClass.instanceConstructor.call(font); michael@0: }); michael@0: }, michael@0: _init: function (info) { michael@0: var loader = this; michael@0: var loaderInfo = loader._contentLoaderInfo; michael@0: loaderInfo._swfVersion = info.swfVersion; michael@0: var bbox = info.bbox; michael@0: loaderInfo._width = bbox.xMax - bbox.xMin; michael@0: loaderInfo._height = bbox.yMax - bbox.yMin; michael@0: loaderInfo._frameRate = info.frameRate; michael@0: var vmPromiseResolve, vmPromiseReject; michael@0: var vmPromise = new Promise(function (resolve, reject) { michael@0: vmPromiseResolve = resolve; michael@0: vmPromiseReject = reject; michael@0: }); michael@0: vmPromise.resolve = vmPromiseResolve; michael@0: vmPromise.reject = vmPromiseReject; michael@0: var documentPromise = new Promise(function (resolve) { michael@0: vmPromise.then(function () { michael@0: var rootInfo = { michael@0: className: 'flash.display.MovieClip', michael@0: props: { michael@0: totalFrames: info.frameCount michael@0: } michael@0: }; michael@0: loader._dictionaryResolved[0] = rootInfo; michael@0: resolve(rootInfo); michael@0: }); michael@0: }); michael@0: loader._dictionary[0] = documentPromise; michael@0: loader._lastPromise = documentPromise; michael@0: loader._vmPromise = vmPromise; michael@0: loader._isAvm2Enabled = info.fileAttributes.doAbc; michael@0: this._setup(); michael@0: }, michael@0: _load: function (request, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowCodeImport, imageDecodingPolicy) { michael@0: if (flash.net.URLRequest.class.isInstanceOf(request)) { michael@0: this._contentLoaderInfo._url = request._url; michael@0: } michael@0: var worker; michael@0: if (WORKERS_ENABLED) { michael@0: worker = new Worker(SHUMWAY_ROOT + LOADER_PATH); michael@0: } else { michael@0: worker = new ResourceLoader(window); michael@0: } michael@0: var loader = this; michael@0: loader._worker = worker; michael@0: worker.onmessage = function (evt) { michael@0: if (evt.data.type === 'exception') { michael@0: avm2.exceptions.push({ michael@0: source: 'parser', michael@0: message: evt.data.message, michael@0: stack: evt.data.stack michael@0: }); michael@0: } else { michael@0: loader._commitData(evt.data); michael@0: } michael@0: }; michael@0: if (flash.net.URLRequest.class.isInstanceOf(request)) { michael@0: var session = FileLoadingService.createSession(); michael@0: session.onprogress = function (data, progress) { michael@0: worker.postMessage({ michael@0: data: data, michael@0: progress: progress michael@0: }); michael@0: }; michael@0: session.onerror = function (error) { michael@0: loader._commitData({ michael@0: command: 'error', michael@0: error: error michael@0: }); michael@0: }; michael@0: session.onopen = function () { michael@0: worker.postMessage('pipe:'); michael@0: }; michael@0: session.onclose = function () { michael@0: worker.postMessage({ michael@0: data: null michael@0: }); michael@0: }; michael@0: session.open(request._toFileRequest()); michael@0: } else { michael@0: worker.postMessage(request); michael@0: } michael@0: }, michael@0: _setup: function () { michael@0: var loader = this; michael@0: var stage = loader._stage; michael@0: if (loader._isAvm2Enabled) { michael@0: var mouseClass = avm2.systemDomain.getClass('flash.ui.Mouse'); michael@0: mouseClass._stage = stage; michael@0: loader._vmPromise.resolve(); michael@0: return; michael@0: } michael@0: if (!avm2.loadAVM1) { michael@0: loader._vmPromise.reject('AVM1 loader is not found'); michael@0: return; michael@0: } michael@0: var loaded = function () { michael@0: var loaderInfo = loader._contentLoaderInfo; michael@0: var avm1Context = new AS2Context(loaderInfo._swfVersion); michael@0: avm1Context.stage = stage; michael@0: loader._avm1Context = avm1Context; michael@0: avm1lib.AS2Key.class.$bind(stage); michael@0: avm1lib.AS2Mouse.class.$bind(stage); michael@0: stage._addEventListener('frameConstructed', avm1Context.flushPendingScripts.bind(avm1Context), false, Number.MAX_VALUE); michael@0: loader._vmPromise.resolve(); michael@0: }; michael@0: if (avm2.isAVM1Loaded) { michael@0: if (AS2Context.instance) { michael@0: loader._avm1Context = AS2Context.instance; michael@0: loader._vmPromise.resolve(); michael@0: } else { michael@0: loaded(); michael@0: } michael@0: } else { michael@0: avm2.isAVM1Loaded = true; michael@0: avm2.loadAVM1(loaded); michael@0: } michael@0: }, michael@0: get contentLoaderInfo() { michael@0: return this._contentLoaderInfo; michael@0: }, michael@0: get content() { michael@0: somewhatImplemented('Loader.content'); michael@0: return this._content; michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: content: Object.getOwnPropertyDescriptor(def, 'content'), michael@0: contentLoaderInfo: Object.getOwnPropertyDescriptor(def, 'contentLoaderInfo'), michael@0: _getJPEGLoaderContextdeblockingfilter: function (context) { michael@0: return 0; michael@0: }, michael@0: _load: def._load, michael@0: _loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) { michael@0: this._load(bytes.a, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy); michael@0: }, michael@0: _unload: function _unload(halt, gc) { michael@0: somewhatImplemented('Loader._unload, do we even need to do anything here?'); michael@0: }, michael@0: _close: function _close() { michael@0: somewhatImplemented('Loader._close'); michael@0: }, michael@0: _getUncaughtErrorEvents: function _getUncaughtErrorEvents() { michael@0: somewhatImplemented('Loader._getUncaughtErrorEvents'); michael@0: return this._uncaughtErrorEvents; michael@0: }, michael@0: _setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) { michael@0: somewhatImplemented('Loader._setUncaughtErrorEvents'); michael@0: this._uncaughtErrorEvents = value; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var LoaderInfoDefinition = function () { michael@0: function dispatchEvent(event) { michael@0: notImplemented('LoaderInfo.dispatchEvent'); michael@0: } michael@0: return { michael@0: __class__: 'flash.display.LoaderInfo', michael@0: initialize: function () { michael@0: this._actionScriptVersion = null; michael@0: this._backgroundColor = null; michael@0: this._bytes = null; michael@0: this._bytesLoaded = 0; michael@0: this._bytesTotal = 0; michael@0: this._content = null; michael@0: this._contentType = null; michael@0: this._frameRate = null; michael@0: this._height = null; michael@0: this._loader = null; michael@0: this._loaderURL = null; michael@0: this._swfVersion = null; michael@0: this._url = null; michael@0: this._width = null; michael@0: this._uncaughtErrorEvents = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: getLoaderInfoByDefinition: function getLoaderInfoByDefinition(object) { michael@0: notImplemented('LoaderInfo.getLoaderInfoByDefinition'); michael@0: } michael@0: }, michael@0: instance: { michael@0: _getArgs: function _getArgs() { michael@0: var params = this._parameters; michael@0: var mangled = {}; michael@0: for (var k in params) { michael@0: mangled[Multiname.getPublicQualifiedName(k)] = params[k]; michael@0: } michael@0: return mangled; michael@0: }, michael@0: _getUncaughtErrorEvents: function _getUncaughtErrorEvents() { michael@0: somewhatImplemented('Loader._getUncaughtErrorEvents'); michael@0: return this._uncaughtErrorEvents; michael@0: }, michael@0: _setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) { michael@0: somewhatImplemented('Loader._setUncaughtErrorEvents'); michael@0: this._uncaughtErrorEvents = value; michael@0: }, michael@0: loaderURL: { michael@0: get: function loaderURL() { michael@0: return this._loaderURL; michael@0: } michael@0: }, michael@0: url: { michael@0: get: function url() { michael@0: return this._url; michael@0: } michael@0: }, michael@0: isURLInaccessible: { michael@0: get: function isURLInaccessible() { michael@0: return this._isURLInaccessible; michael@0: } michael@0: }, michael@0: bytesLoaded: { michael@0: get: function bytesLoaded() { michael@0: return this._bytesLoaded; michael@0: } michael@0: }, michael@0: bytesTotal: { michael@0: get: function bytesTotal() { michael@0: return this._bytesTotal; michael@0: } michael@0: }, michael@0: applicationDomain: { michael@0: get: function applicationDomain() { michael@0: return new flash.system.ApplicationDomain(avm2.applicationDomain); michael@0: } michael@0: }, michael@0: swfVersion: { michael@0: get: function swfVersion() { michael@0: return this._swfVersion; michael@0: } michael@0: }, michael@0: actionScriptVersion: { michael@0: get: function actionScriptVersion() { michael@0: return this._actionScriptVersion; michael@0: } michael@0: }, michael@0: frameRate: { michael@0: get: function frameRate() { michael@0: return this._frameRate; michael@0: } michael@0: }, michael@0: width: { michael@0: get: function width() { michael@0: return this._width; michael@0: } michael@0: }, michael@0: height: { michael@0: get: function height() { michael@0: return this._height; michael@0: } michael@0: }, michael@0: contentType: { michael@0: get: function contentType() { michael@0: return this._contentType; michael@0: } michael@0: }, michael@0: sharedEvents: { michael@0: get: function sharedEvents() { michael@0: return this._sharedEvents; michael@0: } michael@0: }, michael@0: parentSandboxBridge: { michael@0: get: function parentSandboxBridge() { michael@0: return this._parentSandboxBridge; michael@0: }, michael@0: set: function parentSandboxBridge(door) { michael@0: this._parentSandboxBridge = door; michael@0: } michael@0: }, michael@0: childSandboxBridge: { michael@0: get: function childSandboxBridge() { michael@0: return this._childSandboxBridge; michael@0: }, michael@0: set: function childSandboxBridge(door) { michael@0: this._childSandboxBridge = door; michael@0: } michael@0: }, michael@0: sameDomain: { michael@0: get: function sameDomain() { michael@0: return this._sameDomain; michael@0: } michael@0: }, michael@0: childAllowsParent: { michael@0: get: function childAllowsParent() { michael@0: return this._childAllowsParent; michael@0: } michael@0: }, michael@0: parentAllowsChild: { michael@0: get: function parentAllowsChild() { michael@0: return this._parentAllowsChild; michael@0: } michael@0: }, michael@0: loader: { michael@0: get: function loader() { michael@0: return this._loader; michael@0: } michael@0: }, michael@0: content: { michael@0: get: function content() { michael@0: return this._loader._content; michael@0: } michael@0: }, michael@0: bytes: { michael@0: get: function bytes() { michael@0: return this._bytes; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: scriptProperties('public', [ michael@0: 'swfVersion', michael@0: 'bytesTotal', michael@0: 'bytesLoaded', michael@0: 'parameters', michael@0: 'uncaughtErrorEvent' michael@0: ]) michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var MorphShapeDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.display.MorphShape', michael@0: initialize: function () { michael@0: var graphics = this._graphics = new flash.display.Graphics(); michael@0: var s = this.symbol; michael@0: if (s && s.paths) { michael@0: graphics._paths = s.paths; michael@0: graphics.bbox = s.bbox; michael@0: graphics.strokeBbox = s.strokeBbox; michael@0: if (this._stage && this._stage._quality === 'low' && !graphics._bitmap) michael@0: graphics._cacheAsBitmap(this._bbox); michael@0: } michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: graphics: { michael@0: get: function () { michael@0: return this._graphics; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var MovieClipDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.display.MovieClip', michael@0: initialize: function () { michael@0: this._playHead = 1; michael@0: this._currentFrame = 1; michael@0: this._currentFrameLabel = null; michael@0: this._currentLabel = null; michael@0: this._currentScene = 0; michael@0: this._enabled = true; michael@0: this._frameScripts = {}; michael@0: this._framesLoaded = 1; michael@0: this._isPlaying = false; michael@0: this._labelMap = {}; michael@0: this._sceneFrameMap = {}; michael@0: this._sceneMap = {}; michael@0: this._scenes = null; michael@0: this._timeline = null; michael@0: this._totalFrames = 1; michael@0: this._startSoundRegistrations = []; michael@0: this._allowFrameNavigation = true; michael@0: this._complete = true; michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this._timeline = s.timeline || null; michael@0: this._framesLoaded = s.framesLoaded || 1; michael@0: this._labelMap = Object.create(s.labelMap || null); michael@0: this._frameScripts = Object.create(s.frameScripts || null); michael@0: this._totalFrames = s.totalFrames || 1; michael@0: this._startSoundRegistrations = s.startSoundRegistrations || []; michael@0: this._scenes = s.scenes || null; michael@0: this._complete = s.complete === false ? false : true; michael@0: var map = this._labelMap; michael@0: for (var name in map) { michael@0: var frame = map[name]; michael@0: if (frame == 1) { michael@0: this._currentFrameLabel = this._currentLabel = name; michael@0: } michael@0: } michael@0: } michael@0: this._enterFrame(1); michael@0: var self = this; michael@0: this._onExecuteFrame = function onExecuteFrame() { michael@0: self._removeEventListener('executeFrame', onExecuteFrame); michael@0: self._allowFrameNavigation = false; michael@0: self._callFrame(self._currentFrame); michael@0: self._allowFrameNavigation = true; michael@0: if (self._playHead !== self._currentFrame) { michael@0: self._gotoFrame(self._playHead, true); michael@0: } michael@0: self._postConstructChildren(); michael@0: }; michael@0: this._addEventListener('executeFrame', this._onExecuteFrame); michael@0: if (this._complete && this._totalFrames <= 1) { michael@0: return this; michael@0: } michael@0: this._onAdvanceFrame = function onAdvanceFrame() { michael@0: var frameNum = self._playHead + 1; michael@0: if (self._complete && frameNum > self._totalFrames) { michael@0: frameNum = 1; michael@0: } else if (frameNum > self._framesLoaded) { michael@0: return; michael@0: } michael@0: self._updateDisplayList(frameNum); michael@0: if (self._sparse) { michael@0: self._addEventListener('constructChildren', self._onConstructChildren); michael@0: } michael@0: self._startSounds(frameNum); michael@0: self._enterFrame(frameNum); michael@0: if (frameNum in self._frameScripts) { michael@0: self._addEventListener('executeFrame', self._onExecuteFrame); michael@0: } michael@0: }; michael@0: this._onConstructChildren = function onConstructChildren() { michael@0: self._removeEventListener('constructChildren', onConstructChildren); michael@0: self._constructChildren(); michael@0: }; michael@0: this.play(); michael@0: }, michael@0: _updateDisplayList: function (nextFrameNum) { michael@0: this._destructChildren(nextFrameNum); michael@0: this._declareChildren(nextFrameNum); michael@0: }, michael@0: _declareChildren: function declareChildren(nextFrameNum) { michael@0: var currentFrame = this._currentFrame; michael@0: if (nextFrameNum === currentFrame) { michael@0: return; michael@0: } michael@0: var timeline = this._timeline; michael@0: var nextDisplayList = timeline[nextFrameNum - 1]; michael@0: if (nextDisplayList === timeline[currentFrame - 1]) { michael@0: return; michael@0: } michael@0: var prevDisplayListItem = null; michael@0: var currentDisplayListItem = this._currentDisplayList; michael@0: var children = this._children; michael@0: var depths = nextDisplayList.depths; michael@0: var index = children.length; michael@0: var i = depths.length; michael@0: while (i--) { michael@0: var depth = depths[i], depthInt = depth | 0; michael@0: while (currentDisplayListItem && currentDisplayListItem.depth > depthInt) { michael@0: prevDisplayListItem = currentDisplayListItem; michael@0: currentDisplayListItem = currentDisplayListItem.next; michael@0: } michael@0: var currentChild = null; michael@0: if (currentDisplayListItem && currentDisplayListItem.depth === depthInt) { michael@0: currentChild = currentDisplayListItem.obj; michael@0: if (currentChild && currentChild._owned) { michael@0: index = this.getChildIndex(currentChild); michael@0: } michael@0: } michael@0: var currentCmd = currentDisplayListItem && currentDisplayListItem.depth === depthInt ? currentDisplayListItem.cmd : null; michael@0: var nextCmd = nextDisplayList[depth]; michael@0: if (!nextCmd || nextCmd === currentCmd) { michael@0: continue; michael@0: } michael@0: if (currentCmd && currentChild && nextCmd.symbolId === currentCmd.symbolId && nextCmd.ratio === currentCmd.ratio) { michael@0: if (currentChild._animated) { michael@0: currentChild._invalidate(); michael@0: if (nextCmd.hasMatrix) { michael@0: currentChild._setTransformMatrix(nextCmd.matrix, false); michael@0: } michael@0: if (nextCmd.hasCxform) { michael@0: currentChild._cxform = nextCmd.cxform; michael@0: } michael@0: if (nextCmd.clip) { michael@0: currentChild._clipDepth = nextCmd.clipDepth; michael@0: } michael@0: if (nextCmd.hasName) { michael@0: currentChild.name = nextCmd.name; michael@0: } michael@0: if (nextCmd.blend) { michael@0: currentChild._blendMode = this._resolveBlendMode(nextCmd.blendMode); michael@0: } michael@0: } michael@0: currentDisplayListItem.cmd = nextCmd; michael@0: continue; michael@0: } michael@0: var newDisplayListItem = this._addTimelineChild(nextCmd, index); michael@0: newDisplayListItem.next = currentDisplayListItem; michael@0: if (prevDisplayListItem) { michael@0: prevDisplayListItem.next = newDisplayListItem; michael@0: } else { michael@0: this._currentDisplayList = newDisplayListItem; michael@0: } michael@0: prevDisplayListItem = newDisplayListItem; michael@0: } michael@0: }, michael@0: _destructChildren: function destructChildren(nextFrameNum) { michael@0: var currentFrame = this._currentFrame; michael@0: if (nextFrameNum === currentFrame) { michael@0: return; michael@0: } michael@0: var timeline = this._timeline; michael@0: var nextDisplayList = timeline[nextFrameNum - 1]; michael@0: if (nextDisplayList === timeline[currentFrame - 1]) { michael@0: return; michael@0: } michael@0: var prevEntry = null; michael@0: var currentEntry = this._currentDisplayList; michael@0: var toRemove = null; michael@0: while (currentEntry) { michael@0: var depth = currentEntry.depth; michael@0: var currentCmd = currentEntry.cmd; michael@0: var nextCmd = nextDisplayList[depth]; michael@0: if (!nextCmd || nextCmd.symbolId !== currentCmd.symbolId || nextCmd.ratio !== currentCmd.ratio) { michael@0: var nextDisplayListItem = currentEntry.next; michael@0: if (prevEntry) { michael@0: prevEntry.next = nextDisplayListItem; michael@0: } else { michael@0: this._currentDisplayList = nextDisplayListItem; michael@0: } michael@0: currentEntry.next = toRemove; michael@0: toRemove = currentEntry; michael@0: currentEntry = nextDisplayListItem; michael@0: } else { michael@0: prevEntry = currentEntry; michael@0: currentEntry = currentEntry.next; michael@0: } michael@0: } michael@0: while (toRemove) { michael@0: var child = toRemove.obj; michael@0: if (child && child._owned) { michael@0: this._sparse = true; michael@0: this.removeChild(child); michael@0: child.destroy(); michael@0: if (child._isPlaying) { michael@0: child.stop(); michael@0: } michael@0: } michael@0: toRemove = toRemove.next; michael@0: } michael@0: }, michael@0: _gotoFrame: function gotoFrame(frameNum, execute) { michael@0: var enterFrame = frameNum !== this._currentFrame; michael@0: if (this._allowFrameNavigation || !this._loader._isAvm2Enabled) { michael@0: if (enterFrame) { michael@0: this._updateDisplayList(frameNum); michael@0: this._enterFrame(frameNum); michael@0: } michael@0: this._constructChildren(); michael@0: if (this._loader._isAvm2Enabled && this.loaderInfo._swfVersion >= 10) { michael@0: if (enterFrame) { michael@0: this._addEventListener('executeFrame', this._onExecuteFrame); michael@0: } michael@0: var domain = avm2.systemDomain; michael@0: domain.broadcastMessage('frameConstructed'); michael@0: domain.broadcastMessage('executeFrame'); michael@0: domain.broadcastMessage('exitFrame'); michael@0: return; michael@0: } michael@0: if (enterFrame && (execute || !this._loader._isAvm2Enabled)) { michael@0: this._callFrame(frameNum); michael@0: } michael@0: this._postConstructChildren(); michael@0: return; michael@0: } michael@0: if (enterFrame) { michael@0: this._playHead = frameNum; michael@0: } michael@0: }, michael@0: _enterFrame: function navigate(frameNum) { michael@0: if (frameNum === this._currentFrame) { michael@0: return; michael@0: } michael@0: this._currentFrameLabel = null; michael@0: if (frameNum === 1) { michael@0: this._currentLabel = null; michael@0: } michael@0: var map = this._labelMap; michael@0: for (var name in map) { michael@0: if (map[name] === frameNum) { michael@0: this._currentFrameLabel = this._currentLabel = name; michael@0: break; michael@0: } michael@0: } michael@0: if (this._scenes) { michael@0: var scenes = this._scenes; michael@0: for (var j = 0, n = scenes.length; j < n; j++) { michael@0: var scene = scenes[j]; michael@0: if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) { michael@0: this._currentScene = j; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: this._playHead = this._currentFrame = frameNum; michael@0: }, michael@0: _callFrame: function callFrame(frame) { michael@0: if (isNaN(frame)) { michael@0: frame = this._labelMap[frame]; michael@0: if (frame === undefined) { michael@0: return; michael@0: } michael@0: } michael@0: if (frame in this._frameScripts) { michael@0: var scripts = this._frameScripts[frame]; michael@0: try { michael@0: for (var i = 0, n = scripts.length; i < n; i++) { michael@0: scripts[i].call(this); michael@0: } michael@0: } catch (e) { michael@0: var AVM2_ERROR_TYPE = 2; michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'error', michael@0: error: AVM2_ERROR_TYPE michael@0: }); michael@0: if (false) { michael@0: console.error('error ' + e + ', stack: \n' + e.stack); michael@0: } michael@0: this.stop(); michael@0: throw e; michael@0: } michael@0: } michael@0: }, michael@0: _gotoButtonState: function gotoButtonState(stateName) { michael@0: if (this._enabled) { michael@0: this.gotoLabel('_' + stateName); michael@0: } michael@0: }, michael@0: _getAbsFrameNum: function (frameNum, sceneName) { michael@0: if (frameNum < 1) { michael@0: frameNum = 1; michael@0: } michael@0: if (sceneName && this._scenes && this._scenes.length > 1) { michael@0: var scenes = this._scenes; michael@0: for (var i = 0; i < scenes.length; i++) { michael@0: var scene = scenes[i]; michael@0: if (scene.name === sceneName) { michael@0: frameNum += scene._startFrame - 1; michael@0: if (frameNum > scene._endFrame) { michael@0: frameNum = scene._endFrame; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: if (frameNum > this._framesLoaded) { michael@0: return this._framesLoaded; michael@0: } michael@0: return frameNum; michael@0: }, michael@0: _registerStartSounds: function (frameNum, starts) { michael@0: this._startSoundRegistrations[frameNum] = starts; michael@0: }, michael@0: _initSoundStream: function (streamInfo) { michael@0: this._soundStream = new MovieClipSoundStream(streamInfo, this); michael@0: }, michael@0: _addSoundStreamBlock: function (frameNum, streamBlock) { michael@0: this._soundStream.appendBlock(frameNum, streamBlock); michael@0: }, michael@0: _startSounds: function (frameNum) { michael@0: var starts = this._startSoundRegistrations[frameNum]; michael@0: if (starts) { michael@0: var sounds = this._sounds || (this._sounds = {}); michael@0: var loader = this.loaderInfo._loader; michael@0: for (var i = 0; i < starts.length; i++) { michael@0: var start = starts[i]; michael@0: var symbolId = start.soundId; michael@0: var info = start.soundInfo; michael@0: var sound = sounds[symbolId]; michael@0: if (!sound) { michael@0: var symbolInfo = loader._dictionaryResolved[symbolId]; michael@0: if (!symbolInfo) michael@0: continue; michael@0: var symbolClass = avm2.systemDomain.findClass(symbolInfo.className) ? avm2.systemDomain.getClass(symbolInfo.className) : avm2.applicationDomain.getClass(symbolInfo.className); michael@0: var soundObj = symbolClass.createAsSymbol(symbolInfo.props); michael@0: symbolClass.instanceConstructor.call(soundObj); michael@0: sounds[symbolId] = sound = { michael@0: object: soundObj michael@0: }; michael@0: } michael@0: if (sound.channel) { michael@0: sound.channel.stop(); michael@0: sound.channel = null; michael@0: } michael@0: if (!info.stop) { michael@0: var loops = info.hasLoops ? info.loopCount : 0; michael@0: sound.channel = sound.object.play(0, loops); michael@0: } michael@0: } michael@0: } michael@0: if (this._soundStream) { michael@0: this._soundStream.playFrame(frameNum); michael@0: } michael@0: }, michael@0: _getAS2Object: function () { michael@0: if (!this.$as2Object) { michael@0: if (this._avm1SymbolClass) { michael@0: var nativeObject = this, nativeObjectClass = this._avm1SymbolClass; michael@0: var constructWrapper = function () { michael@0: this.init(nativeObject); michael@0: nativeObjectClass.call(this); michael@0: }; michael@0: constructWrapper.prototype = Object.create(nativeObjectClass.prototype); michael@0: constructWrapper.instanceConstructor = constructWrapper; michael@0: constructWrapper.debugName = 'avm1 '; michael@0: construct(constructWrapper); michael@0: } else { michael@0: new avm1lib.AS2MovieClip(this); michael@0: } michael@0: } michael@0: return this.$as2Object; michael@0: }, michael@0: get currentFrame() { michael@0: var frameNum = this._currentFrame; michael@0: return this._scenes ? frameNum - this.currentScene._startFrame + 1 : frameNum; michael@0: }, michael@0: get currentFrameLabel() { michael@0: return this._currentFrameLabel; michael@0: }, michael@0: get currentLabel() { michael@0: return this._currentLabel; michael@0: }, michael@0: get currentLabels() { michael@0: if (this._scenes) { michael@0: return this._scenes[this._currentScene].labels; michael@0: } else { michael@0: var labels = []; michael@0: var map = this._labelMap; michael@0: for (var name in map) { michael@0: labels.push(new flash.display.FrameLabel(name, map[name])); michael@0: } michael@0: return labels; michael@0: } michael@0: }, michael@0: get currentScene() { michael@0: return this._scenes ? this._scenes[this._currentScene] : new flash.display.Scene('', this.currentLabels, this._framesLoaded); michael@0: }, michael@0: get enabled() { michael@0: return this._enabled; michael@0: }, michael@0: set enabled(val) { michael@0: this._enabled = val; michael@0: }, michael@0: get framesLoaded() { michael@0: return this._framesLoaded; michael@0: }, michael@0: get totalFrames() { michael@0: return this._totalFrames; michael@0: }, michael@0: get scenes() { michael@0: return this._scenes || [ michael@0: new flash.display.Scene('', this.currentLabels, this._framesLoaded) michael@0: ]; michael@0: }, michael@0: get trackAsMenu() { michael@0: return false; michael@0: }, michael@0: set trackAsMenu(val) { michael@0: notImplemented(); michael@0: }, michael@0: addFrameScript: function () { michael@0: var frameScripts = this._frameScripts; michael@0: for (var i = 0, n = arguments.length; i < n; i += 2) { michael@0: var frameNum = arguments[i] + 1; michael@0: var fn = arguments[i + 1]; michael@0: if (!fn) { michael@0: continue; michael@0: } michael@0: var scripts = frameScripts[frameNum]; michael@0: if (scripts) { michael@0: scripts.push(fn); michael@0: } else { michael@0: frameScripts[frameNum] = [ michael@0: fn michael@0: ]; michael@0: } michael@0: if (frameNum === this._currentFrame) { michael@0: this._addEventListener('executeFrame', this._onExecuteFrame); michael@0: } michael@0: } michael@0: }, michael@0: gotoAndPlay: function (frame, scene) { michael@0: this.play(); michael@0: if (isNaN(frame)) { michael@0: this.gotoLabel(frame); michael@0: } else { michael@0: this._gotoFrame(this._getAbsFrameNum(frame, scene)); michael@0: } michael@0: }, michael@0: gotoAndStop: function (frame, scene) { michael@0: this.stop(); michael@0: if (isNaN(frame)) { michael@0: this.gotoLabel(frame); michael@0: } else { michael@0: this._gotoFrame(this._getAbsFrameNum(frame, scene)); michael@0: } michael@0: }, michael@0: gotoLabel: function (labelName) { michael@0: var frameNum = this._labelMap[labelName]; michael@0: if (frameNum !== undefined) { michael@0: this._gotoFrame(frameNum); michael@0: } michael@0: }, michael@0: isPlaying: function () { michael@0: return this._isPlaying; michael@0: }, michael@0: nextFrame: function () { michael@0: this.stop(); michael@0: if (this._currentFrame < this._framesLoaded) { michael@0: this._gotoFrame(this._currentFrame + 1); michael@0: } michael@0: }, michael@0: nextScene: function () { michael@0: if (this._scenes && this._currentScene < this._scenes.length - 1) { michael@0: this._gotoFrame(this._scenes[this._currentScene + 1]._startFrame); michael@0: } michael@0: }, michael@0: play: function () { michael@0: if (this._isPlaying || this._complete && this._totalFrames <= 1) { michael@0: return; michael@0: } michael@0: this._isPlaying = true; michael@0: this._addEventListener('advanceFrame', this._onAdvanceFrame); michael@0: }, michael@0: prevFrame: function () { michael@0: this.stop(); michael@0: if (this._currentFrame > 1) { michael@0: this._gotoFrame(this._currentFrame - 1); michael@0: } michael@0: }, michael@0: prevScene: function () { michael@0: if (this._scenes && this._currentScene > 0) { michael@0: this._gotoFrame(this._scenes[this._currentScene - 1]._startFrame); michael@0: } michael@0: }, michael@0: stop: function () { michael@0: if (!this._isPlaying || this._complete && this._totalFrames <= 1) { michael@0: return; michael@0: } michael@0: this._isPlaying = false; michael@0: this._removeEventListener('advanceFrame', this._onAdvanceFrame); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: currentFrame: desc(def, 'currentFrame'), michael@0: framesLoaded: desc(def, 'framesLoaded'), michael@0: totalFrames: desc(def, 'totalFrames'), michael@0: trackAsMenu: desc(def, 'trackAsMenu'), michael@0: scenes: desc(def, 'scenes'), michael@0: currentScene: desc(def, 'currentScene'), michael@0: currentLabel: desc(def, 'currentLabel'), michael@0: currentFrameLabel: desc(def, 'currentFrameLabel'), michael@0: enabled: desc(def, 'enabled'), michael@0: isPlaying: desc(def, 'isPlaying'), michael@0: play: def.play, michael@0: stop: def.stop, michael@0: nextFrame: def.nextFrame, michael@0: prevFrame: def.prevFrame, michael@0: gotoAndPlay: def.gotoAndPlay, michael@0: gotoAndStop: def.gotoAndStop, michael@0: addFrameScript: def.addFrameScript, michael@0: prevScene: def.prevScene, michael@0: nextScene: def.nextScene michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var MovieClipSoundStream = function () { michael@0: var MP3_MIME_TYPE = 'audio/mpeg'; michael@0: function openMediaSource(soundStream, mediaSource) { michael@0: var sourceBuffer; michael@0: try { michael@0: sourceBuffer = mediaSource.addSourceBuffer(MP3_MIME_TYPE); michael@0: soundStream.mediaSource = mediaSource; michael@0: soundStream.sourceBuffer = sourceBuffer; michael@0: soundStream.rawFrames.forEach(function (data) { michael@0: sourceBuffer.appendBuffer(data); michael@0: }); michael@0: delete soundStream.rawFrames; michael@0: } catch (e) { michael@0: console.error('MediaSource mp3 playback is not supported: ' + e); michael@0: } michael@0: } michael@0: function syncTime(element, movieClip) { michael@0: var initialized = false; michael@0: var startMediaTime, startRealTime; michael@0: element.addEventListener('timeupdate', function (e) { michael@0: if (!initialized) { michael@0: startMediaTime = element.currentTime; michael@0: startRealTime = performance.now(); michael@0: initialized = true; michael@0: movieClip._stage._frameScheduler.startTrackDelta(); michael@0: return; michael@0: } michael@0: var mediaDelta = element.currentTime - startMediaTime; michael@0: var realDelta = performance.now() - startRealTime; michael@0: movieClip._stage._frameScheduler.setDelta(realDelta - mediaDelta * 1000); michael@0: }); michael@0: element.addEventListener('pause', function (e) { michael@0: movieClip._stage._frameScheduler.endTrackDelta(); michael@0: initialized = false; michael@0: }); michael@0: element.addEventListener('seeking', function (e) { michael@0: movieClip._stage._frameScheduler.endTrackDelta(); michael@0: initialized = false; michael@0: }); michael@0: } michael@0: function MovieClipSoundStream(streamInfo, movieClip) { michael@0: this.movieClip = movieClip; michael@0: this.data = { michael@0: sampleRate: streamInfo.sampleRate, michael@0: channels: streamInfo.channels michael@0: }; michael@0: this.seekIndex = []; michael@0: this.position = 0; michael@0: var isMP3 = streamInfo.format === 'mp3'; michael@0: if (isMP3 && PLAY_USING_AUDIO_TAG) { michael@0: var element = document.createElement('audio'); michael@0: element.preload = 'metadata'; michael@0: element.loop = false; michael@0: syncTime(element, movieClip); michael@0: if (element.canPlayType(MP3_MIME_TYPE)) { michael@0: this.element = element; michael@0: if (typeof MediaSource !== 'undefined') { michael@0: var mediaSource = new MediaSource(); michael@0: mediaSource.addEventListener('sourceopen', openMediaSource.bind(null, this, mediaSource)); michael@0: element.src = URL.createObjectURL(mediaSource); michael@0: } else { michael@0: console.warn('MediaSource is not supported'); michael@0: } michael@0: this.rawFrames = []; michael@0: return; michael@0: } michael@0: } michael@0: var totalSamples = streamInfo.samplesCount * streamInfo.channels; michael@0: this.data.pcm = new Float32Array(totalSamples); michael@0: if (isMP3) { michael@0: var soundStream = this; michael@0: soundStream.decoderPosition = 0; michael@0: soundStream.decoderSession = new MP3DecoderSession(); michael@0: soundStream.decoderSession.onframedata = function (frameData) { michael@0: var position = soundStream.decoderPosition; michael@0: soundStream.data.pcm.set(frameData, position); michael@0: soundStream.decoderPosition = position + frameData.length; michael@0: }.bind(this); michael@0: soundStream.decoderSession.onerror = function (error) { michael@0: console.error('ERROR: MP3DecoderSession: ' + error); michael@0: }; michael@0: } michael@0: } michael@0: MovieClipSoundStream.prototype = { michael@0: appendBlock: function (frameNum, streamBlock) { michael@0: var streamPosition = this.position; michael@0: this.seekIndex[frameNum] = streamPosition + streamBlock.seek * this.data.channels; michael@0: this.position = streamPosition + streamBlock.samplesCount * this.data.channels; michael@0: if (this.sourceBuffer) { michael@0: this.sourceBuffer.appendBuffer(streamBlock.data); michael@0: return; michael@0: } michael@0: if (this.rawFrames) { michael@0: this.rawFrames.push(streamBlock.data); michael@0: return; michael@0: } michael@0: var decoderSession = this.decoderSession; michael@0: if (decoderSession) { michael@0: decoderSession.pushAsync(streamBlock.data); michael@0: } else { michael@0: this.data.pcm.set(streamBlock.pcm, streamPosition); michael@0: } michael@0: }, michael@0: playFrame: function (frameNum) { michael@0: if (isNaN(this.seekIndex[frameNum])) { michael@0: return; michael@0: } michael@0: var PAUSE_WHEN_OF_SYNC_GREATER = 1; michael@0: var PLAYBACK_ADJUSTMENT = 0.25; michael@0: var element = this.element; michael@0: if (element) { michael@0: var soundStreamData = this.data; michael@0: var time = this.seekIndex[frameNum] / soundStreamData.sampleRate / soundStreamData.channels; michael@0: if (!this.channel && (this.movieClip._complete || this.sourceBuffer)) { michael@0: if (!this.sourceBuffer) { michael@0: var blob = new Blob(this.rawFrames); michael@0: element.src = URL.createObjectURL(blob); michael@0: } michael@0: var symbolClass = flash.media.SoundChannel.class; michael@0: var channel = symbolClass.createAsSymbol({ michael@0: element: element michael@0: }); michael@0: symbolClass.instanceConstructor.call(channel); michael@0: this.channel = channel; michael@0: this.expectedFrame = 0; michael@0: this.waitFor = 0; michael@0: } else if (this.sourceBuffer || !isNaN(element.duration)) { michael@0: if (this.mediaSource && this.movieClip._complete) { michael@0: this.mediaSource.endOfStream(); michael@0: this.mediaSource = null; michael@0: } michael@0: var elementTime = element.currentTime; michael@0: if (this.expectedFrame !== frameNum) { michael@0: if (element.paused) { michael@0: element.play(); michael@0: element.addEventListener('playing', function setTime(e) { michael@0: element.removeEventListener('playing', setTime); michael@0: element.currentTime = time; michael@0: }); michael@0: } else { michael@0: element.currentTime = time; michael@0: } michael@0: } else if (this.waitFor > 0) { michael@0: if (this.waitFor <= time) { michael@0: if (element.paused) { michael@0: element.play(); michael@0: } michael@0: this.waitFor = 0; michael@0: } michael@0: } else if (elementTime - time > PAUSE_WHEN_OF_SYNC_GREATER) { michael@0: console.warn('Sound is faster than frames by ' + (elementTime - time)); michael@0: this.waitFor = elementTime - PLAYBACK_ADJUSTMENT; michael@0: element.pause(); michael@0: } else if (time - elementTime > PAUSE_WHEN_OF_SYNC_GREATER) { michael@0: console.warn('Sound is slower than frames by ' + (time - elementTime)); michael@0: element.currentTime = time + PLAYBACK_ADJUSTMENT; michael@0: } michael@0: this.expectedFrame = frameNum + 1; michael@0: } michael@0: } else if (!this.sound) { michael@0: var symbolClass = flash.media.Sound.class; michael@0: var sound = symbolClass.createAsSymbol(this.data); michael@0: symbolClass.instanceConstructor.call(sound); michael@0: var channel = sound.play(); michael@0: this.sound = sound; michael@0: this.channel = channel; michael@0: } michael@0: } michael@0: }; michael@0: return MovieClipSoundStream; michael@0: }(); michael@0: var NativeMenuDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.NativeMenu', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var NativeMenuItemDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.NativeMenuItem', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: enabled: { michael@0: get: function enabled() { michael@0: somewhatImplemented('NativeMenuItem.enabled'); michael@0: return this._enabled; michael@0: }, michael@0: set: function enabled(isSeparator) { michael@0: somewhatImplemented('NativeMenuItem.enabled'); michael@0: this._enabled = isSeparator; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SceneDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.Scene', michael@0: initialize: function () { michael@0: this._startFrame = 1; michael@0: this._endFrame = 1; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: {} michael@0: }, michael@0: script: { michael@0: static: {}, michael@0: instance: { michael@0: name: { michael@0: get: function name() { michael@0: notImplemented('Scene.name'); michael@0: return this._name; michael@0: } michael@0: }, michael@0: labels: { michael@0: get: function labels() { michael@0: notImplemented('Scene.labels'); michael@0: return this._labels; michael@0: } michael@0: }, michael@0: numFrames: { michael@0: get: function numFrames() { michael@0: notImplemented('Scene.numFrames'); michael@0: return this._numFrames; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ShaderDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.Shader', michael@0: initialize: function () { michael@0: this._data = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: data: { michael@0: get: function data() { michael@0: return this._data; michael@0: }, michael@0: set: function data(p) { michael@0: this._data = p; michael@0: } michael@0: }, michael@0: precisionHint: { michael@0: get: function precisionHint() { michael@0: return this._precisionHint; michael@0: }, michael@0: set: function precisionHint(p) { michael@0: this._precisionHint = p; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ShaderDataDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.ShaderData', michael@0: initialize: function () { michael@0: this._byteCode = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: _setByteCode: function _setByteCode(code) { michael@0: this._byteCode = code; michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ShapeDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.display.Shape', michael@0: initialize: function () { michael@0: var graphics = this._graphics = new flash.display.Graphics(); michael@0: graphics._parent = this; michael@0: var s = this.symbol; michael@0: if (s && s.paths) { michael@0: graphics._paths = s.paths; michael@0: for (var i = 0; i < s.paths.length; i++) { michael@0: s.paths[i] = finishShapePath(s.paths[i], s.dictionaryResolved); michael@0: } michael@0: graphics.bbox = s.bbox; michael@0: graphics.strokeBbox = s.strokeBbox; michael@0: if (this._stage && this._stage._quality === 'low' && !graphics._bitmap) michael@0: graphics._cacheAsBitmap(this._bbox); michael@0: this.ratio = s.ratio || 0; michael@0: } michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: graphics: { michael@0: get: function () { michael@0: return this._graphics; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var SimpleButtonDefinition = function () { michael@0: var AVM1KeyCodeMap = [ michael@0: 0, michael@0: 37, michael@0: 39, michael@0: 36, michael@0: 35, michael@0: 45, michael@0: 46, michael@0: 0, michael@0: 8, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 0, michael@0: 13, michael@0: 38, michael@0: 40, michael@0: 33, michael@0: 34, michael@0: 9, michael@0: 27 michael@0: ]; michael@0: var AVM1MouseTransitionEvents = [ michael@0: 0, michael@0: 0, michael@0: 1, michael@0: 128, michael@0: 64, michael@0: 0, michael@0: 0, michael@0: 32, michael@0: 2, michael@0: 0, michael@0: 0, michael@0: 4, michael@0: 256, michael@0: 16, michael@0: 8, michael@0: 0 michael@0: ]; michael@0: return { michael@0: __class__: 'flash.display.SimpleButton', michael@0: initialize: function () { michael@0: this._useHandCursor = true; michael@0: this._enabled = true; michael@0: this._trackAsMenu = false; michael@0: this._upState = null; michael@0: this._overState = null; michael@0: this._downState = null; michael@0: this._hitTestState = null; michael@0: this._currentButtonState = 'up'; michael@0: this._mouseChildren = false; michael@0: this._buttonMode = true; michael@0: this._prevAvm1StateCode = 0; michael@0: this._avm1StateCode = 0; michael@0: this._avm1MouseEvents = null; michael@0: this._isContainer = true; michael@0: var s = this.symbol; michael@0: if (s) { michael@0: var states = s.states; michael@0: if (states.down) { michael@0: this._downState = this._constructState(states.down, this); michael@0: } michael@0: if (states.hitTest) { michael@0: this._hitTestState = this._constructState(states.hitTest, this); michael@0: } michael@0: if (states.over) { michael@0: this._overState = this._constructState(states.over, this); michael@0: } michael@0: if (states.up) { michael@0: this._upState = this._constructState(states.up, this); michael@0: } michael@0: } michael@0: if (this._loader && !this._loader._isAvm2Enabled && s && s.buttonActions) { michael@0: this._addEventListener('addedToStage', function (e) { michael@0: this._initAvm1Events(s.buttonActions); michael@0: }.bind(this), false); michael@0: } michael@0: }, michael@0: _constructState: function constructState(symbolInfo) { michael@0: var symbolClass = avm2.systemDomain.findClass(symbolInfo.className) ? avm2.systemDomain.getClass(symbolInfo.className) : avm2.applicationDomain.getClass(symbolInfo.className); michael@0: var instance = symbolClass.createAsSymbol(symbolInfo.props); michael@0: symbolClass.instanceConstructor.call(instance); michael@0: if (instance._children.length === 1) { michael@0: instance = instance._children[0]; michael@0: instance._parent = null; michael@0: instance._index = -1; michael@0: } michael@0: return instance; michael@0: }, michael@0: _updateButton: function updateButton() { michael@0: var state = null; michael@0: switch (this._currentButtonState) { michael@0: case 'up': michael@0: state = this._upState; michael@0: break; michael@0: case 'over': michael@0: state = this._overState; michael@0: break; michael@0: case 'down': michael@0: state = this._downState; michael@0: break; michael@0: } michael@0: if (!state) { michael@0: return; michael@0: } michael@0: var currentChild = this._children[0]; michael@0: if (currentChild) { michael@0: if (currentChild === state) { michael@0: return; michael@0: } michael@0: if (this._stage) { michael@0: this._stage._removeFromStage(currentChild); michael@0: } michael@0: currentChild._invalidateTransform(); michael@0: } michael@0: if (!state) { michael@0: this._children.shift(); michael@0: return; michael@0: } michael@0: this._children[0] = state; michael@0: state._parent = this; michael@0: state._invalidateTransform(); michael@0: if (this._stage) { michael@0: this._stage._addToStage(state); michael@0: } michael@0: }, michael@0: _gotoButtonState: function gotoButtonState(buttonState) { michael@0: this._invalidateBounds(); michael@0: this._currentButtonState = buttonState; michael@0: this._updateButton(); michael@0: if (this._avm1MouseEvents) { michael@0: this._processAvm1MouseEvents(this._avm1MouseEvents); michael@0: } michael@0: }, michael@0: _getRegion: function getRegion(targetCoordSpace) { michael@0: if (!this._hitTestState) { michael@0: return { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: 0, michael@0: yMax: 0 michael@0: }; michael@0: } michael@0: var b = this._hitTestState.getBounds(null); michael@0: return this._getTransformedRect(b, targetCoordSpace); michael@0: }, michael@0: _getAS2Object: function () { michael@0: if (!this.$as2Object) { michael@0: new avm1lib.AS2Button(this); michael@0: } michael@0: return this.$as2Object; michael@0: }, michael@0: _initAvm1Events: function (buttonActions) { michael@0: var loader = this._loader; michael@0: var avm1Context = loader._avm1Context; michael@0: var keyEvents = null; michael@0: for (var i = 0; i < buttonActions.length; i++) { michael@0: var buttonAction = buttonActions[i]; michael@0: var fn = function (actionBlock) { michael@0: return executeActions(actionBlock, avm1Context, this._getAS2Object()); michael@0: }.bind(this.parent, buttonAction.actionsData); michael@0: var mouseEventFlags = buttonAction.mouseEventFlags; michael@0: if (mouseEventFlags) { michael@0: var mouseEvents = this._avm1MouseEvents || (this._avm1MouseEvents = []); michael@0: mouseEvents.push({ michael@0: flags: mouseEventFlags, michael@0: listener: fn michael@0: }); michael@0: } michael@0: var keyPress = buttonAction.keyPress; michael@0: if (keyPress) { michael@0: keyEvents = keyEvents || (keyEvents = []); michael@0: keyEvents.push({ michael@0: keyCode: AVM1KeyCodeMap[keyPress] || 0, michael@0: charCode: keyPress, michael@0: listener: fn michael@0: }); michael@0: } michael@0: } michael@0: if (keyEvents) { michael@0: var keyListener = function (e) { michael@0: for (var i = 0; i < keyEvents.length; i++) { michael@0: var keyEvent = keyEvents[i]; michael@0: if (keyEvent.keyCode ? keyEvent.keyCode === e.keyCode : keyEvent.charCode === e.charCode) { michael@0: keyEvent.listener(); michael@0: } michael@0: } michael@0: }; michael@0: var KeyboardEventClass = flash.events.KeyboardEvent; michael@0: this.stage._addEventListener(KeyboardEventClass.class.KEY_DOWN, keyListener, false); michael@0: this._addEventListener('removedFromStage', function (stage) { michael@0: stage._removeEventListener(KeyboardEventClass.class.KEY_DOWN, keyListener, false); michael@0: }.bind(this, this.stage), false); michael@0: } michael@0: }, michael@0: _processAvm1MouseEvents: function (mouseEvents) { michael@0: var prevAvm1StateCode = this._avm1StateCode; michael@0: var avm1StateCode = (this._currentButtonState === 'down' ? 1 : 0) | (this._currentButtonState !== 'up' ? 2 : 0); michael@0: if (prevAvm1StateCode !== avm1StateCode) { michael@0: this._prevAvm1StateCode = prevAvm1StateCode; michael@0: this._avm1StateCode = avm1StateCode; michael@0: var flag = AVM1MouseTransitionEvents[prevAvm1StateCode << 2 | avm1StateCode]; michael@0: for (var i = 0; i < mouseEvents.length; i++) { michael@0: var mouseEvent = mouseEvents[i]; michael@0: if ((mouseEvent.flags & flag) !== 0) { michael@0: mouseEvent.listener(); michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: _updateButton: function _updateButton() { michael@0: this._updateButton(); michael@0: }, michael@0: useHandCursor: { michael@0: get: function useHandCursor() { michael@0: return this._useHandCursor; michael@0: }, michael@0: set: function useHandCursor(value) { michael@0: this._useHandCursor = value; michael@0: } michael@0: }, michael@0: enabled: { michael@0: get: function enabled() { michael@0: return this._enabled; michael@0: }, michael@0: set: function enabled(value) { michael@0: this._enabled = value; michael@0: } michael@0: }, michael@0: trackAsMenu: { michael@0: get: function trackAsMenu() { michael@0: notImplemented('SimpleButton.trackAsMenu'); michael@0: return this._trackAsMenu; michael@0: }, michael@0: set: function trackAsMenu(value) { michael@0: notImplemented('SimpleButton.trackAsMenu'); michael@0: this._trackAsMenu = value; michael@0: } michael@0: }, michael@0: upState: { michael@0: get: function upState() { michael@0: return this._upState; michael@0: }, michael@0: set: function upState(value) { michael@0: this._upState = value; michael@0: this._updateButton(); michael@0: } michael@0: }, michael@0: overState: { michael@0: get: function overState() { michael@0: return this._overState; michael@0: }, michael@0: set: function overState(value) { michael@0: this._overState = value; michael@0: this._updateButton(); michael@0: } michael@0: }, michael@0: downState: { michael@0: get: function downState() { michael@0: return this._downState; michael@0: }, michael@0: set: function downState(value) { michael@0: this._downState = value; michael@0: this._updateButton(); michael@0: } michael@0: }, michael@0: hitTestState: { michael@0: get: function hitTestState() { michael@0: return this._hitTestState; michael@0: }, michael@0: set: function hitTestState(value) { michael@0: if (value === this._hitTestState) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: this._hitTestState = value; michael@0: } michael@0: }, michael@0: soundTransform: { michael@0: get: function soundTransform() { michael@0: notImplemented('SimpleButton.soundTransform'); michael@0: return this._soundTransform; michael@0: }, michael@0: set: function soundTransform(value) { michael@0: notImplemented('SimpleButton.soundTransform'); michael@0: this._soundTransform = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SpriteDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.display.Sprite', michael@0: initialize: function () { michael@0: this._buttonMode = false; michael@0: this._hitArea = null; michael@0: this._useHandCursor = true; michael@0: this._hitTarget = null; michael@0: this._currentDisplayList = null; michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this._graphics = s.graphics || new flash.display.Graphics(); michael@0: if (s.timeline) { michael@0: var displayList = s.timeline[0]; michael@0: if (displayList) { michael@0: var depths = displayList.depths; michael@0: for (var i = 0; i < depths.length; i++) { michael@0: var cmd = displayList[depths[i]]; michael@0: if (cmd) { michael@0: var displayListItem = this._addTimelineChild(cmd); michael@0: displayListItem.next = this._currentDisplayList; michael@0: this._currentDisplayList = displayListItem; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: this._graphics = new flash.display.Graphics(); michael@0: } michael@0: this._graphics._parent = this; michael@0: }, michael@0: _addTimelineChild: function addTimelineChild(cmd, index) { michael@0: var symbolInfo = cmd.symbolInfo; michael@0: var props = Object.create(symbolInfo.props); michael@0: props.symbolId = cmd.symbolId; michael@0: props.depth = cmd.depth; michael@0: if (cmd.clip) { michael@0: props.clipDepth = cmd.clipDepth; michael@0: } michael@0: if (cmd.hasCxform) { michael@0: props.cxform = cmd.cxform; michael@0: } michael@0: if (cmd.hasMatrix) { michael@0: props.currentTransform = cmd.matrix; michael@0: } michael@0: if (cmd.hasName) { michael@0: props.name = cmd.name; michael@0: } michael@0: if (cmd.hasRatio) { michael@0: props.ratio = cmd.ratio / 65535; michael@0: } michael@0: if (cmd.blend) { michael@0: props.blendMode = cmd.blendMode; michael@0: } michael@0: var displayListItem = { michael@0: cmd: cmd, michael@0: depth: cmd.depth, michael@0: className: symbolInfo.className, michael@0: props: props, michael@0: events: cmd.events, michael@0: obj: null michael@0: }; michael@0: if (index !== undefined) { michael@0: this._children.splice(index, 0, displayListItem); michael@0: } else { michael@0: this._children.push(displayListItem); michael@0: } michael@0: this._sparse = true; michael@0: return displayListItem; michael@0: }, michael@0: _constructChildren: function () { michael@0: if (!this._sparse) { michael@0: return; michael@0: } michael@0: var loader = this._loader; michael@0: var children = this._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var displayListItem = children[i]; michael@0: Counter.count('constructChild'); michael@0: if (flash.display.DisplayObject.class.isInstanceOf(displayListItem)) { michael@0: displayListItem._index = i; michael@0: } else { michael@0: var symbolClass = avm2.systemDomain.findClass(displayListItem.className) ? avm2.systemDomain.getClass(displayListItem.className) : avm2.applicationDomain.getClass(displayListItem.className); michael@0: var props = Object.create(displayListItem.props); michael@0: var name = props.name; michael@0: props.animated = true; michael@0: props.owned = true; michael@0: props.parent = this; michael@0: props.stage = this._stage; michael@0: if (this._level > -1) { michael@0: props.level = this._level + 1; michael@0: } michael@0: props.index = i; michael@0: var instance = symbolClass.createAsSymbol(props); michael@0: if (name) { michael@0: this[Multiname.getPublicQualifiedName(name)] = instance; michael@0: } michael@0: symbolClass.instanceConstructor.call(instance); michael@0: if (flash.display.BitmapData.class.isInstanceOf(instance)) { michael@0: var bitmapData = instance; michael@0: instance = flash.display.Bitmap.class.createAsSymbol(props); michael@0: flash.display.Bitmap.class.instanceConstructor.call(instance, bitmapData); michael@0: } michael@0: if (!loader._isAvm2Enabled) { michael@0: this._initAvm1Bindings(instance, name, displayListItem.events); michael@0: instance._dispatchEvent('init'); michael@0: instance._dispatchEvent('construct'); michael@0: instance._needLoadEvent = true; michael@0: } else { michael@0: instance._dispatchEvent('load'); michael@0: } michael@0: instance._dispatchEvent('added', undefined, true); michael@0: if (this._stage) { michael@0: this._stage._addToStage(instance); michael@0: } michael@0: children[i] = instance; michael@0: displayListItem.obj = instance; michael@0: } michael@0: } michael@0: this._sparse = false; michael@0: }, michael@0: _postConstructChildren: function () { michael@0: var loader = this._loader; michael@0: if (!loader || loader._isAvm2Enabled) { michael@0: return; michael@0: } michael@0: var children = this._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var instance = children[i]; michael@0: if (instance._needLoadEvent) { michael@0: instance._needLoadEvent = false; michael@0: instance._dispatchEvent('load'); michael@0: } michael@0: } michael@0: }, michael@0: _duplicate: function (name, depth, initObject) { michael@0: var loader = this._loader; michael@0: var parent = this._parent; michael@0: var children = parent._children; michael@0: var symbolClass = this.class; michael@0: var symbolInfo = this.symbol; michael@0: var props = Object.create(symbolInfo); michael@0: props.name = name; michael@0: props.parent = parent; michael@0: props.depth = depth; michael@0: var instance = symbolClass.createAsSymbol(props); michael@0: if (name && loader && !loader._isAvm2Enabled && !parent.asHasProperty(undefined, name, 0, false)) { michael@0: parent.asSetPublicProperty(name, instance); michael@0: } michael@0: symbolClass.instanceConstructor.call(instance); michael@0: instance._index = children.length; michael@0: children.push(instance); michael@0: if (!loader._isAvm2Enabled) { michael@0: parent._initAvm1Bindings(instance, name, symbolInfo && symbolInfo.events); michael@0: instance._dispatchEvent('init'); michael@0: instance._dispatchEvent('construct'); michael@0: } michael@0: instance._dispatchEvent('load'); michael@0: instance._dispatchEvent('added'); michael@0: if (this._stage) { michael@0: instance._invalidate(); michael@0: } michael@0: return instance; michael@0: }, michael@0: _insertChildAtDepth: function (child, depth) { michael@0: this.addChild(child); michael@0: var name = child._name; michael@0: var loader = this._loader; michael@0: if (name && loader && !loader._isAvm2Enabled && !this._getAS2Object().asHasProperty(undefined, name, 0, true)) { michael@0: this._getAS2Object().asSetPublicProperty(name, child._getAS2Object()); michael@0: } michael@0: }, michael@0: _initAvm1Bindings: function (instance, name, events) { michael@0: var loader = this._loader; michael@0: var avm1Context = loader._avm1Context; michael@0: var symbolProps = instance.symbol; michael@0: if (symbolProps && symbolProps.variableName) { michael@0: instance._getAS2Object().asSetPublicProperty('variable', symbolProps.variableName); michael@0: } michael@0: if (events) { michael@0: var eventsBound = []; michael@0: for (var i = 0; i < events.length; i++) { michael@0: var event = events[i]; michael@0: if (event.eoe) { michael@0: break; michael@0: } michael@0: var fn = function (actionBlock) { michael@0: return executeActions(actionBlock, avm1Context, this._getAS2Object()); michael@0: }.bind(instance, event.actionsData); michael@0: for (var eventName in event) { michael@0: if (eventName.indexOf('on') !== 0 || !event[eventName]) michael@0: continue; michael@0: var avm2EventName = eventName[2].toLowerCase() + eventName.substring(3); michael@0: if (avm2EventName === 'enterFrame') { michael@0: avm2EventName = 'frameConstructed'; michael@0: } michael@0: var avm2EventTarget = instance; michael@0: if (avm2EventName === 'mouseDown' || avm2EventName === 'mouseUp' || avm2EventName === 'mouseMove') { michael@0: avm2EventTarget = this._stage; michael@0: } michael@0: avm2EventTarget._addEventListener(avm2EventName, fn, false); michael@0: eventsBound.push({ michael@0: name: avm2EventName, michael@0: fn: fn, michael@0: target: avm2EventTarget michael@0: }); michael@0: } michael@0: } michael@0: if (eventsBound.length > 0) { michael@0: instance._addEventListener('removed', function (eventsBound) { michael@0: for (var i = 0; i < eventsBound.length; i++) { michael@0: eventsBound[i].target._removeEventListener(eventsBound[i].name, eventsBound[i].fn, false); michael@0: } michael@0: }.bind(instance, eventsBound), false); michael@0: } michael@0: } michael@0: if (name && this._getAS2Object && instance._getAS2Object) { michael@0: this._getAS2Object().asSetPublicProperty(name, instance._getAS2Object()); michael@0: } michael@0: }, michael@0: _gotoButtonState: function gotoButtonState(stateName) { michael@0: }, michael@0: get buttonMode() { michael@0: return this._buttonMode; michael@0: }, michael@0: set buttonMode(val) { michael@0: this._buttonMode = val; michael@0: }, michael@0: get graphics() { michael@0: return this._graphics; michael@0: }, michael@0: get hitArea() { michael@0: return this._hitArea; michael@0: }, michael@0: set hitArea(val) { michael@0: if (this._hitArea === val) { michael@0: return; michael@0: } michael@0: if (val && val._hitTarget) { michael@0: val._hitTarget.hitArea = null; michael@0: } michael@0: this._hitArea = val; michael@0: if (val) { michael@0: val._hitTarget = this; michael@0: } michael@0: }, michael@0: get soundTransform() { michael@0: notImplemented(); michael@0: }, michael@0: set soundTransform(val) { michael@0: notImplemented(); michael@0: }, michael@0: get useHandCursor() { michael@0: return this._useHandCursor; michael@0: }, michael@0: set useHandCursor(val) { michael@0: this._useHandCursor = val; michael@0: if (this._stage) { michael@0: this._stage._mouseMoved = true; michael@0: } michael@0: }, michael@0: startDrag: function (lockCenter, bounds) { michael@0: notImplemented(); michael@0: }, michael@0: startTouchDrag: function (touchPointID, lockCenter, bounds) { michael@0: notImplemented(); michael@0: }, michael@0: stopDrag: function () { michael@0: notImplemented(); michael@0: }, michael@0: stopTouchDrag: function (touchPointID) { michael@0: notImplemented(); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: graphics: desc(def, 'graphics'), michael@0: buttonMode: desc(def, 'buttonMode'), michael@0: dropTarget: desc(def, 'dropTarget'), michael@0: startDrag: def.startDrag, michael@0: stopDrag: def.stopDrag, michael@0: startTouchDrag: def.startTouchDrag, michael@0: stopTouchDrag: def.stopTouchDrag, michael@0: constructChildren: def._constructChildren, michael@0: hitArea: desc(def, 'hitArea'), michael@0: useHandCursor: desc(def, 'useHandCursor'), michael@0: soundTransform: desc(def, 'soundTransform') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var StageDefinition = function () { michael@0: return { michael@0: __class__: 'flash.display.Stage', michael@0: initialize: function () { michael@0: this._frameRate = 24; michael@0: this._scaleMode = 'showAll'; michael@0: this._align = ''; michael@0: this._stageWidth = 0; michael@0: this._stageHeight = 0; michael@0: this._quality = 'high'; michael@0: this._color = 4294967295; michael@0: this._stage = this; michael@0: this._deferRenderEvent = false; michael@0: this._focus = null; michael@0: this._showDefaultContextMenu = true; michael@0: this._displayState = 'normal'; michael@0: this._colorCorrection = 'default'; michael@0: this._stageFocusRect = true; michael@0: this._fullScreenSourceRect = null; michael@0: this._wmodeGPU = false; michael@0: this._root = null; michael@0: this._qtree = null; michael@0: this._invalidRegions = new RegionCluster(); michael@0: this._mouseMoved = false; michael@0: this._mouseTarget = this; michael@0: this._mouseEvents = []; michael@0: this._cursor = 'auto'; michael@0: this._stageVideos = []; michael@0: this._concatenatedTransform.invalid = false; michael@0: }, michael@0: _setup: function setup(ctx, options) { michael@0: this._qtree = new QuadTree(0, 0, this._stageWidth, this._stageHeight, null); michael@0: this._invalid = true; michael@0: }, michael@0: _addToStage: function addToStage(displayObject) { michael@0: displayObject._stage = this; michael@0: var parent = displayObject._parent; michael@0: displayObject._level = parent._level + 1; michael@0: displayObject._invalid = true; michael@0: var children = displayObject._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var child = children[i]; michael@0: if (child._stage === null) { michael@0: this._addToStage(child); michael@0: } michael@0: } michael@0: displayObject._dispatchEvent('addedToStage'); michael@0: }, michael@0: _removeFromStage: function removeFromStage(displayObject) { michael@0: var children = displayObject._children; michael@0: for (var i = 0; i < children.length; i++) { michael@0: var child = children[i]; michael@0: if (child._stage) { michael@0: this._removeFromStage(children[i]); michael@0: } michael@0: } michael@0: displayObject._dispatchEvent('removedFromStage'); michael@0: displayObject._stage = null; michael@0: displayObject._level = -1; michael@0: if (displayObject._region) { michael@0: this._qtree.remove(displayObject._region); michael@0: this._invalidRegions.insert(displayObject._region); michael@0: displayObject._region = null; michael@0: } michael@0: }, michael@0: _processInvalidations: function processInvalidations(refreshStage) { michael@0: var qtree = this._qtree; michael@0: var invalidRegions = this._invalidRegions; michael@0: var stack = []; michael@0: var zindex = 0; michael@0: var children = this._children; michael@0: var i = children.length; michael@0: while (i--) { michael@0: var child = children[i]; michael@0: if (refreshStage) { michael@0: child._invalid = true; michael@0: } michael@0: child._invisible = !child._visible; michael@0: stack.push(child); michael@0: } michael@0: while (stack.length) { michael@0: var node = stack.pop(); michael@0: var m = node._concatenatedTransform; michael@0: var children = node._children; michael@0: var i = children.length; michael@0: while (i--) { michael@0: var child = children[i]; michael@0: if (!flash.display.DisplayObject.class.isInstanceOf(child)) { michael@0: continue; michael@0: } michael@0: if (node._invalid) { michael@0: child._invalid = true; michael@0: } michael@0: if (m.invalid) { michael@0: child._concatenatedTransform.invalid = true; michael@0: } michael@0: child._invisible = node._invisible || !child._visible; michael@0: stack.push(child); michael@0: } michael@0: if (node._level && m.invalid) { michael@0: var m2 = node._currentTransform; michael@0: var m3 = node._parent._concatenatedTransform; michael@0: m.a = m2.a * m3.a + m2.b * m3.c; michael@0: m.b = m2.a * m3.b + m2.b * m3.d; michael@0: m.c = m2.c * m3.a + m2.d * m3.c; michael@0: m.d = m2.d * m3.d + m2.c * m3.b; michael@0: m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c; michael@0: m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b; michael@0: m.invalid = false; michael@0: } michael@0: var invalidRegion = node._region; michael@0: var currentRegion = node._getRegion(m); michael@0: var hidden = node._invisible || !currentRegion || currentRegion.xMax - currentRegion.xMin === 0 || currentRegion.yMax - currentRegion.yMin === 0 || currentRegion.xMax <= 0 || currentRegion.xMin >= this._stageWidth || currentRegion.yMax <= 0 || currentRegion.yMin >= this._stageHeight; michael@0: if (node._invalid) { michael@0: if (invalidRegion) { michael@0: invalidRegions.insert(invalidRegion); michael@0: } michael@0: if (!hidden && (!invalidRegion || currentRegion.xMin !== invalidRegion.xMin || currentRegion.yMin !== invalidRegion.yMin || currentRegion.xMax !== invalidRegion.xMax || currentRegion.yMax !== invalidRegion.yMax)) { michael@0: invalidRegions.insert(currentRegion); michael@0: } michael@0: } michael@0: if (hidden) { michael@0: if (invalidRegion) { michael@0: qtree.remove(invalidRegion); michael@0: node._region = null; michael@0: } michael@0: } else if (invalidRegion) { michael@0: invalidRegion.xMin = currentRegion.xMin; michael@0: invalidRegion.xMax = currentRegion.xMax; michael@0: invalidRegion.yMin = currentRegion.yMin; michael@0: invalidRegion.yMax = currentRegion.yMax; michael@0: qtree.update(invalidRegion); michael@0: } else { michael@0: currentRegion.obj = node; michael@0: qtree.insert(currentRegion); michael@0: node._region = currentRegion; michael@0: } michael@0: node._zindex = zindex++; michael@0: } michael@0: var invalidPath = new ShapePath(); michael@0: if (refreshStage) { michael@0: invalidPath.rect(0, 0, this._stageWidth, this._stageHeight); michael@0: invalidRegions.reset(); michael@0: return invalidPath; michael@0: } michael@0: var redrawRegions = invalidRegions.retrieve(); michael@0: for (var i = 0; i < redrawRegions.length; i++) { michael@0: var region = redrawRegions[i]; michael@0: var xMin = region.xMin - region.xMin % 20 - 40; michael@0: var yMin = region.yMin - region.yMin % 20 - 40; michael@0: var xMax = region.xMax - region.xMax % 20 + 80; michael@0: var yMax = region.yMax - region.yMax % 20 + 80; michael@0: var intersectees = qtree.retrieve(xMin, xMax, yMin, yMax); michael@0: for (var j = 0; j < intersectees.length; j++) { michael@0: var item = intersectees[j]; michael@0: item.obj._invalid = true; michael@0: } michael@0: invalidPath.rect(xMin, yMin, xMax - xMin, yMax - yMin); michael@0: } michael@0: invalidRegions.reset(); michael@0: return invalidPath; michael@0: }, michael@0: _handleMouseButtons: function () { michael@0: if (this._mouseEvents.length === 0) { michael@0: return; michael@0: } michael@0: var eventType = this._mouseEvents.shift(); michael@0: switch (eventType) { michael@0: case 'mousedown': michael@0: if (this._mouseTarget._buttonMode) { michael@0: this._mouseTarget._gotoButtonState('down'); michael@0: } michael@0: this._mouseTarget._dispatchEvent('mouseDown'); michael@0: break; michael@0: case 'mouseup': michael@0: if (this._mouseTarget._buttonMode) { michael@0: this._mouseTarget._gotoButtonState('over'); michael@0: } michael@0: this._mouseTarget._dispatchEvent('mouseUp'); michael@0: break; michael@0: } michael@0: }, michael@0: _handleMouse: function handleMouse() { michael@0: var mouseX = this._mouseX; michael@0: var mouseY = this._mouseY; michael@0: var candidates = this._qtree.retrieve(mouseX, mouseX, mouseY, mouseY); michael@0: var objectsUnderMouse = []; michael@0: for (var i = 0; i < candidates.length; i++) { michael@0: var item = candidates[i]; michael@0: var displayObject = item.obj; michael@0: var isUnderMouse = false; michael@0: if (flash.display.SimpleButton.class.isInstanceOf(displayObject)) { michael@0: if (!displayObject._enabled) { michael@0: continue; michael@0: } michael@0: var hitArea = displayObject._hitTestState; michael@0: hitArea._parent = displayObject; michael@0: isUnderMouse = hitArea._hitTest(true, mouseX, mouseY, true); michael@0: hitArea._parent = null; michael@0: } else { michael@0: isUnderMouse = displayObject._hitTest(true, mouseX, mouseY, true); michael@0: } michael@0: if (isUnderMouse) { michael@0: var currentNode = displayObject; michael@0: var lastEnabled = null; michael@0: if (!flash.display.InteractiveObject.class.isInstanceOf(currentNode)) { michael@0: lastEnabled = currentNode; michael@0: currentNode = currentNode._parent; michael@0: } michael@0: do { michael@0: if (!currentNode._mouseEnabled) { michael@0: lastEnabled = null; michael@0: } else if (lastEnabled === null) { michael@0: lastEnabled = currentNode; michael@0: } michael@0: currentNode = currentNode._parent; michael@0: } while (currentNode); michael@0: objectsUnderMouse.push(lastEnabled); michael@0: } michael@0: } michael@0: var target; michael@0: if (objectsUnderMouse.length) { michael@0: objectsUnderMouse.sort(sortByZindex); michael@0: var i = objectsUnderMouse.length; michael@0: while (i--) { michael@0: target = null; michael@0: var currentNode = objectsUnderMouse[i]; michael@0: if (!flash.display.InteractiveObject.class.isInstanceOf(currentNode)) { michael@0: var j = i; michael@0: while (j--) { michael@0: if (objectsUnderMouse[j]._parent === currentNode._parent && flash.display.InteractiveObject.class.isInstanceOf(objectsUnderMouse[j])) { michael@0: currentNode = objectsUnderMouse[j]; michael@0: i = j; michael@0: } michael@0: } michael@0: } michael@0: do { michael@0: if (flash.display.InteractiveObject.class.isInstanceOf(currentNode)) { michael@0: if ((!target || !currentNode._mouseChildren) && !currentNode._hitArea) { michael@0: target = currentNode; michael@0: } michael@0: } michael@0: currentNode = currentNode._parent; michael@0: } while (currentNode); michael@0: if (target !== objectsUnderMouse[i] && flash.display.SimpleButton.class.isInstanceOf(target)) { michael@0: continue; michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: if (!target) { michael@0: target = this; michael@0: } else if (target._hitTarget) { michael@0: target = target._hitTarget; michael@0: } michael@0: if (target === this._mouseTarget) { michael@0: target._dispatchEvent('mouseMove'); michael@0: } else { michael@0: if (this._mouseTarget._buttonMode) { michael@0: this._mouseTarget._gotoButtonState('up'); michael@0: } michael@0: this._mouseTarget._dispatchEvent('mouseOut'); michael@0: var nodeLeft = this._mouseTarget; michael@0: var containerLeft = nodeLeft._parent; michael@0: var nodeEntered = target; michael@0: var containerEntered = nodeEntered._parent; michael@0: var cursor = 'auto'; michael@0: while (nodeLeft._level >= 0 && nodeLeft !== containerEntered) { michael@0: if (nodeLeft._hasEventListener('rollOut')) { michael@0: nodeLeft._dispatchEvent('rollOut'); michael@0: } michael@0: nodeLeft = nodeLeft._parent; michael@0: } michael@0: while (nodeEntered._level >= 0 && nodeEntered !== containerLeft) { michael@0: if (nodeEntered._hasEventListener('rollOver')) { michael@0: nodeEntered._dispatchEvent('rollOver'); michael@0: } michael@0: if (nodeEntered._buttonMode && nodeEntered._useHandCursor) { michael@0: cursor = 'pointer'; michael@0: } michael@0: nodeEntered = nodeEntered._parent; michael@0: } michael@0: if (target._buttonMode) { michael@0: target._gotoButtonState('over'); michael@0: } michael@0: target._dispatchEvent('mouseOver'); michael@0: this._mouseTarget = target; michael@0: this._cursor = cursor; michael@0: } michael@0: }, michael@0: _as2SetLevel: function (level, loader) { michael@0: somewhatImplemented('Stage._as2SetLevel'); michael@0: this.addChild(loader); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: invalidate: function invalidate() { michael@0: this._invalid = true; michael@0: this._deferRenderEvent = true; michael@0: }, michael@0: isFocusInaccessible: function isFocusInaccessible() { michael@0: notImplemented('Stage.isFocusInaccessible'); michael@0: }, michael@0: set_displayState: function set_displayState(value) { michael@0: somewhatImplemented('Stage.set_displayState'); michael@0: this._displayState = value; michael@0: }, michael@0: get_simulatedFullScreenWidth: function get_simulatedFullScreenWidth() { michael@0: notImplemented('Stage.get_simulatedFullScreenWidth'); michael@0: }, michael@0: get_simulatedFullScreenHeight: function get_simulatedFullScreenHeight() { michael@0: notImplemented('Stage.get_simulatedFullScreenHeight'); michael@0: }, michael@0: removeChildAt: function removeChildAt(index) { michael@0: notImplemented('Stage.removeChildAt'); michael@0: }, michael@0: swapChildrenAt: function swapChildrenAt(index1, index2) { michael@0: notImplemented('Stage.swapChildrenAt'); michael@0: }, michael@0: requireOwnerPermissions: function requireOwnerPermissions() { michael@0: somewhatImplemented('Stage.requireOwnerPermissions'); michael@0: }, michael@0: frameRate: { michael@0: get: function frameRate() { michael@0: return this._frameRate; michael@0: }, michael@0: set: function frameRate(value) { michael@0: this._frameRate = value; michael@0: } michael@0: }, michael@0: scaleMode: { michael@0: get: function scaleMode() { michael@0: return this._scaleMode; michael@0: }, michael@0: set: function scaleMode(value) { michael@0: this._scaleMode = value; michael@0: this._invalid = true; michael@0: } michael@0: }, michael@0: align: { michael@0: get: function align() { michael@0: return this._align; michael@0: }, michael@0: set: function align(value) { michael@0: this._align = value; michael@0: this._invalid = true; michael@0: } michael@0: }, michael@0: stageWidth: { michael@0: get: function stageWidth() { michael@0: return this._stageWidth / 20; michael@0: }, michael@0: set: function stageWidth(value) { michael@0: notImplemented('Stage.stageWidth'); michael@0: this._stageWidth = value * 20 | 0; michael@0: } michael@0: }, michael@0: stageHeight: { michael@0: get: function stageHeight() { michael@0: return this._stageHeight / 20; michael@0: }, michael@0: set: function stageHeight(value) { michael@0: notImplemented('Stage.stageHeight'); michael@0: this._stageHeight = value * 20 | 0; michael@0: } michael@0: }, michael@0: showDefaultContextMenu: { michael@0: get: function showDefaultContextMenu() { michael@0: return this._showDefaultContextMenu; michael@0: }, michael@0: set: function showDefaultContextMenu(value) { michael@0: somewhatImplemented('Stage.showDefaultContextMenu'); michael@0: this._showDefaultContextMenu = value; michael@0: } michael@0: }, michael@0: focus: { michael@0: get: function focus() { michael@0: return this._focus; michael@0: }, michael@0: set: function focus(newFocus) { michael@0: somewhatImplemented('Stage.focus'); michael@0: this._focus = newFocus; michael@0: } michael@0: }, michael@0: colorCorrection: { michael@0: get: function colorCorrection() { michael@0: return this._colorCorrection; michael@0: }, michael@0: set: function colorCorrection(value) { michael@0: notImplemented('Stage.colorCorrection'); michael@0: this._colorCorrection = value; michael@0: } michael@0: }, michael@0: colorCorrectionSupport: { michael@0: get: function colorCorrectionSupport() { michael@0: return false; michael@0: } michael@0: }, michael@0: stageFocusRect: { michael@0: get: function stageFocusRect() { michael@0: return this._stageFocusRect; michael@0: }, michael@0: set: function stageFocusRect(on) { michael@0: somewhatImplemented('Stage.stageFocusRect'); michael@0: this._stageFocusRect = on; michael@0: } michael@0: }, michael@0: quality: { michael@0: get: function quality() { michael@0: return this._quality; michael@0: }, michael@0: set: function quality(value) { michael@0: somewhatImplemented('Stage.stageFocusRect'); michael@0: this._quality = value; michael@0: } michael@0: }, michael@0: displayState: { michael@0: get: function displayState() { michael@0: return this._displayState; michael@0: }, michael@0: set: function displayState(value) { michael@0: this._displayState = value; michael@0: } michael@0: }, michael@0: simulatedDisplayState: { michael@0: get: function simulatedDisplayState() { michael@0: notImplemented('Stage.simulatedDisplayState'); michael@0: return this._simulatedDisplayState; michael@0: }, michael@0: set: function simulatedDisplayState(value) { michael@0: notImplemented('Stage.simulatedDisplayState'); michael@0: this._simulatedDisplayState = value; michael@0: } michael@0: }, michael@0: fullScreenSourceRect: { michael@0: get: function fullScreenSourceRect() { michael@0: return this._fullScreenSourceRect; michael@0: }, michael@0: set: function fullScreenSourceRect(value) { michael@0: notImplemented('Stage.fullScreenSourceRect'); michael@0: this._fullScreenSourceRect = value; michael@0: } michael@0: }, michael@0: simulatedFullScreenSourceRect: { michael@0: get: function simulatedFullScreenSourceRect() { michael@0: notImplemented('Stage.simulatedFullScreenSourceRect'); michael@0: return this._simulatedFullScreenSourceRect; michael@0: }, michael@0: set: function simulatedFullScreenSourceRect(value) { michael@0: notImplemented('Stage.simulatedFullScreenSourceRect'); michael@0: this._simulatedFullScreenSourceRect = value; michael@0: } michael@0: }, michael@0: stageVideos: { michael@0: get: function stageVideos() { michael@0: somewhatImplemented('Stage.stageVideos'); michael@0: return this._stageVideos; michael@0: } michael@0: }, michael@0: stage3Ds: { michael@0: get: function stage3Ds() { michael@0: notImplemented('Stage.stage3Ds'); michael@0: return this._stage3Ds; michael@0: } michael@0: }, michael@0: color: { michael@0: get: function color() { michael@0: return this._color; michael@0: }, michael@0: set: function color(color) { michael@0: this._color = color; michael@0: this._invalid = true; michael@0: } michael@0: }, michael@0: fullScreenWidth: { michael@0: get: function fullScreenWidth() { michael@0: notImplemented('Stage.fullScreenWidth'); michael@0: return this._fullScreenWidth; michael@0: } michael@0: }, michael@0: fullScreenHeight: { michael@0: get: function fullScreenHeight() { michael@0: notImplemented('Stage.fullScreenHeight'); michael@0: return this._fullScreenHeight; michael@0: } michael@0: }, michael@0: wmodeGPU: { michael@0: get: function wmodeGPU() { michael@0: somewhatImplemented('Stage.wmodeGPU'); michael@0: return this._wmodeGPU; michael@0: } michael@0: }, michael@0: softKeyboardRect: { michael@0: get: function softKeyboardRect() { michael@0: notImplemented('Stage.softKeyboardRect'); michael@0: return this._softKeyboardRect; michael@0: } michael@0: }, michael@0: allowsFullScreen: { michael@0: get: function allowsFullScreen() { michael@0: return false; michael@0: } michael@0: }, michael@0: displayContextInfo: { michael@0: get: function displayContextInfo() { michael@0: notImplemented('Stage.displayContextInfo'); michael@0: return this._displayContextInfo; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var EventDefinition = function () { michael@0: return { michael@0: __class__: 'flash.events.Event', michael@0: initialize: function () { michael@0: this._stopPropagation = false; michael@0: this._stopImmediatePropagation = false; michael@0: this._isDefaultPrevented = false; michael@0: this._target = null; michael@0: this._currentTarget = null; michael@0: this._eventPhase = 2; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: ctor: function ctor(type, bubbles, cancelable) { michael@0: Counter.count('Event: ' + type); michael@0: this._type = type; michael@0: this._bubbles = bubbles; michael@0: this._cancelable = cancelable; michael@0: }, michael@0: stopPropagation: function stopPropagation() { michael@0: this._stopPropagation = true; michael@0: }, michael@0: stopImmediatePropagation: function stopImmediatePropagation() { michael@0: this._stopImmediatePropagation = this._stopPropagation = true; michael@0: }, michael@0: preventDefault: function preventDefault() { michael@0: if (this._cancelable) michael@0: this._isDefaultPrevented = true; michael@0: }, michael@0: isDefaultPrevented: function isDefaultPrevented() { michael@0: return this._isDefaultPrevented; michael@0: }, michael@0: type: { michael@0: get: function type() { michael@0: return this._type; michael@0: } michael@0: }, michael@0: bubbles: { michael@0: get: function bubbles() { michael@0: return this._bubbles; michael@0: } michael@0: }, michael@0: cancelable: { michael@0: get: function cancelable() { michael@0: return this._cancelable; michael@0: } michael@0: }, michael@0: target: { michael@0: get: function target() { michael@0: return this._target; michael@0: } michael@0: }, michael@0: currentTarget: { michael@0: get: function currentTarget() { michael@0: return this._currentTarget; michael@0: } michael@0: }, michael@0: eventPhase: { michael@0: get: function eventPhase() { michael@0: return this._eventPhase; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: Glue.ALL, michael@0: instance: { michael@0: clone: 'open public clone' michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var EventDispatcherDefinition = function () { michael@0: var mouseEvents = { michael@0: click: true, michael@0: contextMenu: true, michael@0: doubleClick: true, michael@0: middleClick: true, michael@0: middleMouseDown: true, michael@0: middleMouseUp: true, michael@0: mouseDown: true, michael@0: mouseMove: true, michael@0: mouseOut: true, michael@0: mouseOver: true, michael@0: mouseUp: true, michael@0: mouseWheel: true, michael@0: releaseOutside: true, michael@0: rightClick: true, michael@0: rightMouseDown: true, michael@0: rightMouseUp: true, michael@0: rollOut: false, michael@0: rollOver: false michael@0: }; michael@0: function doDispatchEvent(dispatcher, event, eventClass, bubbles) { michael@0: var target = dispatcher._target; michael@0: var type = event._type || event; michael@0: var listeners = dispatcher._listeners[type]; michael@0: if (bubbles || typeof event === 'string' && mouseEvents[event] || event._bubbles) { michael@0: var ancestors = []; michael@0: var currentNode = target._parent; michael@0: while (currentNode) { michael@0: if (currentNode._hasEventListener(type)) { michael@0: ancestors.push(currentNode); michael@0: } michael@0: currentNode = currentNode._parent; michael@0: } michael@0: if (!listeners && !ancestors.length) { michael@0: return true; michael@0: } michael@0: var keepPropagating = true; michael@0: var i = ancestors.length; michael@0: while (i-- && keepPropagating) { michael@0: var currentTarget = ancestors[i]; michael@0: var queue = currentTarget._captureListeners[type]; michael@0: keepPropagating = processListeners(queue, event, eventClass, bubbles, target, currentTarget, 1); michael@0: } michael@0: if (listeners && keepPropagating) { michael@0: keepPropagating = processListeners(listeners, event, eventClass, bubbles, target); michael@0: } michael@0: for (var i = 0; i < ancestors.length && keepPropagating; i++) { michael@0: var currentTarget = ancestors[i]; michael@0: var queue = currentTarget._listeners[type]; michael@0: keepPropagating = processListeners(queue, event, eventClass, bubbles, target, currentTarget, 3); michael@0: } michael@0: } else if (listeners) { michael@0: processListeners(listeners, event, eventClass, bubbles, target); michael@0: } michael@0: return !event._isDefaultPrevented; michael@0: } michael@0: function processListeners(queue, event, eventClass, bubbles, target, currentTarget, eventPhase) { michael@0: if (queue) { michael@0: queue = queue.slice(); michael@0: var needsInit = true; michael@0: try { michael@0: for (var i = 0; i < queue.length; i++) { michael@0: var item = queue[i]; michael@0: var methodInfo = item.handleEvent.methodInfo; michael@0: if (methodInfo) { michael@0: if (methodInfo.parameters.length) { michael@0: if (!methodInfo.parameters[0].isUsed) { michael@0: item.handleEvent(); michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: if (needsInit) { michael@0: if (typeof event === 'string') { michael@0: if (eventClass) { michael@0: event = new eventClass(event); michael@0: } else { michael@0: if (mouseEvents[event]) { michael@0: event = new flash.events.MouseEvent(event, mouseEvents[event]); michael@0: if (target._stage) { michael@0: event._localX = target.mouseX; michael@0: event._localY = target.mouseY; michael@0: } michael@0: } else { michael@0: event = new flash.events.Event(event); michael@0: } michael@0: } michael@0: } else if (event._target) { michael@0: event = event.clone(); michael@0: } michael@0: event._target = target; michael@0: event._currentTarget = currentTarget || target; michael@0: event._eventPhase = eventPhase || 2; michael@0: needsInit = false; michael@0: } michael@0: item.handleEvent(event); michael@0: if (event._stopImmediatePropagation) { michael@0: break; michael@0: } michael@0: } michael@0: } catch (e) { michael@0: avm2.exceptions.push({ michael@0: source: 'avm2', michael@0: message: e.message, michael@0: stack: e.stack michael@0: }); michael@0: throw e; michael@0: } michael@0: } michael@0: return !event._stopPropagation; michael@0: } michael@0: return { michael@0: __class__: 'flash.events.EventDispatcher', michael@0: initialize: function () { michael@0: this._target = this; michael@0: this._listeners = {}; michael@0: this._captureListeners = {}; michael@0: }, michael@0: _addEventListenerImpl: function addEventListenerImpl(type, listener, useCapture, priority) { michael@0: if (typeof listener !== 'function') { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function'); michael@0: } michael@0: var listeners = useCapture ? this._captureListeners : this._listeners; michael@0: var queue = listeners[type]; michael@0: var listenerObj = { michael@0: handleEvent: listener, michael@0: priority: priority || 0 michael@0: }; michael@0: if (queue) { michael@0: var level = queue.length; michael@0: var i = level; michael@0: while (i--) { michael@0: var item = queue[i]; michael@0: if (item.handleEvent === listener) { michael@0: return; michael@0: } michael@0: if (priority > item.priority) { michael@0: level = i; michael@0: } michael@0: } michael@0: queue.splice(level, 0, listenerObj); michael@0: } else { michael@0: listeners[type] = [ michael@0: listenerObj michael@0: ]; michael@0: } michael@0: }, michael@0: _addEventListener: function addEventListener(type, listener, useCapture, priority) { michael@0: this._addEventListenerImpl(type, listener, useCapture, priority); michael@0: }, michael@0: _removeEventListenerImpl: function removeEventListenerImpl(type, listener, useCapture) { michael@0: if (typeof listener !== 'function') { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function'); michael@0: } michael@0: var listeners = useCapture ? this._captureListeners : this._listeners; michael@0: var queue = listeners[type]; michael@0: if (queue) { michael@0: for (var i = 0; i < queue.length; i++) { michael@0: var item = queue[i]; michael@0: if (item.handleEvent === listener) { michael@0: queue.splice(i, 1); michael@0: if (!queue.length) { michael@0: listeners[type] = null; michael@0: } michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: _removeEventListener: function removeEventListener(type, listener, useCapture) { michael@0: this._removeEventListenerImpl(type, listener, useCapture); michael@0: }, michael@0: _hasEventListener: function hasEventListener(type) { michael@0: return this._listeners[type] || this._captureListeners[type]; michael@0: }, michael@0: _dispatchEvent: function dispatchEvent(event, eventClass, bubbles) { michael@0: doDispatchEvent(this, event, eventClass, bubbles); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: ctor: function ctor(target) { michael@0: this._target = target || this; michael@0: }, michael@0: addEventListener: function addEventListener(type, listener, useCapture, priority, useWeakReference) { michael@0: this._addEventListener(type, listener, useCapture, priority); michael@0: }, michael@0: removeEventListener: function removeEventListener(type, listener, useCapture) { michael@0: this._removeEventListener(type, listener, useCapture); michael@0: }, michael@0: hasEventListener: function hasEventListener(type) { michael@0: return this._hasEventListener(type); michael@0: }, michael@0: willTrigger: function willTrigger(type) { michael@0: var currentNode = this._target; michael@0: do { michael@0: if (currentNode._hasEventListener(type)) { michael@0: return true; michael@0: } michael@0: } while (currentNode = currentNode._parent); michael@0: return false; michael@0: }, michael@0: dispatchEventFunction: function dispatchEventFunction(event) { michael@0: return doDispatchEvent(this, event); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var KeyboardEventDefinition = function () { michael@0: return { michael@0: __class__: 'flash.events.KeyboardEvent', michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: updateAfterEvent: function updateAfterEvent() { michael@0: notImplemented('KeyboardEvent.updateAfterEvent'); michael@0: }, michael@0: charCode: { michael@0: get: function charCode() { michael@0: return this._charCode; michael@0: }, michael@0: set: function charCode(value) { michael@0: this._charCode = value; michael@0: } michael@0: }, michael@0: ctrlKey: { michael@0: get: function ctrlKey() { michael@0: return this._ctrlKey; michael@0: }, michael@0: set: function ctrlKey(value) { michael@0: this._ctrlKey = value; michael@0: } michael@0: }, michael@0: altKey: { michael@0: get: function altKey() { michael@0: return this._altKey; michael@0: }, michael@0: set: function altKey(value) { michael@0: this._altKey = value; michael@0: } michael@0: }, michael@0: shiftKey: { michael@0: get: function shiftKey() { michael@0: return this._shiftKey; michael@0: }, michael@0: set: function shiftKey(value) { michael@0: this._shiftKey = value; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: Glue.ALL, michael@0: instance: { michael@0: keyCode: 'public keyCode' michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var MouseEventDefinition = function () { michael@0: return { michael@0: __class__: 'flash.events.MouseEvent', michael@0: initialize: function () { michael@0: this._localX = NaN; michael@0: this._localY = NaN; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: updateAfterEvent: function updateAfterEvent() { michael@0: }, michael@0: getStageX: function getStageX() { michael@0: if (this._target) { michael@0: var m = this._target._getConcatenatedTransform(null, false); michael@0: var x = m.a * this._localX + m.c * this._localY + m.tx; michael@0: return x / 20; michael@0: } michael@0: return this._localX / 20; michael@0: }, michael@0: getStageY: function getStageY() { michael@0: if (this._target) { michael@0: var m = this._target._getConcatenatedTransform(null, false); michael@0: var y = m.d * this._localY + m.b * this._localX + m.ty; michael@0: return y / 20; michael@0: } michael@0: return this._localY / 20; michael@0: }, michael@0: localX: { michael@0: get: function localX() { michael@0: return this._localX / 20; michael@0: }, michael@0: set: function localX(value) { michael@0: this._localX = value * 20 | 0; michael@0: } michael@0: }, michael@0: localY: { michael@0: get: function localY() { michael@0: return this._localY / 20; michael@0: }, michael@0: set: function localY(value) { michael@0: this._localY = value * 20 | 0; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextEventDefinition = function () { michael@0: return { michael@0: __class__: 'flash.events.TextEvent', michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: copyNativeData: function copyNativeData(other) { michael@0: notImplemented('TextEvent.copyNativeData'); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TimerEventDefinition = function () { michael@0: return { michael@0: __class__: 'flash.events.TimerEvent', michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: updateAfterEvent: function updateAfterEvent() { michael@0: notImplemented('TimerEvent.updateAfterEvent'); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var ExternalInterfaceDefinition = function () { michael@0: function getAvailable() { michael@0: return true; michael@0: } michael@0: var initialized = false; michael@0: var registeredCallbacks = {}; michael@0: function callIn(functionName, args) { michael@0: if (!registeredCallbacks.hasOwnProperty(functionName)) michael@0: return; michael@0: return registeredCallbacks[functionName](functionName, args); michael@0: } michael@0: return { michael@0: __class__: 'flash.external.ExternalInterface', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: _initJS: function _initJS() { michael@0: if (initialized) michael@0: return; michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: EXTERNAL_INTERFACE_FEATURE michael@0: }); michael@0: initialized = true; michael@0: FirefoxCom.initJS(callIn); michael@0: }, michael@0: _getPropNames: function _getPropNames(obj) { michael@0: var keys = []; michael@0: forEachPublicProperty(obj, function (key) { michael@0: keys.push(key); michael@0: }); michael@0: return keys; michael@0: }, michael@0: _addCallback: function _addCallback(functionName, closure, hasNullCallback) { michael@0: FirefoxCom.request('externalCom', { michael@0: action: 'register', michael@0: functionName: functionName, michael@0: remove: hasNullCallback michael@0: }); michael@0: if (hasNullCallback) { michael@0: delete registeredCallbacks[functionName]; michael@0: } else { michael@0: registeredCallbacks[functionName] = closure; michael@0: } michael@0: }, michael@0: _evalJS: function _evalJS(expression) { michael@0: return FirefoxCom.requestSync('externalCom', { michael@0: action: 'eval', michael@0: expression: expression michael@0: }); michael@0: }, michael@0: _callOut: function _callOut(request) { michael@0: return FirefoxCom.requestSync('externalCom', { michael@0: action: 'call', michael@0: request: request michael@0: }); michael@0: }, michael@0: available: { michael@0: get: getAvailable michael@0: }, michael@0: objectID: { michael@0: get: function objectID() { michael@0: return FirefoxCom.requestSync('externalCom', { michael@0: action: 'getId' michael@0: }); michael@0: } michael@0: }, michael@0: activeX: { michael@0: get: function activeX() { michael@0: return false; michael@0: } michael@0: } michael@0: }, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: { michael@0: var BevelFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.BevelFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: } michael@0: var BitmapFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.BitmapFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: var BlurFilterDefinition = function () { michael@0: return { michael@0: __class__: 'flash.filters.BlurFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: var bx = this._blurX * this._quality * 20; michael@0: var by = this._blurY * this._quality * 20; michael@0: bounds.xMin -= bx; michael@0: bounds.xMax += bx; michael@0: bounds.yMin -= by; michael@0: bounds.yMax += by; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: blurX: { michael@0: get: function blurX() { michael@0: return this._blurX; michael@0: }, michael@0: set: function blurX(value) { michael@0: this._blurX = value; michael@0: } michael@0: }, michael@0: blurY: { michael@0: get: function blurY() { michael@0: return this._blurY; michael@0: }, michael@0: set: function blurY(value) { michael@0: this._blurY = value; michael@0: } michael@0: }, michael@0: quality: { michael@0: get: function quality() { michael@0: return this._quality; michael@0: }, michael@0: set: function quality(value) { michael@0: this._quality = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ColorMatrixFilterDefinition = function () { michael@0: return { michael@0: __class__: 'flash.filters.ColorMatrixFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: matrix: { michael@0: get: function matrix() { michael@0: return this._matrix; michael@0: }, michael@0: set: function matrix(value) { michael@0: this._matrix = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ConvolutionFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.ConvolutionFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: var DisplacementMapFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.DisplacementMapFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: var DropShadowFilterDefinition = function () { michael@0: return { michael@0: __class__: 'flash.filters.DropShadowFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: var a = this._angle * Math.PI / 180; michael@0: var dy = Math.sin(a) * this._distance; michael@0: var dx = Math.cos(a) * this._distance; michael@0: var bx = this._blurX * this._quality * 20; michael@0: var by = this._blurY * this._quality * 20; michael@0: bounds.xMin -= bx - (dx > 0 ? 0 : dx); michael@0: bounds.xMax += bx + Math.abs(dx); michael@0: bounds.yMin -= by - (dy > 0 ? 0 : dy); michael@0: bounds.yMax += by + Math.abs(dy); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: instance: { michael@0: distance: { michael@0: get: function distance() { michael@0: return this._distance; michael@0: }, michael@0: set: function distance(value) { michael@0: this._distance = value; michael@0: } michael@0: }, michael@0: angle: { michael@0: get: function angle() { michael@0: return this._angle; michael@0: }, michael@0: set: function angle(value) { michael@0: this._angle = value; michael@0: } michael@0: }, michael@0: color: { michael@0: get: function color() { michael@0: return this._color; michael@0: }, michael@0: set: function color(value) { michael@0: this._color = value; michael@0: } michael@0: }, michael@0: alpha: { michael@0: get: function alpha() { michael@0: return this._alpha; michael@0: }, michael@0: set: function alpha(value) { michael@0: this._alpha = value; michael@0: } michael@0: }, michael@0: blurX: { michael@0: get: function blurX() { michael@0: return this._blurX; michael@0: }, michael@0: set: function blurX(value) { michael@0: this._blurX = value; michael@0: } michael@0: }, michael@0: blurY: { michael@0: get: function blurY() { michael@0: return this._blurY; michael@0: }, michael@0: set: function blurY(value) { michael@0: this._blurY = value; michael@0: } michael@0: }, michael@0: hideObject: { michael@0: get: function hideObject() { michael@0: return this._hideObject; michael@0: }, michael@0: set: function hideObject(value) { michael@0: this._hideObject = value; michael@0: } michael@0: }, michael@0: inner: { michael@0: get: function inner() { michael@0: return this._inner; michael@0: }, michael@0: set: function inner(value) { michael@0: this._inner = value; michael@0: } michael@0: }, michael@0: knockout: { michael@0: get: function knockout() { michael@0: return this._knockout; michael@0: }, michael@0: set: function knockout(value) { michael@0: this._knockout = value; michael@0: } michael@0: }, michael@0: quality: { michael@0: get: function quality() { michael@0: return this._quality; michael@0: }, michael@0: set: function quality(value) { michael@0: this._quality = value; michael@0: } michael@0: }, michael@0: strength: { michael@0: get: function strength() { michael@0: return this._strength; michael@0: }, michael@0: set: function strength(value) { michael@0: this._strength = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var GlowFilterDefinition = function () { michael@0: return { michael@0: __class__: 'flash.filters.GlowFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: var bx = this._blurX * this._quality * 20; michael@0: var by = this._blurY * this._quality * 20; michael@0: bounds.xMin -= bx; michael@0: bounds.xMax += bx; michael@0: bounds.yMin -= by; michael@0: bounds.yMax += by; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: color: { michael@0: get: function color() { michael@0: return this._color; michael@0: }, michael@0: set: function color(value) { michael@0: this._color = value; michael@0: } michael@0: }, michael@0: alpha: { michael@0: get: function alpha() { michael@0: return this._alpha; michael@0: }, michael@0: set: function alpha(value) { michael@0: this._alpha = value; michael@0: } michael@0: }, michael@0: blurX: { michael@0: get: function blurX() { michael@0: return this._blurX; michael@0: }, michael@0: set: function blurX(value) { michael@0: this._blurX = value; michael@0: } michael@0: }, michael@0: blurY: { michael@0: get: function blurY() { michael@0: return this._blurY; michael@0: }, michael@0: set: function blurY(value) { michael@0: this._blurY = value; michael@0: } michael@0: }, michael@0: inner: { michael@0: get: function inner() { michael@0: return this._inner; michael@0: }, michael@0: set: function inner(value) { michael@0: this._inner = value; michael@0: } michael@0: }, michael@0: knockout: { michael@0: get: function knockout() { michael@0: return this._knockout; michael@0: }, michael@0: set: function knockout(value) { michael@0: this._knockout = value; michael@0: } michael@0: }, michael@0: quality: { michael@0: get: function quality() { michael@0: return this._quality; michael@0: }, michael@0: set: function quality(value) { michael@0: this._quality = value; michael@0: } michael@0: }, michael@0: strength: { michael@0: get: function strength() { michael@0: return this._strength; michael@0: }, michael@0: set: function strength(value) { michael@0: this._strength = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var GradientBevelFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.GradientBevelFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: var GradientGlowFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.GradientGlowFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: var ShaderFilterDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.filters.ShaderFilter', michael@0: initialize: function () { michael@0: }, michael@0: _updateFilterBounds: function (bounds) { michael@0: } michael@0: }; michael@0: def.__glue__ = {}; michael@0: return def; michael@0: }.call(this); michael@0: { michael@0: var ColorTransformDefinition = function () { michael@0: return { michael@0: __class__: 'flash.geom.ColorTransform', michael@0: __glue__: { michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var MatrixDefinition = function () { michael@0: return { michael@0: __class__: 'flash.geom.Matrix', michael@0: __glue__: { michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var Matrix3DDefinition = function () { michael@0: var precision = 1e-7; michael@0: var transposeTransform = new Uint32Array([ michael@0: 0, michael@0: 4, michael@0: 8, michael@0: 12, michael@0: 1, michael@0: 5, michael@0: 9, michael@0: 13, michael@0: 2, michael@0: 6, michael@0: 10, michael@0: 14, michael@0: 3, michael@0: 7, michael@0: 11, michael@0: 15 michael@0: ]); michael@0: function getRotationMatrix(theta, u, v, w, a, b, c) { michael@0: var u2 = u * u, v2 = v * v, w2 = w * w; michael@0: var L2 = u2 + v2 + w2, L = Math.sqrt(L2); michael@0: u /= L; michael@0: v /= L; michael@0: w /= L; michael@0: u2 /= L2; michael@0: v2 /= L2; michael@0: w2 /= L2; michael@0: var cos = Math.cos(theta), sin = Math.sin(theta); michael@0: return new flash.geom.Matrix3D([ michael@0: u2 + (v2 + w2) * cos, michael@0: u * v * (1 - cos) + w * sin, michael@0: u * w * (1 - cos) - v * sin, michael@0: 0, michael@0: u * v * (1 - cos) - w * sin, michael@0: v2 + (u2 + w2) * cos, michael@0: v * w * (1 - cos) + u * sin, michael@0: 0, michael@0: u * w * (1 - cos) + v * sin, michael@0: v * w * (1 - cos) - u * sin, michael@0: w2 + (u2 + v2) * cos, michael@0: 0, michael@0: (a * (v2 + w2) - u * (b * v + c * w)) * (1 - cos) + (b * w - c * v) * sin, michael@0: (b * (u2 + w2) - v * (a * u + c * w)) * (1 - cos) + (c * u - a * w) * sin, michael@0: (c * (u2 + v2) - w * (a * u + b * v)) * (1 - cos) + (a * v - b * u) * sin, michael@0: 1 michael@0: ]); michael@0: } michael@0: return { michael@0: __class__: 'flash.geom.Matrix3D', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: interpolate: function interpolate(thisMat, toMat, percent) { michael@0: notImplemented('Matrix3D.interpolate'); michael@0: } michael@0: }, michael@0: instance: { michael@0: ctor: function ctor(v) { michael@0: this._matrix = new Float32Array(16); michael@0: if (v && v.length >= 16) { michael@0: this.copyRawDataFrom(v, 0, false); michael@0: } else { michael@0: this.identity(); michael@0: } michael@0: }, michael@0: clone: function clone() { michael@0: return new flash.geom.Matrix3D(this._matrix); michael@0: }, michael@0: copyToMatrix3D: function copyToMatrix3D(dest) { michael@0: dest._matrix.set(this._matrix); michael@0: }, michael@0: append: function append(lhs) { michael@0: var ma = lhs._matrix, mb = this._matrix, m = this._matrix; michael@0: var ma11 = ma[0], ma12 = ma[4], ma13 = ma[8], ma14 = ma[12], ma21 = ma[1], ma22 = ma[5], ma23 = ma[9], ma24 = ma[13], ma31 = ma[2], ma32 = ma[6], ma33 = ma[10], ma34 = ma[14], ma41 = ma[3], ma42 = ma[7], ma43 = ma[11], ma44 = ma[15]; michael@0: var mb11 = mb[0], mb12 = mb[4], mb13 = mb[8], mb14 = mb[12], mb21 = mb[1], mb22 = mb[5], mb23 = mb[9], mb24 = mb[13], mb31 = mb[2], mb32 = mb[6], mb33 = mb[10], mb34 = mb[14], mb41 = mb[3], mb42 = mb[7], mb43 = mb[11], mb44 = mb[15]; michael@0: m[0] = ma11 * mb11 + ma12 * mb21 + ma13 * mb31 + ma14 * mb41; michael@0: m[1] = ma21 * mb11 + ma22 * mb21 + ma23 * mb31 + ma24 * mb41; michael@0: m[2] = ma31 * mb11 + ma32 * mb21 + ma33 * mb31 + ma34 * mb41; michael@0: m[3] = ma41 * mb11 + ma42 * mb21 + ma43 * mb31 + ma44 * mb41; michael@0: m[4] = ma11 * mb12 + ma12 * mb22 + ma13 * mb32 + ma14 * mb42; michael@0: m[5] = ma21 * mb12 + ma22 * mb22 + ma23 * mb32 + ma24 * mb42; michael@0: m[6] = ma31 * mb12 + ma32 * mb22 + ma33 * mb32 + ma34 * mb42; michael@0: m[7] = ma41 * mb12 + ma42 * mb22 + ma43 * mb32 + ma44 * mb42; michael@0: m[8] = ma11 * mb13 + ma12 * mb23 + ma13 * mb33 + ma14 * mb43; michael@0: m[9] = ma21 * mb13 + ma22 * mb23 + ma23 * mb33 + ma24 * mb43; michael@0: m[10] = ma31 * mb13 + ma32 * mb23 + ma33 * mb33 + ma34 * mb43; michael@0: m[11] = ma41 * mb13 + ma42 * mb23 + ma43 * mb33 + ma44 * mb43; michael@0: m[12] = ma11 * mb14 + ma12 * mb24 + ma13 * mb34 + ma14 * mb44; michael@0: m[13] = ma21 * mb14 + ma22 * mb24 + ma23 * mb34 + ma24 * mb44; michael@0: m[14] = ma31 * mb14 + ma32 * mb24 + ma33 * mb34 + ma34 * mb44; michael@0: m[15] = ma41 * mb14 + ma42 * mb24 + ma43 * mb34 + ma44 * mb44; michael@0: }, michael@0: prepend: function prepend(rhs) { michael@0: var ma = this._matrix, mb = rhs._matrix, m = this._matrix; michael@0: var ma11 = ma[0], ma12 = ma[4], ma13 = ma[8], ma14 = ma[12], ma21 = ma[1], ma22 = ma[5], ma23 = ma[9], ma24 = ma[13], ma31 = ma[2], ma32 = ma[6], ma33 = ma[10], ma34 = ma[14], ma41 = ma[3], ma42 = ma[7], ma43 = ma[11], ma44 = ma[15]; michael@0: var mb11 = mb[0], mb12 = mb[4], mb13 = mb[8], mb14 = mb[12], mb21 = mb[1], mb22 = mb[5], mb23 = mb[9], mb24 = mb[13], mb31 = mb[2], mb32 = mb[6], mb33 = mb[10], mb34 = mb[14], mb41 = mb[3], mb42 = mb[7], mb43 = mb[11], mb44 = mb[15]; michael@0: m[0] = ma11 * mb11 + ma12 * mb21 + ma13 * mb31 + ma14 * mb41; michael@0: m[1] = ma21 * mb11 + ma22 * mb21 + ma23 * mb31 + ma24 * mb41; michael@0: m[2] = ma31 * mb11 + ma32 * mb21 + ma33 * mb31 + ma34 * mb41; michael@0: m[3] = ma41 * mb11 + ma42 * mb21 + ma43 * mb31 + ma44 * mb41; michael@0: m[4] = ma11 * mb12 + ma12 * mb22 + ma13 * mb32 + ma14 * mb42; michael@0: m[5] = ma21 * mb12 + ma22 * mb22 + ma23 * mb32 + ma24 * mb42; michael@0: m[6] = ma31 * mb12 + ma32 * mb22 + ma33 * mb32 + ma34 * mb42; michael@0: m[7] = ma41 * mb12 + ma42 * mb22 + ma43 * mb32 + ma44 * mb42; michael@0: m[8] = ma11 * mb13 + ma12 * mb23 + ma13 * mb33 + ma14 * mb43; michael@0: m[9] = ma21 * mb13 + ma22 * mb23 + ma23 * mb33 + ma24 * mb43; michael@0: m[10] = ma31 * mb13 + ma32 * mb23 + ma33 * mb33 + ma34 * mb43; michael@0: m[11] = ma41 * mb13 + ma42 * mb23 + ma43 * mb33 + ma44 * mb43; michael@0: m[12] = ma11 * mb14 + ma12 * mb24 + ma13 * mb34 + ma14 * mb44; michael@0: m[13] = ma21 * mb14 + ma22 * mb24 + ma23 * mb34 + ma24 * mb44; michael@0: m[14] = ma31 * mb14 + ma32 * mb24 + ma33 * mb34 + ma34 * mb44; michael@0: m[15] = ma41 * mb14 + ma42 * mb24 + ma43 * mb34 + ma44 * mb44; michael@0: }, michael@0: invert: function invert() { michael@0: var d = this.determinant; michael@0: if (Math.abs(d) < precision) { michael@0: return false; michael@0: } michael@0: d = 1 / d; michael@0: var m = this._matrix; michael@0: var m11 = m[0], m12 = m[1], m13 = m[2], m14 = m[3], m21 = m[4], m22 = m[5], m23 = m[6], m24 = m[7], m31 = m[8], m32 = m[9], m33 = m[10], m34 = m[11], m41 = m[12], m42 = m[13], m43 = m[14], m44 = m[15]; michael@0: m[0] = d * (m22 * (m33 * m44 - m43 * m34) - m32 * (m23 * m44 - m43 * m24) + m42 * (m23 * m34 - m33 * m24)); michael@0: m[1] = -d * (m12 * (m33 * m44 - m43 * m34) - m32 * (m13 * m44 - m43 * m14) + m42 * (m13 * m34 - m33 * m14)); michael@0: m[2] = d * (m12 * (m23 * m44 - m43 * m24) - m22 * (m13 * m44 - m43 * m14) + m42 * (m13 * m24 - m23 * m14)); michael@0: m[3] = -d * (m12 * (m23 * m34 - m33 * m24) - m22 * (m13 * m34 - m33 * m14) + m32 * (m13 * m24 - m23 * m14)); michael@0: m[4] = -d * (m21 * (m33 * m44 - m43 * m34) - m31 * (m23 * m44 - m43 * m24) + m41 * (m23 * m34 - m33 * m24)); michael@0: m[5] = d * (m11 * (m33 * m44 - m43 * m34) - m31 * (m13 * m44 - m43 * m14) + m41 * (m13 * m34 - m33 * m14)); michael@0: m[6] = -d * (m11 * (m23 * m44 - m43 * m24) - m21 * (m13 * m44 - m43 * m14) + m41 * (m13 * m24 - m23 * m14)); michael@0: m[7] = d * (m11 * (m23 * m34 - m33 * m24) - m21 * (m13 * m34 - m33 * m14) + m31 * (m13 * m24 - m23 * m14)); michael@0: m[8] = d * (m21 * (m32 * m44 - m42 * m34) - m31 * (m22 * m44 - m42 * m24) + m41 * (m22 * m34 - m32 * m24)); michael@0: m[9] = -d * (m11 * (m32 * m44 - m42 * m34) - m31 * (m12 * m44 - m42 * m14) + m41 * (m12 * m34 - m32 * m14)); michael@0: m[10] = d * (m11 * (m22 * m44 - m42 * m24) - m21 * (m12 * m44 - m42 * m14) + m41 * (m12 * m24 - m22 * m14)); michael@0: m[11] = -d * (m11 * (m22 * m34 - m32 * m24) - m21 * (m12 * m34 - m32 * m14) + m31 * (m12 * m24 - m22 * m14)); michael@0: m[12] = -d * (m21 * (m32 * m43 - m42 * m33) - m31 * (m22 * m43 - m42 * m23) + m41 * (m22 * m33 - m32 * m23)); michael@0: m[13] = d * (m11 * (m32 * m43 - m42 * m33) - m31 * (m12 * m43 - m42 * m13) + m41 * (m12 * m33 - m32 * m13)); michael@0: m[14] = -d * (m11 * (m22 * m43 - m42 * m23) - m21 * (m12 * m43 - m42 * m13) + m41 * (m12 * m23 - m22 * m13)); michael@0: m[15] = d * (m11 * (m22 * m33 - m32 * m23) - m21 * (m12 * m33 - m32 * m13) + m31 * (m12 * m23 - m22 * m13)); michael@0: return true; michael@0: }, michael@0: identity: function identity() { michael@0: var m = this._matrix; michael@0: m[0] = m[5] = m[10] = m[15] = 1; michael@0: m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] = 0; michael@0: }, michael@0: decompose: function decompose(orientationStyle) { michael@0: notImplemented('Matrix3D.decompose'); michael@0: }, michael@0: recompose: function recompose(components, orientationStyle) { michael@0: notImplemented('Matrix3D.recompose'); michael@0: }, michael@0: appendTranslation: function appendTranslation(x, y, z) { michael@0: var m = this._matrix; michael@0: var m41 = m[3], m42 = m[7], m43 = m[11], m44 = m[15]; michael@0: m[0] += x * m41; michael@0: m[1] += y * m41; michael@0: m[2] += z * m41; michael@0: m[4] += x * m42; michael@0: m[5] += y * m42; michael@0: m[6] += z * m42; michael@0: m[8] += x * m43; michael@0: m[9] += y * m43; michael@0: m[10] += z * m43; michael@0: m[12] += x * m44; michael@0: m[13] += y * m44; michael@0: m[14] += z * m44; michael@0: }, michael@0: appendRotation: function appendRotation(degrees, axis, pivotPoint) { michael@0: this.append(getRotationMatrix(degrees / 180 * Math.PI, axis.x, axis.y, axis.z, pivotPoint ? pivotPoint.x : 0, pivotPoint ? pivotPoint.y : 0, pivotPoint ? pivotPoint.z : 0)); michael@0: }, michael@0: appendScale: function appendScale(xScale, yScale, zScale) { michael@0: var m = this._matrix; michael@0: m[0] *= xScale; michael@0: m[1] *= yScale; michael@0: m[2] *= zScale; michael@0: m[4] *= xScale; michael@0: m[5] *= yScale; michael@0: m[6] *= zScale; michael@0: m[8] *= xScale; michael@0: m[9] *= yScale; michael@0: m[10] *= zScale; michael@0: m[12] *= xScale; michael@0: m[13] *= yScale; michael@0: m[14] *= zScale; michael@0: }, michael@0: prependTranslation: function prependTranslation(x, y, z) { michael@0: var m = this._matrix; michael@0: var m11 = m[0], m12 = m[4], m13 = m[8], m14 = m[12], m21 = m[1], m22 = m[5], m23 = m[9], m24 = m[13], m31 = m[2], m32 = m[6], m33 = m[10], m34 = m[14], m41 = m[3], m42 = m[7], m43 = m[11], m44 = m[15]; michael@0: m[12] += m11 * x + m12 * y + m13 * z; michael@0: m[13] += m21 * x + m22 * y + m23 * z; michael@0: m[14] += m31 * x + m32 * y + m33 * z; michael@0: m[15] += m41 * x + m42 * y + m43 * z; michael@0: }, michael@0: prependRotation: function prependRotation(degrees, axis, pivotPoint) { michael@0: this.prepend(getRotationMatrix(degrees / 180 * Math.PI, axis.x, axis.y, axis.z, pivotPoint ? pivotPoint.x : 0, pivotPoint ? pivotPoint.y : 0, pivotPoint ? pivotPoint.z : 0)); michael@0: }, michael@0: prependScale: function prependScale(xScale, yScale, zScale) { michael@0: var m = this._matrix; michael@0: m[0] *= xScale; michael@0: m[1] *= xScale; michael@0: m[2] *= xScale; michael@0: m[3] *= xScale; michael@0: m[4] *= yScale; michael@0: m[5] *= yScale; michael@0: m[6] *= yScale; michael@0: m[7] *= yScale; michael@0: m[8] *= zScale; michael@0: m[9] *= zScale; michael@0: m[10] *= zScale; michael@0: m[11] *= zScale; michael@0: }, michael@0: transformVector: function transformVector(v) { michael@0: var m = this._matrix; michael@0: var x = v.x, y = v.y, z = v.z; michael@0: return new flash.geom.Vector3D(m[0] * x + m[4] * y + m[8] * z + m[12], m[1] * x + m[5] * y + m[9] * z + m[13], m[2] * x + m[6] * y + m[10] * z + m[14]); michael@0: }, michael@0: deltaTransformVector: function deltaTransformVector(v) { michael@0: var m = this._matrix; michael@0: var x = v.x, y = v.y, z = v.z; michael@0: return new flash.geom.Vector3D(m[0] * x + m[4] * y + m[8] * z, m[1] * x + m[5] * y + m[9] * z, m[2] * x + m[6] * y + m[10] * z); michael@0: }, michael@0: transformVectors: function transformVectors(vin, vout) { michael@0: var m = this._matrix; michael@0: var m11 = m[0], m12 = m[4], m13 = m[8], m14 = m[12], m21 = m[1], m22 = m[5], m23 = m[9], m24 = m[13], m31 = m[2], m32 = m[6], m33 = m[10], m34 = m[14], m41 = m[3], m42 = m[7], m43 = m[11], m44 = m[15]; michael@0: for (var i = 0; i < vin.length - 2; i += 3) { michael@0: var x = vin.asGetNumericProperty(i), y = vin.asGetNumericProperty(i + 1), z = vin.asGetNumericProperty(i + 2); michael@0: vout.push(m11 * x + m12 * y + m13 * z + m14); michael@0: vout.push(m21 * x + m22 * y + m23 * z + m24); michael@0: vout.push(m31 * x + m32 * y + m33 * z + m34); michael@0: } michael@0: }, michael@0: transpose: function transpose() { michael@0: var m = this._matrix; michael@0: var tmp; michael@0: tmp = m[1]; michael@0: m[1] = m[4]; michael@0: m[4] = tmp; michael@0: tmp = m[2]; michael@0: m[2] = m[8]; michael@0: m[5] = tmp; michael@0: tmp = m[3]; michael@0: m[3] = m[12]; michael@0: m[12] = tmp; michael@0: tmp = m[6]; michael@0: m[6] = m[9]; michael@0: m[9] = tmp; michael@0: tmp = m[7]; michael@0: m[7] = m[13]; michael@0: m[13] = tmp; michael@0: tmp = m[11]; michael@0: m[11] = m[14]; michael@0: m[14] = tmp; michael@0: }, michael@0: pointAt: function pointAt(pos, at, up) { michael@0: notImplemented('Matrix3D.pointAt'); michael@0: }, michael@0: interpolateTo: function interpolateTo(toMat, percent) { michael@0: notImplemented('Matrix3D.interpolateTo'); michael@0: }, michael@0: copyFrom: function copyFrom(sourceMatrix3D) { michael@0: this._matrix.set(sourceMatrix3D._matrix); michael@0: }, michael@0: copyRawDataTo: function copyRawDataTo(vector, index, transpose) { michael@0: var m = this._matrix; michael@0: if (transpose) { michael@0: for (var i = 0, j = index | 0; i < 16; i++, j++) { michael@0: vector.asSetNumericProperty(j, m[transposeTransform[i]]); michael@0: } michael@0: } else { michael@0: for (var i = 0, j = index | 0; i < 16; i++, j++) { michael@0: vector.asSetNumericProperty(j, m[i]); michael@0: } michael@0: } michael@0: }, michael@0: copyRawDataFrom: function copyRawDataFrom(vector, index, transpose) { michael@0: var m = this._matrix; michael@0: if (transpose) { michael@0: for (var i = 0, j = index | 0; i < 16; i++, j++) { michael@0: m[transposeTransform[i]] = vector.asGetNumericProperty(j) || 0; michael@0: } michael@0: } else { michael@0: for (var i = 0, j = index | 0; i < 16; i++, j++) { michael@0: m[i] = vector.asGetNumericProperty(j) || 0; michael@0: } michael@0: } michael@0: }, michael@0: copyRowTo: function copyRowTo(row, vector3D) { michael@0: var offset = row | 0; michael@0: var m = this._matrix; michael@0: vector3D.x = m[offset]; michael@0: vector3D.y = m[offset + 4]; michael@0: vector3D.z = m[offset + 8]; michael@0: vector3D.w = m[offset + 12]; michael@0: }, michael@0: copyColumnTo: function copyColumnTo(column, vector3D) { michael@0: var offset = column << 2; michael@0: var m = this._matrix; michael@0: vector3D.x = m[offset]; michael@0: vector3D.y = m[offset + 1]; michael@0: vector3D.z = m[offset + 2]; michael@0: vector3D.w = m[offset + 3]; michael@0: }, michael@0: copyRowFrom: function copyRowFrom(row, vector3D) { michael@0: var offset = row | 0; michael@0: var m = this._matrix; michael@0: m[offset] = vector3D.x; michael@0: m[offset + 4] = vector3D.y; michael@0: m[offset + 8] = vector3D.z; michael@0: m[offset + 12] = vector3D.w; michael@0: }, michael@0: copyColumnFrom: function copyColumnFrom(column, vector3D) { michael@0: var offset = column << 2; michael@0: var m = this._matrix; michael@0: m[offset] = vector3D.x; michael@0: m[offset + 1] = vector3D.y; michael@0: m[offset + 2] = vector3D.z; michael@0: m[offset + 3] = vector3D.w; michael@0: }, michael@0: rawData: { michael@0: get: function rawData() { michael@0: var result = new Float64Vector(); michael@0: this.copyRawDataTo(result, 0, false); michael@0: return result; michael@0: }, michael@0: set: function rawData(v) { michael@0: this.copyRawDataFrom(v, 0, false); michael@0: } michael@0: }, michael@0: position: { michael@0: get: function position() { michael@0: var m = this._matrix; michael@0: return new flash.geom.Vector3D(m[12], m[13], m[14]); michael@0: }, michael@0: set: function position(pos) { michael@0: var m = this._matrix; michael@0: m[12] = pos.x; michael@0: m[13] = pos.y; michael@0: m[14] = pos.z; michael@0: } michael@0: }, michael@0: determinant: { michael@0: get: function determinant() { michael@0: var m = this._matrix; michael@0: var m11 = m[0], m12 = m[4], m13 = m[8], m14 = m[12], m21 = m[1], m22 = m[5], m23 = m[9], m24 = m[13], m31 = m[2], m32 = m[6], m33 = m[10], m34 = m[14], m41 = m[3], m42 = m[7], m43 = m[11], m44 = m[15]; michael@0: var d; michael@0: d = m11 * (m22 * (m33 * m44 - m43 * m34) - m32 * (m23 * m44 - m43 * m24) + m42 * (m23 * m34 - m33 * m24)) - m21 * (m12 * (m33 * m44 - m43 * m34) - m32 * (m13 * m44 - m43 * m14) + m42 * (m13 * m34 - m33 * m14)) + m31 * (m12 * (m23 * m44 - m43 * m24) - m22 * (m13 * m44 - m43 * m14) + m42 * (m13 * m24 - m23 * m14)) - m41 * (m12 * (m23 * m34 - m33 * m24) - m22 * (m13 * m34 - m33 * m14) + m32 * (m13 * m24 - m23 * m14)); michael@0: return d; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var PointDefinition = function () { michael@0: return { michael@0: __class__: 'flash.geom.Point', michael@0: __glue__: { michael@0: script: { michael@0: static: Glue.ALL, michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var RectangleDefinition = function () { michael@0: return { michael@0: __class__: 'flash.geom.Rectangle', michael@0: __glue__: { michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TransformDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.geom.Transform', michael@0: get colorTransform() { michael@0: var cxform = this._target._cxform; michael@0: if (cxform) { michael@0: return new flash.geom.ColorTransform(cxform.redMultiplier / 256, cxform.greenMultiplier / 256, cxform.blueMultiplier / 256, cxform.alphaMultiplier / 256, cxform.redOffset, cxform.greenOffset, cxform.blueOffset, cxform.alphaOffset); michael@0: } else { michael@0: return new flash.geom.ColorTransform(); michael@0: } michael@0: }, michael@0: set colorTransform(val) { michael@0: var CTClass = avm2.systemDomain.getClass('flash.geom.ColorTransform'); michael@0: if (!CTClass.isInstanceOf(val)) { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.ColorTransform'); michael@0: } michael@0: this._target._cxform = { michael@0: redMultiplier: val.redMultiplier * 256, michael@0: greenMultiplier: val.greenMultiplier * 256, michael@0: blueMultiplier: val.blueMultiplier * 256, michael@0: alphaMultiplier: val.alphaMultiplier * 256, michael@0: redOffset: val.redOffset, michael@0: greenOffset: val.greenOffset, michael@0: blueOffset: val.blueOffset, michael@0: alphaOffset: val.alphaOffset michael@0: }; michael@0: this._target._invalidate(); michael@0: }, michael@0: get concatenatedColorTransform() { michael@0: var cxform = this.colorTransform; michael@0: cxform.concat(this._target.parent.transform.concatenatedColorTransform); michael@0: return cxform; michael@0: }, michael@0: get concatenatedMatrix() { michael@0: if (this._target._current3DTransform) { michael@0: return null; michael@0: } michael@0: var m = this._target._getConcatenatedTransform(null, false); michael@0: return new flash.geom.Matrix(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20); michael@0: }, michael@0: get matrix() { michael@0: if (this._target._current3DTransform) { michael@0: return null; michael@0: } michael@0: var m = this._target._currentTransform; michael@0: return new flash.geom.Matrix(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20); michael@0: }, michael@0: set matrix(val) { michael@0: if (!flash.geom.Matrix.class.isInstanceOf(val)) { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix'); michael@0: } michael@0: var target = this._target; michael@0: target._invalidate(); michael@0: target._setTransformMatrix(val, true); michael@0: target._current3DTransform = null; michael@0: target._animated = false; michael@0: }, michael@0: get matrix3D() { michael@0: var m = this._target._current3DTransform; michael@0: return m && m.clone(); michael@0: }, michael@0: set matrix3D(val) { michael@0: var Matrix3DClass = avm2.systemDomain.getClass('flash.geom.Matrix3D'); michael@0: if (!Matrix3DClass.isInstanceOf(val)) { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix3D'); michael@0: } michael@0: var raw = val.rawData; michael@0: this.matrix = new flash.geom.Matrix(raw.asGetPublicProperty(0), raw.asGetPublicProperty(1), raw.asGetPublicProperty(4), raw.asGetPublicProperty(5), raw.asGetPublicProperty(12), raw.asGetPublicProperty(13)); michael@0: this._target._current3DTransform = val; michael@0: }, michael@0: ctor: function (target) { michael@0: this._target = target; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: colorTransform: desc(def, 'colorTransform'), michael@0: concatenatedColorTransform: desc(def, 'concatenatedColorTransform'), michael@0: concatenatedMatrix: desc(def, 'concatenatedMatrix'), michael@0: matrix: desc(def, 'matrix'), michael@0: matrix3D: desc(def, 'matrix3D'), michael@0: ctor: def.ctor michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var Vector3DDefinition = function () { michael@0: return { michael@0: __class__: 'flash.geom.Vector3D', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var ID3InfoDefinition = function () { michael@0: return { michael@0: __glue__: { michael@0: script: { michael@0: instance: { michael@0: songName: 'public songName', michael@0: genre: 'public genre', michael@0: artist: 'public artist', michael@0: track: 'public track', michael@0: album: 'public album', michael@0: year: 'public year', michael@0: comment: 'public comment' michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var MicrophoneDefinition = function () { michael@0: return { michael@0: __class__: 'flash.media.Microphone', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: getMicrophone: function getMicrophone(index) { michael@0: notImplemented('Microphone.getMicrophone'); michael@0: }, michael@0: getEnhancedMicrophone: function getEnhancedMicrophone(index) { michael@0: notImplemented('Microphone.getEnhancedMicrophone'); michael@0: }, michael@0: names: { michael@0: get: function names() { michael@0: notImplemented('Microphone.names'); michael@0: } michael@0: }, michael@0: isSupported: { michael@0: get: function isSupported() { michael@0: notImplemented('Microphone.isSupported'); michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: setSilenceLevel: function setSilenceLevel(silenceLevel, timeout) { michael@0: notImplemented('Microphone.setSilenceLevel'); michael@0: }, michael@0: setUseEchoSuppression: function setUseEchoSuppression(useEchoSuppression) { michael@0: notImplemented('Microphone.setUseEchoSuppression'); michael@0: }, michael@0: setLoopBack: function setLoopBack(state) { michael@0: notImplemented('Microphone.setLoopBack'); michael@0: }, michael@0: gain: { michael@0: set: function gain(gain) { michael@0: notImplemented('Microphone.gain'); michael@0: this._gain = gain; michael@0: }, michael@0: get: function gain() { michael@0: notImplemented('Microphone.gain'); michael@0: return this._gain; michael@0: } michael@0: }, michael@0: rate: { michael@0: set: function rate(rate) { michael@0: notImplemented('Microphone.rate'); michael@0: this._rate = rate; michael@0: }, michael@0: get: function rate() { michael@0: notImplemented('Microphone.rate'); michael@0: return this._rate; michael@0: } michael@0: }, michael@0: codec: { michael@0: set: function codec(codec) { michael@0: notImplemented('Microphone.codec'); michael@0: this._codec = codec; michael@0: }, michael@0: get: function codec() { michael@0: notImplemented('Microphone.codec'); michael@0: return this._codec; michael@0: } michael@0: }, michael@0: framesPerPacket: { michael@0: get: function framesPerPacket() { michael@0: notImplemented('Microphone.framesPerPacket'); michael@0: return this._framesPerPacket; michael@0: }, michael@0: set: function framesPerPacket(frames) { michael@0: notImplemented('Microphone.framesPerPacket'); michael@0: this._framesPerPacket = frames; michael@0: } michael@0: }, michael@0: encodeQuality: { michael@0: get: function encodeQuality() { michael@0: notImplemented('Microphone.encodeQuality'); michael@0: return this._encodeQuality; michael@0: }, michael@0: set: function encodeQuality(quality) { michael@0: notImplemented('Microphone.encodeQuality'); michael@0: this._encodeQuality = quality; michael@0: } michael@0: }, michael@0: noiseSuppressionLevel: { michael@0: get: function noiseSuppressionLevel() { michael@0: notImplemented('Microphone.noiseSuppressionLevel'); michael@0: return this._noiseSuppressionLevel; michael@0: }, michael@0: set: function noiseSuppressionLevel(level) { michael@0: notImplemented('Microphone.noiseSuppressionLevel'); michael@0: this._noiseSuppressionLevel = level; michael@0: } michael@0: }, michael@0: enableVAD: { michael@0: get: function enableVAD() { michael@0: notImplemented('Microphone.enableVAD'); michael@0: return this._enableVAD; michael@0: }, michael@0: set: function enableVAD(enable) { michael@0: notImplemented('Microphone.enableVAD'); michael@0: this._enableVAD = enable; michael@0: } michael@0: }, michael@0: activityLevel: { michael@0: get: function activityLevel() { michael@0: notImplemented('Microphone.activityLevel'); michael@0: return this._activityLevel; michael@0: } michael@0: }, michael@0: index: { michael@0: get: function index() { michael@0: notImplemented('Microphone.index'); michael@0: return this._index; michael@0: } michael@0: }, michael@0: muted: { michael@0: get: function muted() { michael@0: notImplemented('Microphone.muted'); michael@0: return this._muted; michael@0: } michael@0: }, michael@0: name: { michael@0: get: function name() { michael@0: notImplemented('Microphone.name'); michael@0: return this._name; michael@0: } michael@0: }, michael@0: silenceLevel: { michael@0: get: function silenceLevel() { michael@0: notImplemented('Microphone.silenceLevel'); michael@0: return this._silenceLevel; michael@0: } michael@0: }, michael@0: silenceTimeout: { michael@0: get: function silenceTimeout() { michael@0: notImplemented('Microphone.silenceTimeout'); michael@0: return this._silenceTimeout; michael@0: } michael@0: }, michael@0: useEchoSuppression: { michael@0: get: function useEchoSuppression() { michael@0: notImplemented('Microphone.useEchoSuppression'); michael@0: return this._useEchoSuppression; michael@0: } michael@0: }, michael@0: soundTransform: { michael@0: get: function soundTransform() { michael@0: notImplemented('Microphone.soundTransform'); michael@0: return this._soundTransform; michael@0: }, michael@0: set: function soundTransform(sndTransform) { michael@0: notImplemented('Microphone.soundTransform'); michael@0: this._soundTransform = sndTransform; michael@0: } michael@0: }, michael@0: enhancedOptions: { michael@0: get: function enhancedOptions() { michael@0: notImplemented('Microphone.enhancedOptions'); michael@0: return this._enhancedOptions; michael@0: }, michael@0: set: function enhancedOptions(options) { michael@0: notImplemented('Microphone.enhancedOptions'); michael@0: this._enhancedOptions = options; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var PLAY_USING_AUDIO_TAG = true; michael@0: var SoundDefinition = function () { michael@0: function getAudioDescription(soundData, onComplete) { michael@0: var audioElement = document.createElement('audio'); michael@0: if (!audioElement.canPlayType(soundData.mimeType)) { michael@0: onComplete({ michael@0: duration: 0 michael@0: }); michael@0: return; michael@0: } michael@0: audioElement.preload = 'metadata'; michael@0: var blob = new Blob([ michael@0: soundData.data michael@0: ], { michael@0: type: soundData.mimeType michael@0: }); michael@0: audioElement.src = URL.createObjectURL(blob); michael@0: audioElement.load(); michael@0: audioElement.addEventListener('loadedmetadata', function () { michael@0: onComplete({ michael@0: duration: this.duration * 1000 michael@0: }); michael@0: }); michael@0: } michael@0: var def = { michael@0: initialize: function initialize() { michael@0: this._playQueue = []; michael@0: this._url = null; michael@0: this._length = 0; michael@0: this._bytesTotal = 0; michael@0: this._bytesLoaded = 0; michael@0: this._id3 = new flash.media.ID3Info(); michael@0: var s = this.symbol; michael@0: if (s) { michael@0: var soundData = {}; michael@0: if (s.pcm) { michael@0: soundData.sampleRate = s.sampleRate; michael@0: soundData.channels = s.channels; michael@0: soundData.pcm = s.pcm; michael@0: soundData.end = s.pcm.length; michael@0: } michael@0: soundData.completed = true; michael@0: if (s.packaged) { michael@0: soundData.data = s.packaged.data.buffer; michael@0: soundData.mimeType = s.packaged.mimeType; michael@0: } michael@0: var _this = this; michael@0: getAudioDescription(soundData, function (description) { michael@0: _this._length = description.duration; michael@0: }); michael@0: this._soundData = soundData; michael@0: } michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: SOUND_FEATURE michael@0: }); michael@0: }, michael@0: close: function close() { michael@0: somewhatImplemented('Sound.close'); michael@0: }, michael@0: extract: function extract(target, length, startPosition) { michael@0: notImplemented('Sound.extract'); michael@0: }, michael@0: _load: function _load(request, checkPolicyFile, bufferTime) { michael@0: if (!request) { michael@0: return; michael@0: } michael@0: var _this = this; michael@0: var stream = this._stream = new flash.net.URLStream(); michael@0: var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray'); michael@0: var data = ByteArrayClass.createInstance(); michael@0: var dataPosition = 0; michael@0: var mp3DecodingSession = null; michael@0: var soundData = { michael@0: completed: false michael@0: }; michael@0: stream._addEventListener('progress', function (event) { michael@0: _this._bytesLoaded = event[Multiname.getPublicQualifiedName('bytesLoaded')]; michael@0: _this._bytesTotal = event[Multiname.getPublicQualifiedName('bytesTotal')]; michael@0: if (!PLAY_USING_AUDIO_TAG && !mp3DecodingSession) { michael@0: mp3DecodingSession = decodeMP3(soundData, function (duration, final) { michael@0: if (_this._length === 0) { michael@0: _this._soundData = soundData; michael@0: _this._playQueue.forEach(function (item) { michael@0: item.channel._playSoundDataViaChannel(soundData, item.startTime); michael@0: }); michael@0: } michael@0: _this._length = final ? duration * 1000 : Math.max(duration, mp3DecodingSession.estimateDuration(_this._bytesTotal)) * 1000; michael@0: }); michael@0: } michael@0: var bytesAvailable = stream.bytesAvailable; michael@0: stream.readBytes(data, dataPosition, bytesAvailable); michael@0: if (mp3DecodingSession) { michael@0: mp3DecodingSession.pushData(new Uint8Array(data.a, dataPosition, bytesAvailable)); michael@0: } michael@0: dataPosition += bytesAvailable; michael@0: _this._dispatchEvent(event); michael@0: }); michael@0: stream._addEventListener('complete', function (event) { michael@0: _this._dispatchEvent(event); michael@0: soundData.data = data.a; michael@0: soundData.mimeType = 'audio/mpeg'; michael@0: soundData.completed = true; michael@0: if (PLAY_USING_AUDIO_TAG) { michael@0: _this._soundData = soundData; michael@0: getAudioDescription(soundData, function (description) { michael@0: _this._length = description.duration; michael@0: }); michael@0: _this._playQueue.forEach(function (item) { michael@0: item.channel._playSoundDataViaAudio(soundData, item.startTime); michael@0: }); michael@0: } michael@0: if (mp3DecodingSession) { michael@0: mp3DecodingSession.close(); michael@0: } michael@0: }); michael@0: stream.load(request); michael@0: }, michael@0: loadCompressedDataFromByteArray: function loadCompressedDataFromByteArray(bytes, bytesLength) { michael@0: notImplemented('Sound#loadCompressedDataFromByteArray'); michael@0: }, michael@0: loadPCMFromByteArray: function loadPCMFromByteArray(bytes, samples, format, stereo, sampleRate) { michael@0: notImplemented('Sound#loadPCMFromByteArray'); michael@0: }, michael@0: play: function play(startTime, loops, soundTransform) { michael@0: startTime = startTime || 0; michael@0: loops = loops || 0; michael@0: var channel = new flash.media.SoundChannel(); michael@0: channel._sound = this; michael@0: channel._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform; michael@0: this._playQueue.push({ michael@0: channel: channel, michael@0: startTime: startTime michael@0: }); michael@0: if (this._soundData) { michael@0: if (PLAY_USING_AUDIO_TAG) michael@0: channel._playSoundDataViaAudio(this._soundData, startTime, loops); michael@0: else michael@0: channel._playSoundDataViaChannel(this._soundData, startTime, loops); michael@0: } michael@0: return channel; michael@0: }, michael@0: get bytesLoaded() { michael@0: return this._bytesLoaded; michael@0: }, michael@0: get bytesTotal() { michael@0: return this._bytesTotal; michael@0: }, michael@0: get id3() { michael@0: return this._id3; michael@0: }, michael@0: get isBuffering() { michael@0: notImplemented('Sound#isBuffering'); michael@0: }, michael@0: get isURLInaccessible() { michael@0: notImplemented('Sound#isURLInaccessible'); michael@0: }, michael@0: get length() { michael@0: return this._length; michael@0: }, michael@0: get url() { michael@0: return this._url; michael@0: } michael@0: }; michael@0: function decodeMP3(soundData, ondurationchanged) { michael@0: var currentSize = 8000; michael@0: var pcm = new Float32Array(currentSize); michael@0: var position = 0; michael@0: var lastTimeRatio = 0; michael@0: var durationEstimationData = { michael@0: estimateBitRate: true, michael@0: bitRateSum: 0, michael@0: bitRateCount: 0, michael@0: metadataSize: 0, michael@0: averageBitRate: 0 michael@0: }; michael@0: var mp3DecoderSession = new MP3DecoderSession(); michael@0: mp3DecoderSession.onframedata = function (frame, channels, sampleRate, bitRate) { michael@0: if (durationEstimationData.estimateBitRate) { michael@0: var FramesToEstimate = 200; michael@0: if (durationEstimationData.bitRateCount < FramesToEstimate) { michael@0: durationEstimationData.bitRateSum += bitRate; michael@0: durationEstimationData.bitRateCount++; michael@0: } else { michael@0: durationEstimationData.estimateBitRate = false; michael@0: } michael@0: this.averageBitRate = durationEstimationData.bitRateSum / durationEstimationData.bitRateCount; michael@0: } michael@0: if (frame.length === 0) michael@0: return; michael@0: if (!position) { michael@0: soundData.sampleRate = sampleRate, soundData.channels = channels; michael@0: soundData.pcm = pcm; michael@0: } michael@0: if (position + frame.length >= currentSize) { michael@0: do { michael@0: currentSize *= 2; michael@0: } while (position + frame.length >= currentSize); michael@0: var newPcm = new Float32Array(currentSize); michael@0: newPcm.set(pcm); michael@0: pcm = soundData.pcm = newPcm; michael@0: } michael@0: pcm.set(frame, position); michael@0: soundData.end = position += frame.length; michael@0: lastTimeRatio = 1 / soundData.sampleRate / soundData.channels; michael@0: ondurationchanged(position * lastTimeRatio, false); michael@0: }; michael@0: mp3DecoderSession.onid3tag = function (data) { michael@0: durationEstimationData.metadataSize += data.length; michael@0: }, mp3DecoderSession.onclosed = function () { michael@0: ondurationchanged(position * lastTimeRatio, true); michael@0: }; michael@0: var completed = false; michael@0: return { michael@0: pushData: function (data) { michael@0: mp3DecoderSession.pushAsync(data); michael@0: }, michael@0: estimateDuration: function (fileSize) { michael@0: return Math.max(0, (fileSize - durationEstimationData.metadataSize) * 8 / durationEstimationData.averageBitRate); michael@0: }, michael@0: close: function () { michael@0: mp3DecoderSession.close(); michael@0: } michael@0: }; michael@0: } michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: close: def.close, michael@0: extract: def.extract, michael@0: _load: def._load, michael@0: loadCompressedDataFromByteArray: def.loadCompressedDataFromByteArray, michael@0: loadPCMFromByteArray: def.loadPCMFromByteArray, michael@0: play: def.play, michael@0: bytesLoaded: desc(def, 'bytesLoaded'), michael@0: bytesTotal: desc(def, 'bytesTotal'), michael@0: id3: desc(def, 'id3'), michael@0: isBuffering: desc(def, 'isBuffering'), michael@0: isURLInaccessible: desc(def, 'isURLInaccessible'), michael@0: length: desc(def, 'length'), michael@0: url: desc(def, 'url') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var SoundChannelDefinition = function () { michael@0: return { michael@0: initialize: function () { michael@0: this._element = null; michael@0: this._position = 0; michael@0: this._leftPeak = 0; michael@0: this._rightPeak = 0; michael@0: this._pcmData = null; michael@0: this._soundTransform = new flash.media.SoundTransform(); michael@0: this._soundMixerClass = avm2.systemDomain.getClass('flash.media.SoundMixer'); michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this._element = s.element || null; michael@0: } michael@0: if (this._element) { michael@0: this._registerWithSoundMixer(); michael@0: } michael@0: }, michael@0: _registerWithSoundMixer: function () { michael@0: this._soundMixerClass.native.static._registerChannel(this); michael@0: }, michael@0: _unregisterWithSoundMixer: function () { michael@0: this._soundMixerClass.native.static._unregisterChannel(this); michael@0: }, michael@0: _applySoundTransform: function () { michael@0: var volume = this._soundTransform._volume; michael@0: if (this._soundMixerClass._soundTransform) { michael@0: volume *= this._soundMixerClass._soundTransform._volume; michael@0: } michael@0: volume *= this._soundMixerClass.native.static._getMasterVolume(); michael@0: if (this._element) { michael@0: this._element.volume = clamp(volume, 0, 1); michael@0: } michael@0: if (this._audioChannel) { michael@0: } michael@0: }, michael@0: _playSoundDataViaChannel: function (soundData, startTime, loops) { michael@0: this._registerWithSoundMixer(); michael@0: var self = this; michael@0: var startPosition = Math.round(startTime / 1000 * soundData.sampleRate) * soundData.channels; michael@0: var position = startPosition; michael@0: this._position = startTime; michael@0: this._audioChannel = createAudioChannel(soundData.sampleRate, soundData.channels); michael@0: this._audioChannel.ondatarequested = function (e) { michael@0: var end = soundData.end; michael@0: if (position >= end && soundData.completed) { michael@0: self._unregisterWithSoundMixer(); michael@0: self._audioChannel.stop(); michael@0: self._dispatchEvent(new flash.events.Event('soundComplete', false, false)); michael@0: return; michael@0: } michael@0: var left = e.count; michael@0: var data = e.data; michael@0: var source = soundData.pcm; michael@0: do { michael@0: var count = Math.min(end - position, left); michael@0: for (var j = 0; j < count; j++) { michael@0: data[j] = source[position++]; michael@0: } michael@0: left -= count; michael@0: if (position >= end) { michael@0: if (!loops) michael@0: break; michael@0: loops--; michael@0: position = startPosition; michael@0: } michael@0: } while (left > 0); michael@0: self._position = position / soundData.sampleRate / soundData.channels * 1000; michael@0: }; michael@0: this._audioChannel.start(); michael@0: this._applySoundTransform(); michael@0: }, michael@0: _playSoundDataViaAudio: function (soundData, startTime, loops) { michael@0: if (!soundData.mimeType) michael@0: return; michael@0: this._registerWithSoundMixer(); michael@0: this._position = startTime; michael@0: var self = this; michael@0: var lastCurrentTime = 0; michael@0: var element = document.createElement('audio'); michael@0: if (!element.canPlayType(soundData.mimeType)) { michael@0: console.error('ERROR: "' + soundData.mimeType + '" ' + 'type playback is not supported by the browser'); michael@0: return; michael@0: } michael@0: element.preload = 'metadata'; michael@0: element.loop = loops > 0; michael@0: var blob = new Blob([ michael@0: soundData.data michael@0: ], { michael@0: type: soundData.mimeType michael@0: }); michael@0: element.src = URL.createObjectURL(blob); michael@0: element.addEventListener('loadeddata', function loaded() { michael@0: element.currentTime = startTime / 1000; michael@0: element.play(); michael@0: }); michael@0: element.addEventListener('timeupdate', function timeupdate() { michael@0: var currentTime = element.currentTime; michael@0: if (loops && lastCurrentTime > currentTime) { michael@0: --loops; michael@0: if (!loops) michael@0: element.loop = false; michael@0: if (currentTime < startTime / 1000) michael@0: element.currentTime = startTime / 1000; michael@0: } michael@0: self._position = (lastCurrentTime = currentTime) * 1000; michael@0: }); michael@0: element.addEventListener('ended', function ended() { michael@0: self._unregisterWithSoundMixer(); michael@0: self._dispatchEvent(new flash.events.Event('soundComplete', false, false)); michael@0: self._element = null; michael@0: }); michael@0: this._element = element; michael@0: this._applySoundTransform(); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: stop: function stop() { michael@0: if (this._element) { michael@0: this._unregisterWithSoundMixer(); michael@0: this._element.pause(); michael@0: } michael@0: if (this._audioChannel) { michael@0: this._unregisterWithSoundMixer(); michael@0: this._audioChannel.stop(); michael@0: } michael@0: }, michael@0: 'position': { michael@0: get: function position() { michael@0: return this._position; michael@0: } michael@0: }, michael@0: 'leftPeak': { michael@0: get: function leftPeak() { michael@0: return this._leftPeak; michael@0: } michael@0: }, michael@0: 'rightPeak': { michael@0: get: function rightPeak() { michael@0: return this.rightPeak; michael@0: } michael@0: }, michael@0: 'soundTransform': { michael@0: get: function soundTransform() { michael@0: somewhatImplemented('SoundChannel.soundTransform'); michael@0: return new flash.media.SoundTransform(this._soundTransform._volume, this._soundTransform.pan); michael@0: }, michael@0: set: function soundTransform(soundTransform) { michael@0: somewhatImplemented('SoundChannel.soundTransform'); michael@0: this._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform; michael@0: this._applySoundTransform(); michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: scriptProperties('public', [ michael@0: 'stop' michael@0: ]) michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: function createAudioChannel(sampleRate, channels) { michael@0: if (WebAudioChannel.isSupported) michael@0: return new WebAudioChannel(sampleRate, channels); michael@0: else michael@0: error('PCM data playback is not supported by the browser'); michael@0: } michael@0: function AudioResampler(sourceRate, targetRate) { michael@0: this.sourceRate = sourceRate; michael@0: this.targetRate = targetRate; michael@0: this.tail = []; michael@0: this.sourceOffset = 0; michael@0: } michael@0: AudioResampler.prototype = { michael@0: ondatarequested: function (e) { michael@0: }, michael@0: getData: function (channelsData, count) { michael@0: var k = this.sourceRate / this.targetRate; michael@0: var offset = this.sourceOffset; michael@0: var needed = Math.ceil((count - 1) * k + offset) + 1; michael@0: var sourceData = []; michael@0: for (var channel = 0; channel < channelsData.length; channel++) michael@0: sourceData.push(new Float32Array(needed)); michael@0: var e = { michael@0: data: sourceData, michael@0: count: needed michael@0: }; michael@0: this.ondatarequested(e); michael@0: for (var channel = 0; channel < channelsData.length; channel++) { michael@0: var data = channelsData[channel]; michael@0: var source = sourceData[channel]; michael@0: for (var j = 0; j < count; j++) { michael@0: var i = j * k + offset; michael@0: var i1 = i | 0, i2 = Math.ceil(i) | 0; michael@0: var source_i1 = i1 < 0 ? this.tail[channel] : source[i1]; michael@0: if (i1 === i2) { michael@0: data[j] = source_i1; michael@0: } else { michael@0: var alpha = i - i1; michael@0: data[j] = source_i1 * (1 - alpha) + source[i2] * alpha; michael@0: } michael@0: } michael@0: this.tail[channel] = source[needed - 1]; michael@0: } michael@0: this.sourceOffset = (count - 1) * k + offset - (needed - 1); michael@0: } michael@0: }; michael@0: function WebAudioChannel(sampleRate, channels) { michael@0: var context = WebAudioChannel.context; michael@0: if (!context) { michael@0: if (typeof AudioContext !== 'undefined') michael@0: context = new AudioContext(); michael@0: else michael@0: context = new webkitAudioContext(); michael@0: WebAudioChannel.context = context; michael@0: } michael@0: this.context = context; michael@0: this.contextSampleRate = context.sampleRate || 44100; michael@0: this.channels = channels; michael@0: this.sampleRate = sampleRate; michael@0: if (this.contextSampleRate != sampleRate) { michael@0: this.resampler = new AudioResampler(sampleRate, this.contextSampleRate); michael@0: this.resampler.ondatarequested = function (e) { michael@0: this.requestData(e.data, e.count); michael@0: }.bind(this); michael@0: } michael@0: } michael@0: WebAudioChannel.prototype = { michael@0: start: function () { michael@0: var source = this.context.createScriptProcessor ? this.context.createScriptProcessor(2048, 0, this.channels) : this.context.createJavaScriptNode(2048, 0, this.channels); michael@0: var self = this; michael@0: source.onaudioprocess = function (e) { michael@0: var channelsData = []; michael@0: for (var i = 0; i < self.channels; i++) michael@0: channelsData.push(e.outputBuffer.getChannelData(i)); michael@0: var count = channelsData[0].length; michael@0: if (self.resampler) { michael@0: self.resampler.getData(channelsData, count); michael@0: } else { michael@0: var e = { michael@0: data: channelsData, michael@0: count: count michael@0: }; michael@0: self.requestData(channelsData, count); michael@0: } michael@0: }; michael@0: source.connect(this.context.destination); michael@0: this.source = source; michael@0: }, michael@0: stop: function () { michael@0: this.source.disconnect(this.context.destination); michael@0: }, michael@0: requestData: function (channelsData, count) { michael@0: var channels = this.channels; michael@0: var buffer = new Float32Array(count * channels); michael@0: var e = { michael@0: data: buffer, michael@0: count: buffer.length michael@0: }; michael@0: this.ondatarequested(e); michael@0: for (var j = 0, p = 0; j < count; j++) { michael@0: for (var i = 0; i < channels; i++) michael@0: channelsData[i][j] = buffer[p++]; michael@0: } michael@0: } michael@0: }; michael@0: WebAudioChannel.isSupported = function () { michael@0: return typeof AudioContext !== 'undefined' || typeof webkitAudioContext != 'undefined'; michael@0: }(); michael@0: var SoundMixerDefinition = function () { michael@0: var masterVolume = 1; michael@0: var registeredChannels = []; michael@0: return { michael@0: __class__: 'flash.media.SoundMixer', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: _registerChannel: function _registerChannel(channel) { michael@0: registeredChannels.push(channel); michael@0: }, michael@0: _unregisterChannel: function _unregisterChannel(channel) { michael@0: var index = registeredChannels.indexOf(channel); michael@0: if (index >= 0) michael@0: registeredChannels.splice(index, 1); michael@0: }, michael@0: _getMasterVolume: function _getMasterVolume() { michael@0: return masterVolume; michael@0: }, michael@0: _setMasterVolume: function _setMasterVolume(volume) { michael@0: masterVolume = volume; michael@0: registeredChannels.forEach(function (channel) { michael@0: channel._applySoundTransform(); michael@0: }); michael@0: }, michael@0: stopAll: function stopAll() { michael@0: registeredChannels.forEach(function (channel) { michael@0: channel.stop(); michael@0: }); michael@0: registeredChannels = []; michael@0: }, michael@0: computeSpectrum: function computeSpectrum(outputArray, FFTMode, stretchFactor) { michael@0: somewhatImplemented('SoundMixer.computeSpectrum'); michael@0: var data = new Float32Array(1024); michael@0: for (var i = 0; i < 1024; i++) { michael@0: data[i] = Math.random(); michael@0: } michael@0: outputArray.writeRawBytes(data); michael@0: outputArray.position = 0; michael@0: }, michael@0: areSoundsInaccessible: function areSoundsInaccessible() { michael@0: notImplemented('SoundMixer.areSoundsInaccessible'); michael@0: }, michael@0: bufferTime: { michael@0: get: function bufferTime() { michael@0: notImplemented('SoundMixer.bufferTime'); michael@0: }, michael@0: set: function bufferTime(pA) { michael@0: notImplemented('SoundMixer.bufferTime'); michael@0: } michael@0: }, michael@0: soundTransform: { michael@0: get: function soundTransform() { michael@0: somewhatImplemented('SoundMixer.soundTransform'); michael@0: return isNullOrUndefined(this._soundTransform) ? new flash.media.SoundTransform() : new flash.media.SoundTransform(this._soundTransform._volume, this._soundTransform.pan); michael@0: }, michael@0: set: function soundTransform(soundTransform) { michael@0: somewhatImplemented('SoundMixer.soundTransform'); michael@0: this._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform; michael@0: registeredChannels.forEach(function (channel) { michael@0: channel._applySoundTransform(); michael@0: }); michael@0: } michael@0: }, michael@0: audioPlaybackMode: { michael@0: get: function audioPlaybackMode() { michael@0: notImplemented('SoundMixer.audioPlaybackMode'); michael@0: }, michael@0: set: function audioPlaybackMode(pA) { michael@0: notImplemented('SoundMixer.audioPlaybackMode'); michael@0: } michael@0: }, michael@0: useSpeakerphoneForVoice: { michael@0: get: function useSpeakerphoneForVoice() { michael@0: notImplemented('SoundMixer.useSpeakerphoneForVoice'); michael@0: }, michael@0: set: function useSpeakerphoneForVoice(pA) { michael@0: notImplemented('SoundMixer.useSpeakerphoneForVoice'); michael@0: } michael@0: } michael@0: }, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SoundTransformDefinition = function () { michael@0: return { michael@0: __class__: 'flash.media.SoundTransform', michael@0: initialize: function () { michael@0: }, michael@0: _updateTransform: function () { michael@0: somewhatImplemented('SoundTransform._updateTransform'); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: volume: { michael@0: get: function volume() { michael@0: return this._volume; michael@0: }, michael@0: set: function volume(volume) { michael@0: this._volume = volume; michael@0: this._updateTransform(); michael@0: } michael@0: }, michael@0: leftToLeft: { michael@0: get: function leftToLeft() { michael@0: return this._leftToLeft; michael@0: }, michael@0: set: function leftToLeft(leftToLeft) { michael@0: this._leftToLeft = leftToLeft; michael@0: this._updateTransform(); michael@0: } michael@0: }, michael@0: leftToRight: { michael@0: get: function leftToRight() { michael@0: return this._leftToRight; michael@0: }, michael@0: set: function leftToRight(leftToRight) { michael@0: this._leftToRight = leftToRight; michael@0: this._updateTransform(); michael@0: } michael@0: }, michael@0: rightToRight: { michael@0: get: function rightToRight() { michael@0: return this._rightToRight; michael@0: }, michael@0: set: function rightToRight(rightToRight) { michael@0: this._rightToRight = rightToRight; michael@0: this._updateTransform(); michael@0: } michael@0: }, michael@0: rightToLeft: { michael@0: get: function rightToLeft() { michael@0: return this._rightToLeft; michael@0: }, michael@0: set: function rightToLeft(rightToLeft) { michael@0: this._rightToLeft = rightToLeft; michael@0: this._updateTransform(); michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: { michael@0: pan: 'public pan' michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var StageVideoDefinition = function () { michael@0: return { michael@0: __class__: 'flash.media.StageVideo', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: attachNetStream: function attachNetStream(netStream) { michael@0: notImplemented('StageVideo.attachNetStream'); michael@0: }, michael@0: attachCamera: function attachCamera(theCamera) { michael@0: notImplemented('StageVideo.attachCamera'); michael@0: }, michael@0: viewPort: { michael@0: get: function viewPort() { michael@0: notImplemented('StageVideo.viewPort'); michael@0: return this._viewPort; michael@0: }, michael@0: set: function viewPort(rect) { michael@0: notImplemented('StageVideo.viewPort'); michael@0: this._viewPort = rect; michael@0: } michael@0: }, michael@0: pan: { michael@0: set: function pan(point) { michael@0: notImplemented('StageVideo.pan'); michael@0: this._pan = point; michael@0: }, michael@0: get: function pan() { michael@0: notImplemented('StageVideo.pan'); michael@0: return this._pan; michael@0: } michael@0: }, michael@0: zoom: { michael@0: set: function zoom(point) { michael@0: notImplemented('StageVideo.zoom'); michael@0: this._zoom = point; michael@0: }, michael@0: get: function zoom() { michael@0: notImplemented('StageVideo.zoom'); michael@0: return this._zoom; michael@0: } michael@0: }, michael@0: depth: { michael@0: set: function depth(depth) { michael@0: notImplemented('StageVideo.depth'); michael@0: this._depth = depth; michael@0: }, michael@0: get: function depth() { michael@0: notImplemented('StageVideo.depth'); michael@0: return this._depth; michael@0: } michael@0: }, michael@0: videoWidth: { michael@0: get: function videoWidth() { michael@0: notImplemented('StageVideo.videoWidth'); michael@0: return this._videoWidth; michael@0: } michael@0: }, michael@0: videoHeight: { michael@0: get: function videoHeight() { michael@0: notImplemented('StageVideo.videoHeight'); michael@0: return this._videoHeight; michael@0: } michael@0: }, michael@0: colorSpaces: { michael@0: get: function colorSpaces() { michael@0: notImplemented('StageVideo.colorSpaces'); michael@0: return this._colorSpaces; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var VideoDefinition = function () { michael@0: function burnHole(ctx, x, y, width, height) { michael@0: ctx.save(); michael@0: ctx.beginPath(); michael@0: ctx.rect(0, 0, width, height); michael@0: ctx.clip(); michael@0: ctx.clearRect(0, 0, width, height); michael@0: ctx.restore(); michael@0: } michael@0: var def = { michael@0: initialize: function initialize() { michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: VIDEO_FEATURE michael@0: }); michael@0: }, michael@0: attachNetStream: function (netStream) { michael@0: if (this._netStream === netStream) { michael@0: return; michael@0: } michael@0: if (this._netStream) { michael@0: this._netStream._videoReady.then(function (element) { michael@0: this._element = null; michael@0: if (this._added) { michael@0: element.remove(); michael@0: this._added = false; michael@0: } michael@0: }.bind(this)); michael@0: } michael@0: this._netStream = netStream; michael@0: if (!netStream) { michael@0: return; michael@0: } michael@0: netStream._videoReady.then(function (element) { michael@0: this._element = element; michael@0: netStream._videoMetadataReady.then(function (url) { michael@0: this._element.width = this._videoWidth = this._element.videoWidth; michael@0: this._element.height = this._videoHeight = this._element.videoHeight; michael@0: if (this.stage) { michael@0: this.stage._invalid = true; michael@0: } michael@0: }.bind(this)); michael@0: }.bind(this)); michael@0: }, michael@0: ctor: function (width, height) { michael@0: if (!width || width < 0) michael@0: width = 320; michael@0: if (!height || height < 0) michael@0: height = 240; michael@0: this._bbox = { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: width * 20, michael@0: yMax: height * 20 michael@0: }; michael@0: this._initialWidth = this._videoWidth = width; michael@0: this._initialHeight = this._videoHeight = height; michael@0: this._netStream = null; michael@0: this._element = null; michael@0: this._added = false; michael@0: }, michael@0: draw: function (ctx, ratio, ct, parentCtxs) { michael@0: if (!this._element) { michael@0: return; michael@0: } michael@0: if (!this._added && this._stage) { michael@0: this._stage._domContainer.appendChild(this._element); michael@0: this._added = true; michael@0: } michael@0: var width = this._initialWidth; michael@0: var height = this._initialHeight; michael@0: var matrix = this._getConcatenatedTransform(null, true); michael@0: var scaleFactor = this.stage && this.stage._contentsScaleFactor || 1; michael@0: var a = matrix.a / scaleFactor; michael@0: var b = matrix.b / scaleFactor; michael@0: var c = matrix.c / scaleFactor; michael@0: var d = matrix.d / scaleFactor; michael@0: var e = matrix.tx / 20 / scaleFactor; michael@0: var f = matrix.ty / 20 / scaleFactor; michael@0: if (width > 0 && height > 0) { michael@0: burnHole(ctx, 0, 0, width, height); michael@0: parentCtxs.forEach(function (ctx) { michael@0: ctx.save(); michael@0: ctx.setTransform(a, b, c, d, e, f); michael@0: burnHole(ctx, 0, 0, width, height); michael@0: ctx.restore(); michael@0: }); michael@0: } michael@0: var sx = width / this._videoWidth; michael@0: var sy = height / this._videoHeight; michael@0: var cssTransform = 'transform: matrix(' + sx * a + ',' + sx * b + ',' + sy * c + ',' + sy * d + ',' + e + ',' + f + ');'; michael@0: if (this._currentCssTransform !== cssTransform) { michael@0: this._currentCssTransform = cssTransform; michael@0: this._element.setAttribute('style', 'position: absolute; top:0; left:0; z-index: -100;transform-origin: 0px 0px 0;' + cssTransform + '-webkit-transform-origin: 0px 0px 0; -webkit-' + cssTransform); michael@0: } michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: attachNetStream: def.attachNetStream, michael@0: ctor: def.ctor, michael@0: smoothing: { michael@0: get: function smoothing() { michael@0: return this._smoothing; michael@0: }, michael@0: set: function smoothing(value) { michael@0: somewhatImplemented('Video.smoothing'); michael@0: this._smoothing = value; michael@0: } michael@0: }, michael@0: videoHeight: { michael@0: get: function videoHeight() { michael@0: return this._videoHeight; michael@0: } michael@0: }, michael@0: videoWidth: { michael@0: get: function videoWidth() { michael@0: return this._videoWidth; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: { michael@0: var FileFilterDefinition = function () { michael@0: return { michael@0: __class__: 'flash.net.FileFilter', michael@0: initialize: function () { michael@0: this._description = null; michael@0: this._extension = null; michael@0: this._macType = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: description: { michael@0: get: function description() { michael@0: return this._description; michael@0: }, michael@0: set: function description(value) { michael@0: this._description = value; michael@0: } michael@0: }, michael@0: extension: { michael@0: get: function extension() { michael@0: return this._extension; michael@0: }, michael@0: set: function extension(value) { michael@0: this._extension = value; michael@0: } michael@0: }, michael@0: macType: { michael@0: get: function macType() { michael@0: return this._macType; michael@0: }, michael@0: set: function macType(value) { michael@0: this._macType = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var LocalConnectionDefinition = function () { michael@0: return { michael@0: __class__: 'flash.net.LocalConnection', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: close: function close() { michael@0: notImplemented('LocalConnection.close'); michael@0: }, michael@0: connect: function connect(connectionName) { michael@0: notImplemented('LocalConnection.connect'); michael@0: }, michael@0: send: function send(connectionName, methodName) { michael@0: notImplemented('LocalConnection.send'); michael@0: }, michael@0: allowDomain: function allowDomain() { michael@0: notImplemented('LocalConnection.allowDomain'); michael@0: }, michael@0: allowInsecureDomain: function allowInsecureDomain() { michael@0: notImplemented('LocalConnection.allowInsecureDomain'); michael@0: }, michael@0: domain: { michael@0: get: function domain() { michael@0: somewhatImplemented('LocalConnection.domain'); michael@0: var url = FileLoadingService.resolveUrl('/'); michael@0: var m = /:\/\/(.+?)[:?#\/]/.exec(url); michael@0: return m && m[1]; michael@0: } michael@0: }, michael@0: client: { michael@0: get: function client() { michael@0: notImplemented('LocalConnection.client'); michael@0: return this._client; michael@0: }, michael@0: set: function client(client) { michael@0: notImplemented('LocalConnection.client'); michael@0: this._client = client; michael@0: } michael@0: }, michael@0: isPerUser: { michael@0: get: function isPerUser() { michael@0: notImplemented('LocalConnection.isPerUser'); michael@0: return this._isPerUser; michael@0: }, michael@0: set: function isPerUser(newValue) { michael@0: notImplemented('LocalConnection.isPerUser'); michael@0: this._isPerUser = newValue; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var NetConnectionDefinition = function () { michael@0: var defaultObjectEncoding = 3; michael@0: return { michael@0: __class__: 'flash.net.NetConnection', michael@0: initialize: function () { michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: NETCONNECTION_FEATURE michael@0: }); michael@0: }, michael@0: _invoke: function (index, args) { michael@0: var simulated = false, result; michael@0: switch (index) { michael@0: case 2: michael@0: simulated = true; michael@0: break; michael@0: } michael@0: (simulated ? somewhatImplemented : notImplemented)('NetConnection._invoke (' + index + ')'); michael@0: return result; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: defaultObjectEncoding: { michael@0: get: function defaultObjectEncoding() { michael@0: return defaultObjectEncoding; michael@0: }, michael@0: set: function defaultObjectEncoding(version) { michael@0: somewhatImplemented('NetConnection.defaultObjectEncoding'); michael@0: return defaultObjectEncoding; michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: ctor: function ctor() { michael@0: this._uri = null; michael@0: this._connected = false; michael@0: this._client = null; michael@0: this._proxyType = 'none'; michael@0: this._objectEncoding = defaultObjectEncoding; michael@0: }, michael@0: connect: function connect(command) { michael@0: var NetStatusEvent = flash.events.NetStatusEvent; michael@0: somewhatImplemented('NetConnection.connect'); michael@0: this._uri = command; michael@0: if (!command) { michael@0: this._connected = true; michael@0: this._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: level: 'status', michael@0: code: 'NetConnection.Connect.Success' michael@0: }))); michael@0: } else { michael@0: this._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: level: 'status', michael@0: code: 'NetConnection.Connect.Failed' michael@0: }))); michael@0: } michael@0: }, michael@0: call: function call(command, responder) { michael@0: notImplemented('NetConnection.call'); michael@0: }, michael@0: connected: { michael@0: get: function connected() { michael@0: return this._connected; michael@0: } michael@0: }, michael@0: uri: { michael@0: get: function uri() { michael@0: return this._uri; michael@0: } michael@0: }, michael@0: client: { michael@0: get: function client() { michael@0: return this._client; michael@0: }, michael@0: set: function client(object) { michael@0: this._client = object; michael@0: } michael@0: }, michael@0: objectEncoding: { michael@0: get: function objectEncoding() { michael@0: return this._objectEncoding; michael@0: }, michael@0: set: function objectEncoding(version) { michael@0: somewhatImplemented('NetConnection.objectEncoding'); michael@0: this._objectEncoding = version; michael@0: } michael@0: }, michael@0: proxyType: { michael@0: get: function proxyType() { michael@0: return this._proxyType; michael@0: }, michael@0: set: function proxyType(ptype) { michael@0: notImplemented('NetConnection.proxyType'); michael@0: this._proxyType = ptype; michael@0: } michael@0: }, michael@0: connectedProxyType: { michael@0: get: function connectedProxyType() { michael@0: notImplemented('NetConnection.connectedProxyType'); michael@0: return this._connectedProxyType; michael@0: } michael@0: }, michael@0: usingTLS: { michael@0: get: function usingTLS() { michael@0: somewhatImplemented('NetConnection.usingTLS'); michael@0: return false; michael@0: } michael@0: }, michael@0: protocol: { michael@0: get: function protocol() { michael@0: notImplemented('NetConnection.protocol'); michael@0: return this._protocol; michael@0: } michael@0: }, michael@0: maxPeerConnections: { michael@0: get: function maxPeerConnections() { michael@0: notImplemented('NetConnection.maxPeerConnections'); michael@0: return this._maxPeerConnections; michael@0: }, michael@0: set: function maxPeerConnections(maxPeers) { michael@0: notImplemented('NetConnection.maxPeerConnections'); michael@0: this._maxPeerConnections = maxPeers; michael@0: } michael@0: }, michael@0: nearID: { michael@0: get: function nearID() { michael@0: notImplemented('NetConnection.nearID'); michael@0: return this._nearID; michael@0: } michael@0: }, michael@0: farID: { michael@0: get: function farID() { michael@0: notImplemented('NetConnection.farID'); michael@0: return this._farID; michael@0: } michael@0: }, michael@0: nearNonce: { michael@0: get: function nearNonce() { michael@0: notImplemented('NetConnection.nearNonce'); michael@0: return this._nearNonce; michael@0: } michael@0: }, michael@0: farNonce: { michael@0: get: function farNonce() { michael@0: notImplemented('NetConnection.farNonce'); michael@0: return this._farNonce; michael@0: } michael@0: }, michael@0: unconnectedPeerStreams: { michael@0: get: function unconnectedPeerStreams() { michael@0: notImplemented('NetConnection.unconnectedPeerStreams'); michael@0: return this._unconnectedPeerStreams; michael@0: } michael@0: }, michael@0: invoke: function invokeWithArgsArray(index) { michael@0: return this._invoke(index, Array.prototype.slice.call(arguments, 1)); michael@0: }, michael@0: invokeWithArgsArray: function invokeWithArgsArray(index, p_arguments) { michael@0: return this._invoke.call(this, index, p_arguments); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var USE_MEDIASOURCE_API = false; michael@0: var NetStreamDefinition = function () { michael@0: return { michael@0: __class__: 'flash.net.NetStream', michael@0: initialize: function () { michael@0: }, michael@0: _invoke: function (index, args) { michael@0: var simulated = false, result; michael@0: var videoElement = this._videoElement; michael@0: switch (index) { michael@0: case 4: michael@0: this._videoState.bufferTime = args[0]; michael@0: simulated = true; michael@0: break; michael@0: case 202: michael@0: switch (args[1]) { michael@0: case 'pause': michael@0: simulated = true; michael@0: if (videoElement) { michael@0: if (args[3] !== false && !videoElement.paused) { michael@0: videoElement.pause(); michael@0: } else if (args[3] !== true && videoElement.paused) { michael@0: videoElement.play(); michael@0: } michael@0: videoElement.currentTime = args[4] / 1000; michael@0: } michael@0: break; michael@0: case 'seek': michael@0: simulated = true; michael@0: if (videoElement && !videoElement.paused) { michael@0: videoElement.currentTime = args[3] / 1000; michael@0: } michael@0: break; michael@0: } michael@0: break; michael@0: case 300: michael@0: result = videoElement ? videoElement.currentTime : 0; michael@0: simulated = true; michael@0: break; michael@0: case 302: michael@0: result = this._videoState.bufferTime; michael@0: simulated = true; michael@0: break; michael@0: case 303: michael@0: result = videoElement ? videoElement.duration : 0; michael@0: simulated = true; michael@0: break; michael@0: case 305: michael@0: result = this._videoState.buffer === 'full' ? 100 : this._videoState.buffer === 'progress' ? 50 : 0; michael@0: simulated = true; michael@0: break; michael@0: case 306: michael@0: result = 100; michael@0: simulated = true; michael@0: break; michael@0: } michael@0: (simulated ? somewhatImplemented : notImplemented)('NetStream._invoke (' + index + ')'); michael@0: return result; michael@0: }, michael@0: _createVideoElement: function (url) { michael@0: function notifyPlayStart(e) { michael@0: if (netStream._videoState.started) { michael@0: return; michael@0: } michael@0: netStream._videoState.started = true; michael@0: netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: code: 'NetStream.Play.Start', michael@0: level: 'status' michael@0: }))); michael@0: } michael@0: function notifyPlayStop(e) { michael@0: netStream._videoState.started = false; michael@0: netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: code: 'NetStream.Play.Stop', michael@0: level: 'status' michael@0: }))); michael@0: } michael@0: function notifyBufferFull(e) { michael@0: netStream._videoState.buffer = 'full'; michael@0: netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: code: 'NetStream.Buffer.Full', michael@0: level: 'status' michael@0: }))); michael@0: } michael@0: function notifyProgress(e) { michael@0: netStream._videoState.buffer = 'progress'; michael@0: } michael@0: function notifyBufferEmpty(e) { michael@0: netStream._videoState.buffer = 'empty'; michael@0: netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: code: 'NetStream.Buffer.Empty', michael@0: level: 'status' michael@0: }))); michael@0: } michael@0: function notifyError(e) { michael@0: var code = e.target.error.code === 4 ? 'NetStream.Play.NoSupportedTrackFound' : e.target.error.code === 3 ? 'NetStream.Play.FileStructureInvalid' : 'NetStream.Play.StreamNotFound'; michael@0: netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({ michael@0: code: code, michael@0: level: 'error' michael@0: }))); michael@0: } michael@0: function notifyMetadata(e) { michael@0: netStream._videoMetadataReady.resolve({ michael@0: videoWidth: element.videoWidth, michael@0: videoHeight: element.videoHeight michael@0: }); michael@0: if (netStream._client) { michael@0: var data = {}; michael@0: data.asSetPublicProperty('width', element.videoWidth); michael@0: data.asSetPublicProperty('height', element.videoHeight); michael@0: data.asSetPublicProperty('duration', element.duration); michael@0: netStream._client.asCallPublicProperty('onMetaData', [ michael@0: data michael@0: ]); michael@0: } michael@0: } michael@0: var NetStatusEvent = flash.events.NetStatusEvent; michael@0: var netStream = this; michael@0: if (/\.mp4$/i.test(url) && /Intel Mac OS X.*?Firefox\/\d+/.test(window.navigator.userAgent)) { michael@0: url = 'http://videos-cdn.mozilla.net/brand/Mozilla_2011_Story.webm'; michael@0: } michael@0: var element = document.createElement('video'); michael@0: element.preload = 'metadata'; michael@0: element.src = url; michael@0: element.addEventListener('play', notifyPlayStart); michael@0: element.addEventListener('ended', notifyPlayStop); michael@0: element.addEventListener('loadeddata', notifyBufferFull); michael@0: element.addEventListener('progress', notifyProgress); michael@0: element.addEventListener('waiting', notifyBufferEmpty); michael@0: element.addEventListener('loadedmetadata', notifyMetadata); michael@0: element.addEventListener('error', notifyError); michael@0: element.play(); michael@0: this._videoElement = element; michael@0: this._videoReady.resolve(element); michael@0: }, michael@0: __glue__: { michael@0: script: { michael@0: instance: scriptProperties('public', [ michael@0: 'appendBytes', michael@0: 'appendBytesAction' michael@0: ]) michael@0: }, michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: ctor: function ctor(connection, peerID) { michael@0: somewhatImplemented('NetStream.ctor'); michael@0: this._contentTypeHint = null; michael@0: this._mediaSource = null; michael@0: this._checkPolicyFile = true; michael@0: this._videoElement = null; michael@0: var videoReadyResolve, videoReadyReject; michael@0: this._videoReady = new Promise(function (resolve, reject) { michael@0: videoReadyResolve = resolve; michael@0: videoReadyReject = reject; michael@0: }); michael@0: this._videoReady.resolve = videoReadyResolve; michael@0: this._videoReady.reject = videoReadyReject; michael@0: var videoMetadataReadyResolve, videoMetadataReadyReject; michael@0: this._videoMetadataReady = new Promise(function (resolve, reject) { michael@0: videoMetadataReadyResolve = resolve; michael@0: videoMetadataReadyReject = reject; michael@0: }); michael@0: this._videoMetadataReady.resolve = videoMetadataReadyResolve; michael@0: this._videoMetadataReady.reject = videoMetadataReadyReject; michael@0: this._videoState = { michael@0: started: false, michael@0: buffer: 'empty', michael@0: bufferTime: 0.1 michael@0: }; michael@0: }, michael@0: onResult: function onResult(streamId) { michael@0: notImplemented('NetStream.onResult'); michael@0: }, michael@0: dispose: function dispose() { michael@0: notImplemented('NetStream.dispose'); michael@0: }, michael@0: play: function play(url) { michael@0: var isMediaSourceEnabled = USE_MEDIASOURCE_API; michael@0: if (isMediaSourceEnabled && typeof MediaSource === 'undefined') { michael@0: console.warn('MediaSource API is not enabled, falling back to regular playback'); michael@0: isMediaSourceEnabled = false; michael@0: } michael@0: if (!isMediaSourceEnabled) { michael@0: somewhatImplemented('NetStream.play'); michael@0: this._createVideoElement(FileLoadingService.resolveUrl(url)); michael@0: return; michael@0: } michael@0: var mediaSource = new MediaSource(); michael@0: mediaSource.addEventListener('sourceopen', function (e) { michael@0: this._mediaSource = mediaSource; michael@0: }.bind(this)); michael@0: mediaSource.addEventListener('sourceend', function (e) { michael@0: this._mediaSource = null; michael@0: }.bind(this)); michael@0: this._createVideoElement(window.URL.createObjectURL(mediaSource)); michael@0: if (!url) { michael@0: return; michael@0: } michael@0: var request = new flash.net.URLRequest(url); michael@0: request._checkPolicyFile = this._checkPolicyFile; michael@0: var stream = new flash.net.URLStream(); michael@0: stream._addEventListener('httpStatus', function (e) { michael@0: var responseHeaders = e.asGetPublicProperty('responseHeaders'); michael@0: var contentTypeHeader = responseHeaders.filter(function (h) { michael@0: return h.asGetPublicProperty('name') === 'Content-Type'; michael@0: })[0]; michael@0: if (contentTypeHeader && contentTypeHeader.asGetPublicProperty('value') !== 'application/octet-stream') { michael@0: this._contentTypeHint = contentTypeHeader.asGetPublicProperty('value'); michael@0: } michael@0: }.bind(this)); michael@0: stream._addEventListener('progress', function (e) { michael@0: var available = stream.bytesAvailable; michael@0: var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray'); michael@0: var data = ByteArrayClass.createInstance(); michael@0: stream.readBytes(data, 0, available); michael@0: this.appendBytes(data); michael@0: }.bind(this)); michael@0: stream._addEventListener('complete', function (e) { michael@0: this.appendBytesAction('endSequence'); michael@0: }.bind(this)); michael@0: stream.load(request); michael@0: }, michael@0: play2: function play2(param) { michael@0: notImplemented('NetStream.play2'); michael@0: }, michael@0: invoke: function invoke(index) { michael@0: return this._invoke(index, Array.prototype.slice.call(arguments, 1)); michael@0: }, michael@0: invokeWithArgsArray: function invokeWithArgsArray(index, p_arguments) { michael@0: return this._invoke.call(this, index, p_arguments); michael@0: }, michael@0: appendBytes: function appendBytes(bytes) { michael@0: if (this._mediaSource) { michael@0: if (!this._mediaSourceBuffer) { michael@0: this._mediaSourceBuffer = this._mediaSource.addSourceBuffer(this._contentTypeHint); michael@0: } michael@0: this._mediaSourceBuffer.appendBuffer(new Uint8Array(bytes.a, 0, bytes.length)); michael@0: } michael@0: somewhatImplemented('NetStream.appendBytes'); michael@0: }, michael@0: appendBytesAction: function appendBytesAction(netStreamAppendBytesAction) { michael@0: if (netStreamAppendBytesAction === 'endSequence' && this._mediaSource) { michael@0: this._mediaSource.endOfStream(); michael@0: } michael@0: somewhatImplemented('NetStream.appendBytesAction'); michael@0: }, michael@0: info: { michael@0: get: function info() { michael@0: notImplemented('NetStream.info'); michael@0: return this._info; michael@0: } michael@0: }, michael@0: multicastInfo: { michael@0: get: function multicastInfo() { michael@0: notImplemented('NetStream.multicastInfo'); michael@0: return this._multicastInfo; michael@0: } michael@0: }, michael@0: soundTransform: { michael@0: get: function soundTransform() { michael@0: return this._soundTransform; michael@0: }, michael@0: set: function soundTransform(sndTransform) { michael@0: somewhatImplemented('NetStream.soundTransform'); michael@0: this._soundTransform = sndTransform; michael@0: } michael@0: }, michael@0: checkPolicyFile: { michael@0: get: function checkPolicyFile() { michael@0: return this._checkPolicyFile; michael@0: }, michael@0: set: function checkPolicyFile(state) { michael@0: this._checkPolicyFile = state; michael@0: } michael@0: }, michael@0: client: { michael@0: get: function client() { michael@0: somewhatImplemented('NetStream.client'); michael@0: return this._client; michael@0: }, michael@0: set: function client(object) { michael@0: somewhatImplemented('NetStream.client'); michael@0: this._client = object; michael@0: } michael@0: }, michael@0: objectEncoding: { michael@0: get: function objectEncoding() { michael@0: notImplemented('NetStream.objectEncoding'); michael@0: return this._objectEncoding; michael@0: } michael@0: }, michael@0: multicastPushNeighborLimit: { michael@0: get: function multicastPushNeighborLimit() { michael@0: notImplemented('NetStream.multicastPushNeighborLimit'); michael@0: return this._multicastPushNeighborLimit; michael@0: }, michael@0: set: function multicastPushNeighborLimit(neighbors) { michael@0: notImplemented('NetStream.multicastPushNeighborLimit'); michael@0: this._multicastPushNeighborLimit = neighbors; michael@0: } michael@0: }, michael@0: multicastWindowDuration: { michael@0: get: function multicastWindowDuration() { michael@0: notImplemented('NetStream.multicastWindowDuration'); michael@0: return this._multicastWindowDuration; michael@0: }, michael@0: set: function multicastWindowDuration(seconds) { michael@0: notImplemented('NetStream.multicastWindowDuration'); michael@0: this._multicastWindowDuration = seconds; michael@0: } michael@0: }, michael@0: multicastRelayMarginDuration: { michael@0: get: function multicastRelayMarginDuration() { michael@0: notImplemented('NetStream.multicastRelayMarginDuration'); michael@0: return this._multicastRelayMarginDuration; michael@0: }, michael@0: set: function multicastRelayMarginDuration(seconds) { michael@0: notImplemented('NetStream.multicastRelayMarginDuration'); michael@0: this._multicastRelayMarginDuration = seconds; michael@0: } michael@0: }, michael@0: multicastAvailabilityUpdatePeriod: { michael@0: get: function multicastAvailabilityUpdatePeriod() { michael@0: notImplemented('NetStream.multicastAvailabilityUpdatePeriod'); michael@0: return this._multicastAvailabilityUpdatePeriod; michael@0: }, michael@0: set: function multicastAvailabilityUpdatePeriod(seconds) { michael@0: notImplemented('NetStream.multicastAvailabilityUpdatePeriod'); michael@0: this._multicastAvailabilityUpdatePeriod = seconds; michael@0: } michael@0: }, michael@0: multicastFetchPeriod: { michael@0: get: function multicastFetchPeriod() { michael@0: notImplemented('NetStream.multicastFetchPeriod'); michael@0: return this._multicastFetchPeriod; michael@0: }, michael@0: set: function multicastFetchPeriod(seconds) { michael@0: notImplemented('NetStream.multicastFetchPeriod'); michael@0: this._multicastFetchPeriod = seconds; michael@0: } michael@0: }, michael@0: multicastAvailabilitySendToAll: { michael@0: get: function multicastAvailabilitySendToAll() { michael@0: notImplemented('NetStream.multicastAvailabilitySendToAll'); michael@0: return this._multicastAvailabilitySendToAll; michael@0: }, michael@0: set: function multicastAvailabilitySendToAll(value) { michael@0: notImplemented('NetStream.multicastAvailabilitySendToAll'); michael@0: this._multicastAvailabilitySendToAll = value; michael@0: } michael@0: }, michael@0: farID: { michael@0: get: function farID() { michael@0: notImplemented('NetStream.farID'); michael@0: return this._farID; michael@0: } michael@0: }, michael@0: nearNonce: { michael@0: get: function nearNonce() { michael@0: notImplemented('NetStream.nearNonce'); michael@0: return this._nearNonce; michael@0: } michael@0: }, michael@0: farNonce: { michael@0: get: function farNonce() { michael@0: notImplemented('NetStream.farNonce'); michael@0: return this._farNonce; michael@0: } michael@0: }, michael@0: peerStreams: { michael@0: get: function peerStreams() { michael@0: notImplemented('NetStream.peerStreams'); michael@0: return this._peerStreams; michael@0: } michael@0: }, michael@0: audioReliable: { michael@0: get: function audioReliable() { michael@0: notImplemented('NetStream.audioReliable'); michael@0: return this._audioReliable; michael@0: }, michael@0: set: function audioReliable(reliable) { michael@0: notImplemented('NetStream.audioReliable'); michael@0: this._audioReliable = reliable; michael@0: } michael@0: }, michael@0: videoReliable: { michael@0: get: function videoReliable() { michael@0: notImplemented('NetStream.videoReliable'); michael@0: return this._videoReliable; michael@0: }, michael@0: set: function videoReliable(reliable) { michael@0: notImplemented('NetStream.videoReliable'); michael@0: this._videoReliable = reliable; michael@0: } michael@0: }, michael@0: dataReliable: { michael@0: get: function dataReliable() { michael@0: notImplemented('NetStream.dataReliable'); michael@0: return this._dataReliable; michael@0: }, michael@0: set: function dataReliable(reliable) { michael@0: notImplemented('NetStream.dataReliable'); michael@0: this._dataReliable = reliable; michael@0: } michael@0: }, michael@0: audioSampleAccess: { michael@0: get: function audioSampleAccess() { michael@0: notImplemented('NetStream.audioSampleAccess'); michael@0: return this._audioSampleAccess; michael@0: }, michael@0: set: function audioSampleAccess(reliable) { michael@0: notImplemented('NetStream.audioSampleAccess'); michael@0: this._audioSampleAccess = reliable; michael@0: } michael@0: }, michael@0: videoSampleAccess: { michael@0: get: function videoSampleAccess() { michael@0: notImplemented('NetStream.videoSampleAccess'); michael@0: return this._videoSampleAccess; michael@0: }, michael@0: set: function videoSampleAccess(reliable) { michael@0: notImplemented('NetStream.videoSampleAccess'); michael@0: this._videoSampleAccess = reliable; michael@0: } michael@0: }, michael@0: useHardwareDecoder: { michael@0: get: function useHardwareDecoder() { michael@0: notImplemented('NetStream.useHardwareDecoder'); michael@0: return this._useHardwareDecoder; michael@0: }, michael@0: set: function useHardwareDecoder(v) { michael@0: notImplemented('NetStream.useHardwareDecoder'); michael@0: this._useHardwareDecoder = v; michael@0: } michael@0: }, michael@0: useJitterBuffer: { michael@0: get: function useJitterBuffer() { michael@0: notImplemented('NetStream.useJitterBuffer'); michael@0: return this._useJitterBuffer; michael@0: }, michael@0: set: function useJitterBuffer(value) { michael@0: notImplemented('NetStream.useJitterBuffer'); michael@0: this._useJitterBuffer = value; michael@0: } michael@0: }, michael@0: videoStreamSettings: { michael@0: get: function videoStreamSettings() { michael@0: notImplemented('NetStream.videoStreamSettings'); michael@0: return this._videoStreamSettings; michael@0: }, michael@0: set: function videoStreamSettings(settings) { michael@0: notImplemented('NetStream.videoStreamSettings'); michael@0: this._videoStreamSettings = settings; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ObjectEncodingDefinition = function () { michael@0: return { michael@0: __class__: 'flash.net.ObjectEncoding', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: dynamicPropertyWriter: { michael@0: get: function dynamicPropertyWriter() { michael@0: notImplemented('ObjectEncoding.dynamicPropertyWriter'); michael@0: }, michael@0: set: function dynamicPropertyWriter(object) { michael@0: notImplemented('ObjectEncoding.dynamicPropertyWriter'); michael@0: } michael@0: } michael@0: }, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ResponderDefinition = function () { michael@0: var def = { michael@0: ctor: function (result, status) { michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: ctor: def.ctor michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var SharedObjectDefinition = function () { michael@0: var _defaultObjectEncoding = 3; michael@0: var sharedObjects = createEmptyObject(); michael@0: function invokeWithArgsArray(index, args) { michael@0: var simulated = false, result; michael@0: switch (index) { michael@0: case 4: michael@0: result = JSON.stringify(this._data).length - 2; michael@0: simulated = true; michael@0: break; michael@0: case 6: michael@0: this._data = {}; michael@0: sessionStorage.removeItem(this._path); michael@0: simulated = true; michael@0: break; michael@0: case 2: michael@0: sessionStorage.setItem(this._path, JSON.stringify(this._data)); michael@0: simulated = true; michael@0: result = true; michael@0: break; michael@0: case 3: michael@0: simulated = true; michael@0: break; michael@0: } michael@0: (simulated ? somewhatImplemented : notImplemented)('SharedObject.invoke (' + index + ')'); michael@0: return result; michael@0: } michael@0: return { michael@0: __class__: 'flash.net.SharedObject', michael@0: initialize: function () { michael@0: this._path = null; michael@0: this._data = null; michael@0: this._objectEncoding = _defaultObjectEncoding; michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: SHAREDOBJECT_FEATURE michael@0: }); michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: deleteAll: function deleteAll(url) { michael@0: notImplemented('SharedObject.deleteAll'); michael@0: }, michael@0: getDiskUsage: function getDiskUsage(url) { michael@0: notImplemented('SharedObject.getDiskUsage'); michael@0: }, michael@0: getLocal: function getLocal(name, localPath, secure) { michael@0: var path = (localPath || '') + '/' + name; michael@0: if (sharedObjects[path]) { michael@0: return sharedObjects[path]; michael@0: } michael@0: var so = new flash.net.SharedObject(); michael@0: so._path = path; michael@0: var data = sessionStorage.getItem(path); michael@0: so._data = data ? JSON.parse(data) : {}; michael@0: return so; michael@0: }, michael@0: getRemote: function getRemote(name, remotePath, persistence, secure) { michael@0: notImplemented('SharedObject.getRemote'); michael@0: }, michael@0: defaultObjectEncoding: { michael@0: get: function defaultObjectEncoding() { michael@0: return _defaultObjectEncoding; michael@0: }, michael@0: set: function defaultObjectEncoding(version) { michael@0: _defaultObjectEncoding = version; michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: setDirty: function setDirty(propertyName) { michael@0: somewhatImplemented('SharedObject.setDirty'); michael@0: }, michael@0: invoke: function invoke(index) { michael@0: return invokeWithArgsArray.call(this, index, Array.prototype.slice.call(arguments, 1)); michael@0: }, michael@0: invokeWithArgsArray: function invokeWithArgsArray(index, args) { michael@0: return invokeWithArgsArray.call(this, index, args); michael@0: }, michael@0: data: { michael@0: get: function data() { michael@0: return this._data; michael@0: } michael@0: }, michael@0: objectEncoding: { michael@0: get: function objectEncoding() { michael@0: return this._objectEncoding; michael@0: }, michael@0: set: function objectEncoding(version) { michael@0: this._objectEncoding = version; michael@0: } michael@0: }, michael@0: client: { michael@0: get: function client() { michael@0: notImplemented('SharedObject.client'); michael@0: return this._client; michael@0: }, michael@0: set: function client(object) { michael@0: notImplemented('SharedObject.client'); michael@0: this._client = object; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SocketDefinition = function () { michael@0: return { michael@0: __class__: 'flash.net.Socket', michael@0: initialize: function () { michael@0: this._connected = false; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: internalGetSecurityErrorMessage: function internalGetSecurityErrorMessage(host, port) { michael@0: somewhatImplemented('Socket.internalGetSecurityErrorMessage'); michael@0: return 'SecurityErrorEvent'; michael@0: }, michael@0: internalConnect: function internalConnect(host, port) { michael@0: somewhatImplemented('Socket.internalConnect'); michael@0: throwError('SecurityError', Errors.SocketConnectError, host, port); michael@0: }, michael@0: didFailureOccur: function didFailureOccur() { michael@0: somewhatImplemented('Socket.didFailureOccur'); michael@0: return true; michael@0: }, michael@0: readBytes: function readBytes(bytes, offset, length) { michael@0: notImplemented('Socket.readBytes'); michael@0: }, michael@0: writeBytes: function writeBytes(bytes, offset, length) { michael@0: notImplemented('Socket.writeBytes'); michael@0: }, michael@0: writeBoolean: function writeBoolean(value) { michael@0: notImplemented('Socket.writeBoolean'); michael@0: }, michael@0: writeByte: function writeByte(value) { michael@0: notImplemented('Socket.writeByte'); michael@0: }, michael@0: writeShort: function writeShort(value) { michael@0: notImplemented('Socket.writeShort'); michael@0: }, michael@0: writeInt: function writeInt(value) { michael@0: notImplemented('Socket.writeInt'); michael@0: }, michael@0: writeUnsignedInt: function writeUnsignedInt(value) { michael@0: notImplemented('Socket.writeUnsignedInt'); michael@0: }, michael@0: writeFloat: function writeFloat(value) { michael@0: notImplemented('Socket.writeFloat'); michael@0: }, michael@0: writeDouble: function writeDouble(value) { michael@0: notImplemented('Socket.writeDouble'); michael@0: }, michael@0: writeMultiByte: function writeMultiByte(value, charSet) { michael@0: notImplemented('Socket.writeMultiByte'); michael@0: }, michael@0: writeUTF: function writeUTF(value) { michael@0: notImplemented('Socket.writeUTF'); michael@0: }, michael@0: writeUTFBytes: function writeUTFBytes(value) { michael@0: notImplemented('Socket.writeUTFBytes'); michael@0: }, michael@0: readBoolean: function readBoolean() { michael@0: notImplemented('Socket.readBoolean'); michael@0: }, michael@0: readByte: function readByte() { michael@0: notImplemented('Socket.readByte'); michael@0: }, michael@0: readUnsignedByte: function readUnsignedByte() { michael@0: notImplemented('Socket.readUnsignedByte'); michael@0: }, michael@0: readShort: function readShort() { michael@0: notImplemented('Socket.readShort'); michael@0: }, michael@0: readUnsignedShort: function readUnsignedShort() { michael@0: notImplemented('Socket.readUnsignedShort'); michael@0: }, michael@0: readInt: function readInt() { michael@0: notImplemented('Socket.readInt'); michael@0: }, michael@0: readUnsignedInt: function readUnsignedInt() { michael@0: notImplemented('Socket.readUnsignedInt'); michael@0: }, michael@0: readFloat: function readFloat() { michael@0: notImplemented('Socket.readFloat'); michael@0: }, michael@0: readDouble: function readDouble() { michael@0: notImplemented('Socket.readDouble'); michael@0: }, michael@0: readMultiByte: function readMultiByte(length, charSet) { michael@0: notImplemented('Socket.readMultiByte'); michael@0: }, michael@0: readUTF: function readUTF() { michael@0: notImplemented('Socket.readUTF'); michael@0: }, michael@0: readUTFBytes: function readUTFBytes(length) { michael@0: notImplemented('Socket.readUTFBytes'); michael@0: }, michael@0: internalClose: function internalClose() { michael@0: notImplemented('Socket.internalClose'); michael@0: }, michael@0: flush: function flush() { michael@0: notImplemented('Socket.flush'); michael@0: }, michael@0: writeObject: function writeObject(object) { michael@0: notImplemented('Socket.writeObject'); michael@0: }, michael@0: readObject: function readObject() { michael@0: notImplemented('Socket.readObject'); michael@0: }, michael@0: bytesAvailable: { michael@0: get: function bytesAvailable() { michael@0: notImplemented('Socket.bytesAvailable'); michael@0: return this._bytesAvailable; michael@0: } michael@0: }, michael@0: connected: { michael@0: get: function connected() { michael@0: somewhatImplemented('Socket.connected'); michael@0: return this._connected; michael@0: } michael@0: }, michael@0: objectEncoding: { michael@0: get: function objectEncoding() { michael@0: notImplemented('Socket.objectEncoding'); michael@0: return this._objectEncoding; michael@0: }, michael@0: set: function objectEncoding(version) { michael@0: notImplemented('Socket.objectEncoding'); michael@0: this._objectEncoding = version; michael@0: } michael@0: }, michael@0: endian: { michael@0: get: function endian() { michael@0: notImplemented('Socket.endian'); michael@0: return this._endian; michael@0: }, michael@0: set: function endian(type) { michael@0: notImplemented('Socket.endian'); michael@0: this._endian = type; michael@0: } michael@0: }, michael@0: bytesPending: { michael@0: get: function bytesPending() { michael@0: notImplemented('Socket.bytesPending'); michael@0: return this._bytesPending; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var URLLoaderDefinition = function () { michael@0: return { michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: {} michael@0: }, michael@0: script: { michael@0: static: {}, michael@0: instance: { michael@0: data: 'public data', michael@0: dataFormat: 'public dataFormat', michael@0: bytesTotal: 'public bytesTotal', michael@0: bytesLoaded: 'public bytesLoaded', michael@0: load: 'public load' michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var URLRequestDefinition = function () { michael@0: function toFileLoadingServiceRequest() { michael@0: var obj = {}; michael@0: obj.url = this._url; michael@0: obj.method = this._method; michael@0: obj.checkPolicyFile = this._checkPolicyFile; michael@0: if (this._data) { michael@0: obj.mimeType = this._contentType; michael@0: var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray'); michael@0: if (ByteArrayClass.isInstanceOf(this._data)) { michael@0: obj.data = new Uint8Array(this._data.a, 0, this._data.length); michael@0: } else { michael@0: var data = this._data.asGetPublicProperty('toString').call(this._data); michael@0: if (this._method === 'GET') { michael@0: var i = obj.url.lastIndexOf('?'); michael@0: obj.url = (i < 0 ? obj.url : obj.url.substring(0, i)) + '?' + data; michael@0: } else { michael@0: obj.data = data; michael@0: } michael@0: } michael@0: } michael@0: return obj; michael@0: } michael@0: var def = { michael@0: initialize: function () { michael@0: this._url = null; michael@0: this._method = 'GET'; michael@0: this._data = null; michael@0: this._digest = null; michael@0: this._contentType = 'application/x-www-form-urlencoded'; michael@0: this._requestHeaders = null; michael@0: this._checkPolicyFile = true; michael@0: this._toFileRequest = toFileLoadingServiceRequest; michael@0: }, michael@0: setMethod: function (val) { michael@0: this._method = val; michael@0: }, michael@0: setRequestHeaders: function (val) { michael@0: this._requestHeaders = val; michael@0: }, michael@0: get contentType() { michael@0: return this._contentType; michael@0: }, michael@0: set contentType(val) { michael@0: this._contentType = val; michael@0: }, michael@0: get data() { michael@0: return this._data; michael@0: }, michael@0: set data(val) { michael@0: this._data = val; michael@0: }, michael@0: get digest() { michael@0: return this._digest; michael@0: }, michael@0: set digest(val) { michael@0: this._digest = val; michael@0: }, michael@0: get method() { michael@0: return this._method; michael@0: }, michael@0: set method(method) { michael@0: this._method = method; michael@0: }, michael@0: get requestHeaders() { michael@0: return this._requestHeaders; michael@0: }, michael@0: set requestHeaders(requestHeaders) { michael@0: this._requestHeaders = requestHeaders; michael@0: }, michael@0: get url() { michael@0: return this._url; michael@0: }, michael@0: set url(val) { michael@0: this._url = val; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: setMethod: def.setMethod, michael@0: setRequestHeaders: def.setRequestHeaders, michael@0: contentType: desc(def, 'contentType'), michael@0: data: desc(def, 'data'), michael@0: digest: desc(def, 'digest'), michael@0: method: desc(def, 'method'), michael@0: requestHeaders: desc(def, 'requestHeaders'), michael@0: url: desc(def, 'url') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var URLStreamDefinition = function () { michael@0: var def = { michael@0: initialize: function () { michael@0: this._stream = null; michael@0: this._connected = false; michael@0: this._littleEndian = false; michael@0: }, michael@0: close: function close() { michael@0: this._session.close(); michael@0: }, michael@0: load: function load(request) { michael@0: var session = FileLoadingService.createSession(); michael@0: var self = this; michael@0: var initStream = true; michael@0: session.onprogress = function (data, progressState) { michael@0: if (initStream) { michael@0: initStream = false; michael@0: var length = Math.max(progressState.bytesTotal, data.length); michael@0: var buffer = new ArrayBuffer(length); michael@0: self._stream = new Stream(buffer, 0, 0, length); michael@0: } else if (self._stream.end + data.length > self._stream.bytes.length) { michael@0: var length = self._stream.end + data.length; michael@0: var buffer = new ArrayBuffer(length); michael@0: var newStream = new Stream(buffer, 0, 0, length); michael@0: newStream.push(self._stream.bytes.subarray(0, self._stream.end)); michael@0: self._stream = newStream; michael@0: } michael@0: self._stream.push(data); michael@0: var ProgressEventClass = avm2.systemDomain.getClass('flash.events.ProgressEvent'); michael@0: self._dispatchEvent(ProgressEventClass.createInstance([ michael@0: 'progress', michael@0: false, michael@0: false, michael@0: progressState.bytesLoaded, michael@0: progressState.bytesTotal michael@0: ])); michael@0: }; michael@0: session.onerror = function (error) { michael@0: self._connected = false; michael@0: if (!self._stream) { michael@0: self._stream = new Stream(new ArrayBuffer(0), 0, 0, 0); michael@0: } michael@0: self._dispatchEvent(new flash.events.IOErrorEvent(flash.events.IOErrorEvent.class.IO_ERROR, false, false, error)); michael@0: }; michael@0: session.onopen = function () { michael@0: self._connected = true; michael@0: self._dispatchEvent(new flash.events.Event('open', false, false)); michael@0: }; michael@0: session.onhttpstatus = function (location, httpStatus, httpHeaders) { michael@0: var HTTPStatusEventClass = avm2.systemDomain.getClass('flash.events.HTTPStatusEvent'); michael@0: var URLRequestHeaderClass = avm2.systemDomain.getClass('flash.net.URLRequestHeader'); michael@0: var httpStatusEvent = HTTPStatusEventClass.createInstance([ michael@0: 'httpStatus', michael@0: false, michael@0: false, michael@0: httpStatus michael@0: ]); michael@0: var headers = []; michael@0: httpHeaders.split(/(?:\n|\r?\n)/g).forEach(function (h) { michael@0: var m = /^([^:]+): (.*)$/.exec(h); michael@0: if (m) { michael@0: headers.push(URLRequestHeaderClass.createInstance([ michael@0: m[1], michael@0: m[2] michael@0: ])); michael@0: if (m[1] === 'Location') { michael@0: location = m[2]; michael@0: } michael@0: } michael@0: }); michael@0: httpStatusEvent.asSetPublicProperty('responseHeaders', headers); michael@0: httpStatusEvent.asSetPublicProperty('responseURL', location); michael@0: self._dispatchEvent(httpStatusEvent); michael@0: }; michael@0: session.onclose = function () { michael@0: self._connected = false; michael@0: if (!self._stream) { michael@0: self._stream = new Stream(new ArrayBuffer(0), 0, 0, 0); michael@0: } michael@0: self._dispatchEvent(new flash.events.Event('complete', false, false)); michael@0: }; michael@0: session.open(request._toFileRequest()); michael@0: this._session = session; michael@0: }, michael@0: readBoolean: function readBoolean() { michael@0: notImplemented('URLStream.readBoolean'); michael@0: }, michael@0: readByte: function readByte() { michael@0: var stream = this._stream; michael@0: stream.ensure(1); michael@0: return stream.bytes[stream.pos++]; michael@0: }, michael@0: readBytes: function readBytes(bytes, offset, length) { michael@0: if (length < 0) michael@0: throw 'Invalid length argument'; michael@0: var stream = this._stream; michael@0: if (!length) michael@0: length = stream.remaining(); michael@0: else michael@0: stream.ensure(length); michael@0: bytes.writeRawBytes(stream.bytes.subarray(stream.pos, stream.pos + length), offset, length); michael@0: stream.pos += length; michael@0: }, michael@0: readDouble: function readDouble() { michael@0: notImplemented('URLStream.readDouble'); michael@0: }, michael@0: readFloat: function readFloat() { michael@0: notImplemented('URLStream.readFloat'); michael@0: }, michael@0: readInt: function readInt() { michael@0: notImplemented('URLStream.readInt'); michael@0: }, michael@0: readMultiByte: function readMultiByte(length, charSet) { michael@0: notImplemented('URLStream.readMultiByte'); michael@0: }, michael@0: readObject: function readObject() { michael@0: notImplemented('URLStream.readObject'); michael@0: }, michael@0: readShort: function readShort() { michael@0: notImplemented('URLStream.readShort'); michael@0: }, michael@0: readUTF: function readUTF() { michael@0: return this.readUTFBytes(this.readUnsignedShort()); michael@0: }, michael@0: readUTFBytes: function readUTFBytes(length) { michael@0: if (length < 0) michael@0: throw 'Invalid length argument'; michael@0: var stream = this._stream; michael@0: stream.ensure(length); michael@0: var str = utf8encode(stream.bytes.subarray(stream.pos, stream.pos + length)); michael@0: stream.pos += length; michael@0: return str; michael@0: }, michael@0: readUnsignedByte: function readUnsignedByte() { michael@0: notImplemented('URLStream.readUnsignedByte'); michael@0: }, michael@0: readUnsignedInt: function readUnsignedInt() { michael@0: notImplemented('URLStream.readUnsignedInt'); michael@0: }, michael@0: readUnsignedShort: function readUnsignedShort() { michael@0: var stream = this._stream; michael@0: stream.ensure(2); michael@0: var result = stream.getUint16(stream.pos, this._littleEndian); michael@0: stream.pos += 2; michael@0: return result; michael@0: }, michael@0: get bytesAvailable() { michael@0: return this._stream.remaining(); michael@0: }, michael@0: get connected() { michael@0: return this._connected; michael@0: }, michael@0: get endian() { michael@0: return this._littleEndian ? 'littleEndian' : 'bigEndian'; michael@0: }, michael@0: set endian(val) { michael@0: this._littleEndian = val == 'littleEndian'; michael@0: }, michael@0: get objectEncoding() { michael@0: notImplemented('URLStream.objectEncoding'); michael@0: }, michael@0: set objectEncoding(val) { michael@0: notImplemented('URLStream.objectEncoding'); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: close: def.close, michael@0: load: def.load, michael@0: readBoolean: def.readBoolean, michael@0: readByte: def.readByte, michael@0: readBytes: def.readBytes, michael@0: readDouble: def.readDouble, michael@0: readFloat: def.readFloat, michael@0: readInt: def.readInt, michael@0: readMultiByte: def.readMultiByte, michael@0: readObject: def.readObject, michael@0: readShort: def.readShort, michael@0: readUTF: def.readUTF, michael@0: readUTFBytes: def.readUTFBytes, michael@0: readUnsignedByte: def.readUnsignedByte, michael@0: readUnsignedInt: def.readUnsignedInt, michael@0: readUnsignedShort: def.readUnsignedShort, michael@0: bytesAvailable: desc(def, 'bytesAvailable'), michael@0: connected: desc(def, 'connected'), michael@0: endian: desc(def, 'endian'), michael@0: objectEncoding: desc(def, 'objectEncoding') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: { michael@0: var ApplicationDomainDefinition = function () { michael@0: return { michael@0: __class__: 'flash.system.ApplicationDomain', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: currentDomain: { michael@0: get: function currentDomain() { michael@0: return new flash.system.ApplicationDomain(AVM2.currentDomain()); michael@0: } michael@0: }, michael@0: MIN_DOMAIN_MEMORY_LENGTH: { michael@0: get: function MIN_DOMAIN_MEMORY_LENGTH() { michael@0: notImplemented('ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH'); michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: ctor: function ctor(parentDomainOrNativeObject) { michael@0: if (parentDomainOrNativeObject instanceof ApplicationDomain) { michael@0: this.nativeObject = parentDomainOrNativeObject; michael@0: return; michael@0: } michael@0: var parentNativeObject = parentDomainOrNativeObject ? parentDomainOrNativeObject.nativeObject : AVM2.currentDomain().system; michael@0: this.nativeObject = new ApplicationDomain(parentNativeObject.vm, parentNativeObject); michael@0: }, michael@0: getDefinition: function getDefinition(name) { michael@0: var simpleName = name.replace('::', '.'); michael@0: return this.nativeObject.getProperty(Multiname.fromSimpleName(simpleName), true, true); michael@0: }, michael@0: hasDefinition: function hasDefinition(name) { michael@0: if (name === undefined) { michael@0: return false; michael@0: } michael@0: var simpleName = name.replace('::', '.'); michael@0: return !(!this.nativeObject.findDomainProperty(Multiname.fromSimpleName(simpleName), false, false)); michael@0: }, michael@0: getQualifiedDefinitionNames: function getQualifiedDefinitionNames() { michael@0: notImplemented('ApplicationDomain.getQualifiedDefinitionNames'); michael@0: }, michael@0: parentDomain: { michael@0: get: function parentDomain() { michael@0: var base = this.nativeObject.base; michael@0: if (!base) { michael@0: return undefined; michael@0: } michael@0: return new flash.system.ApplicationDomain(base); michael@0: } michael@0: }, michael@0: domainMemory: { michael@0: get: function domainMemory() { michael@0: notImplemented('ApplicationDomain.domainMemory'); michael@0: return this._domainMemory; michael@0: }, michael@0: set: function domainMemory(mem) { michael@0: notImplemented('ApplicationDomain.domainMemory'); michael@0: this._domainMemory = mem; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: Glue.ALL, michael@0: instance: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var CapabilitiesDefinition = function () { michael@0: var def = {}; michael@0: var os; michael@0: var userAgent = window.navigator.userAgent; michael@0: if (userAgent.indexOf('Macintosh') > 0) { michael@0: os = 'Mac OS 10.5.2'; michael@0: } else if (userAgent.indexOf('Windows') > 0) { michael@0: os = 'Windows XP'; michael@0: } else if (userAgent.indexOf('Linux') > 0) { michael@0: os = 'Linux'; michael@0: } else if (/(iPad|iPhone|iPod|Android)/.test(userAgent)) { michael@0: os = 'iPhone3,1'; michael@0: } else { michael@0: notImplemented(); michael@0: } michael@0: def.__glue__ = { michael@0: native: { michael@0: static: { michael@0: version: { michael@0: get: function version() { michael@0: return 'SHUMWAY 10,0,0,0'; michael@0: }, michael@0: enumerable: true michael@0: }, michael@0: os: { michael@0: get: function () { michael@0: return os; michael@0: }, michael@0: enumerable: true michael@0: }, michael@0: serverString: { michael@0: get: function () { michael@0: var str = toKeyValueArray({ michael@0: OS: os michael@0: }).map(function (pair) { michael@0: return pair[0] + '=' + encodeURIComponent(pair[1]); michael@0: }).join('&'); michael@0: somewhatImplemented('Capabilities.serverString: ' + str); michael@0: return str; michael@0: } michael@0: }, michael@0: hasAccessibility: { michael@0: get: function hasAccessibility() { michael@0: somewhatImplemented('Capabilities.hasAccessibility'); michael@0: return false; michael@0: } michael@0: }, michael@0: isDebugger: { michael@0: get: function isDebugger() { michael@0: return false; michael@0: } michael@0: }, michael@0: screenResolutionX: { michael@0: get: function screenResolutionX() { michael@0: return window.screen.width; michael@0: } michael@0: }, michael@0: screenResolutionY: { michael@0: get: function screenResolutionY() { michael@0: return window.screen.height; michael@0: } michael@0: }, michael@0: manufacturer: { michael@0: get: function manufacturer() { michael@0: somewhatImplemented('Capabilities.manufacturer'); michael@0: return 'Mozilla Research'; michael@0: } michael@0: }, michael@0: language: { michael@0: get: function language() { michael@0: somewhatImplemented('Capabilities.language'); michael@0: return 'en'; michael@0: } michael@0: }, michael@0: playerType: { michael@0: get: function playerType() { michael@0: somewhatImplemented('Capabilities.playerType'); michael@0: return 'PlugIn'; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: scriptProperties('public', [ michael@0: 'version', michael@0: 'os' michael@0: ]) michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var FSCommandDefinition = function () { michael@0: var def = {}; michael@0: function fscommand(command, parameters) { michael@0: console.log('FSCommand: ' + command + '; ' + parameters); michael@0: switch (command.toLowerCase()) { michael@0: case 'quit': michael@0: renderingTerminated = true; michael@0: return; michael@0: case 'debugger': michael@0: debugger; michael@0: return; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: def.__glue__ = { michael@0: native: { michael@0: static: { michael@0: _fscommand: fscommand michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var SecurityDefinition = function () { michael@0: var _exactSettings; michael@0: return { michael@0: __class__: 'flash.system.Security', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: allowDomain: function allowDomain() { michael@0: somewhatImplemented('Security.allowDomain ["' + Array.prototype.join.call(arguments, '", "') + '"]'); michael@0: }, michael@0: allowInsecureDomain: function allowInsecureDomain() { michael@0: somewhatImplemented('Security.allowInsecureDomain'); michael@0: }, michael@0: loadPolicyFile: function loadPolicyFile(url) { michael@0: somewhatImplemented('Security.loadPolicyFile'); michael@0: }, michael@0: duplicateSandboxBridgeInputArguments: function duplicateSandboxBridgeInputArguments(toplevel, args) { michael@0: notImplemented('Security.duplicateSandboxBridgeInputArguments'); michael@0: }, michael@0: duplicateSandboxBridgeOutputArgument: function duplicateSandboxBridgeOutputArgument(toplevel, arg) { michael@0: notImplemented('Security.duplicateSandboxBridgeOutputArgument'); michael@0: }, michael@0: showSettings: function showSettings(panel) { michael@0: notImplemented('Security.showSettings'); michael@0: }, michael@0: exactSettings: { michael@0: get: function () { michael@0: return _exactSettings; michael@0: }, michael@0: set: function (value) { michael@0: _exactSettings = value; michael@0: } michael@0: }, michael@0: disableAVM1Loading: { michael@0: get: function disableAVM1Loading() { michael@0: notImplemented('Security.disableAVM1Loading'); michael@0: }, michael@0: set: function disableAVM1Loading(value) { michael@0: notImplemented('Security.disableAVM1Loading'); michael@0: } michael@0: }, michael@0: sandboxType: { michael@0: get: function () { michael@0: somewhatImplemented('Security.sandboxType'); michael@0: return 'remote'; michael@0: } michael@0: }, michael@0: pageDomain: { michael@0: get: function pageDomain() { michael@0: somewhatImplemented('Security.pageDomain'); michael@0: var pageHost = FileLoadingService.resolveUrl('/'); michael@0: var parts = pageHost.split('/'); michael@0: parts.pop(); michael@0: return parts.pop(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SecurityDomainDefinition = function () { michael@0: return { michael@0: __class__: 'flash.system.SecurityDomain', michael@0: initialize: function () { michael@0: }, michael@0: _currentDomain: null, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: currentDomain: { michael@0: get: function () { michael@0: return this._currentDomain; michael@0: } michael@0: } michael@0: }, michael@0: instance: { michael@0: ctor_impl: function ctor_impl() { michael@0: notImplemented('SecurityDomain.ctor_impl'); michael@0: }, michael@0: domainID: { michael@0: get: function domainID() { michael@0: notImplemented('SecurityDomain.domainID'); michael@0: return this._domainID; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SystemDefinition = function () { michael@0: return { michael@0: __class__: 'flash.system.System', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: setClipboard: function setClipboard(string) { michael@0: FirefoxCom.request('setClipboard', string); michael@0: TelemetryService.reportTelemetry({ michael@0: topic: 'feature', michael@0: feature: CLIPBOARD_FEATURE michael@0: }); michael@0: }, michael@0: pause: function pause() { michael@0: somewhatImplemented('System.pause'); michael@0: }, michael@0: resume: function resume() { michael@0: somewhatImplemented('System.resume'); michael@0: }, michael@0: exit: function exit(code) { michael@0: somewhatImplemented('System.exit'); michael@0: renderingTerminated = true; michael@0: }, michael@0: gc: function gc() { michael@0: somewhatImplemented('System.gc'); michael@0: }, michael@0: pauseForGCIfCollectionImminent: function pauseForGCIfCollectionImminent(imminence) { michael@0: notImplemented('System.pauseForGCIfCollectionImminent'); michael@0: }, michael@0: disposeXML: function disposeXML(node) { michael@0: notImplemented('System.disposeXML'); michael@0: }, michael@0: ime: { michael@0: get: function ime() { michael@0: notImplemented('System.ime'); michael@0: } michael@0: }, michael@0: totalMemoryNumber: { michael@0: get: function totalMemoryNumber() { michael@0: if (performance.memory) { michael@0: return performance.memory.usedJSHeapSize; michael@0: } michael@0: return 0; michael@0: } michael@0: }, michael@0: freeMemory: { michael@0: get: function freeMemory() { michael@0: notImplemented('System.freeMemory'); michael@0: } michael@0: }, michael@0: privateMemory: { michael@0: get: function privateMemory() { michael@0: return 0; michael@0: } michael@0: }, michael@0: processCPUUsage: { michael@0: get: function processCPUUsage() { michael@0: notImplemented('System.processCPUUsage'); michael@0: } michael@0: }, michael@0: useCodePage: { michael@0: get: function useCodePage() { michael@0: somewhatImplemented('System.useCodePage'); michael@0: return false; michael@0: }, michael@0: set: function useCodePage(value) { michael@0: notImplemented('System.useCodePage'); michael@0: } michael@0: }, michael@0: vmVersion: { michael@0: get: function vmVersion() { michael@0: somewhatImplemented('System.vmVersion'); michael@0: return '1.0 shumway'; michael@0: } michael@0: }, michael@0: swfVersion: { michael@0: get: function () { michael@0: return 19; michael@0: } michael@0: }, michael@0: apiVersion: { michael@0: get: function () { michael@0: return 26; michael@0: } michael@0: }, michael@0: getArgv: function () { michael@0: return []; michael@0: }, michael@0: getRunmode: function () { michael@0: return 'mixed'; michael@0: } michael@0: }, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var FontDefinition = function () { michael@0: var fonts = []; michael@0: var fontsByUniqueName = Object.create(null); michael@0: var fontsByNameStyleType = Object.create(null); michael@0: var _deviceFontMetrics; michael@0: var def = { michael@0: __class__: 'flash.text.Font', michael@0: initialize: function () { michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this._fontName = s.name || null; michael@0: this._uniqueName = s.uniqueName; michael@0: if (s.bold) { michael@0: if (s.italic) { michael@0: this._fontStyle = 'boldItalic'; michael@0: } else { michael@0: this._fontStyle = 'bold'; michael@0: } michael@0: } else if (s.italic) { michael@0: this._fontStyle = 'italic'; michael@0: } else { michael@0: this._fontStyle = 'regular'; michael@0: } michael@0: var metrics = s.metrics; michael@0: metrics.height = metrics.ascent + metrics.descent + metrics.leading; michael@0: this._metrics = metrics; michael@0: this._fontType = 'embedded'; michael@0: fonts.push(this); michael@0: fontsByUniqueName[this._uniqueName] = this; michael@0: var ident = this._fontName.toLowerCase() + '_' + this._fontStyle + '_embedded'; michael@0: fontsByNameStyleType[ident] = this; michael@0: } michael@0: }, michael@0: get fontName() { michael@0: return this._fontName; michael@0: }, michael@0: get fontStyle() { michael@0: return this._fontStyle; michael@0: }, michael@0: get fontType() { michael@0: return this._fontType; michael@0: }, michael@0: hasGlyphs: function hasGlyphs(str) { michael@0: return true; michael@0: }, michael@0: getFont: function (name, style, embedded) { michael@0: var ident = name.toLowerCase() + '_' + style + (embedded ? '_embedded' : '_device'); michael@0: var font = fontsByNameStyleType[ident]; michael@0: if (font) { michael@0: return font; michael@0: } michael@0: font = new flash.text.Font(); michael@0: font._fontName = font._uniqueName = name; michael@0: font._fontStyle = style; michael@0: font._fontType = 'device'; michael@0: var metrics = deviceFontMetrics()[name]; michael@0: if (!metrics) { michael@0: metrics = deviceFontMetrics().serif; michael@0: font._fontName = font._uniqueName = 'serif'; michael@0: } michael@0: font._metrics = { michael@0: ascent: metrics[0], michael@0: descent: metrics[1], michael@0: leading: metrics[2] michael@0: }; michael@0: font._metrics.height = metrics[0] + metrics[1] + metrics[2]; michael@0: fontsByNameStyleType[ident] = font; michael@0: return font; michael@0: }, michael@0: getFontByUniqueName: function (name) { michael@0: return fontsByUniqueName[name]; michael@0: } michael@0: }; michael@0: function enumerateFonts(device) { michael@0: return fonts.slice(); michael@0: } michael@0: function registerFont(font) { michael@0: somewhatImplemented('Font.registerFont'); michael@0: } michael@0: function deviceFontMetrics() { michael@0: if (_deviceFontMetrics) { michael@0: return _deviceFontMetrics; michael@0: } michael@0: var userAgent = window.navigator.userAgent; michael@0: if (userAgent.indexOf('Windows') > -1) { michael@0: _deviceFontMetrics = DEVICE_FONT_METRICS_WIN; michael@0: } else if (/(Macintosh|iPad|iPhone|iPod|Android)/.test(userAgent)) { michael@0: _deviceFontMetrics = DEVICE_FONT_METRICS_MAC; michael@0: } else { michael@0: _deviceFontMetrics = DEVICE_FONT_METRICS_LINUX; michael@0: } michael@0: return _deviceFontMetrics; michael@0: } michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: fontName: desc(def, 'fontName'), michael@0: fontStyle: desc(def, 'fontStyle'), michael@0: fontType: desc(def, 'fontType'), michael@0: hasGlyphs: def.hasGlyphs michael@0: }, michael@0: static: { michael@0: enumerateFonts: enumerateFonts, michael@0: registerFont: registerFont michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var DEVICE_FONT_METRICS_WIN = { michael@0: 'serif': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'sans-serif': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'monospace': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'birch std': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'blackoak std': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'chaparral pro': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'chaparral pro light': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'charlemagne std': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cooper std black': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'giddyup std': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'hobo std': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro b': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro el': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro h': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro l': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro m': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pro r': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro b': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro el': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro h': [ michael@0: 1.1667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro l': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro m': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pro r': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'mesquite std': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'minion pro cond': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'minion pro med': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'minion pro smbd': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'myriad arabic': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'nueva std': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nueva std cond': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'ocr a std': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'orator std': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'poplar std': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'prestige elite std': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'rosewood std regular': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'stencil std': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'trajan pro': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n b': [ michael@0: 1.4167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n el': [ michael@0: 1.4167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n h': [ michael@0: 1.4167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n l': [ michael@0: 1.4167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n m': [ michael@0: 1.5, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka gothic pr6n r': [ michael@0: 1.4167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n b': [ michael@0: 1.3333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n el': [ michael@0: 1.3333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n h': [ michael@0: 1.4167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n l': [ michael@0: 1.3333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n m': [ michael@0: 1.3333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kozuka mincho pr6n r': [ michael@0: 1.3333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'letter gothic std': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'minion pro': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'myriad hebrew': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'myriad pro': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'myriad pro cond': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'myriad pro light': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'marlett': [ michael@0: 1, michael@0: 0, michael@0: 0 michael@0: ], michael@0: 'arial': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arabic transparent': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial baltic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial ce': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial cyr': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial greek': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial tur': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'batang': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'batangche': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'gungsuh': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'gungsuhche': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'courier new': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new baltic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new ce': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new cyr': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new greek': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new tur': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'daunpenh': [ michael@0: 0.6667, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'dokchampa': [ michael@0: 1.4167, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'estrangelo edessa': [ michael@0: 0.75, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'euphemia': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'gautami': [ michael@0: 1.1667, michael@0: 0.8333, michael@0: 0 michael@0: ], michael@0: 'vani': [ michael@0: 1.0833, michael@0: 0.75, michael@0: 0 michael@0: ], michael@0: 'gulim': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'gulimche': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'dotum': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'dotumche': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'impact': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'iskoola pota': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kalinga': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'kartika': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'khmer ui': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'lao ui': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'latha': [ michael@0: 1.0833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'lucida console': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'malgun gothic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'mangal': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'meiryo': [ michael@0: 1.0833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'meiryo ui': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'microsoft himalaya': [ michael@0: 0.5833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'microsoft jhenghei': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'microsoft yahei': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'mingliu': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'pmingliu': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'mingliu_hkscs': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'mingliu-extb': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'pmingliu-extb': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'mingliu_hkscs-extb': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'mongolian baiti': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'ms gothic': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'ms pgothic': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'ms ui gothic': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'ms mincho': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'ms pmincho': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'mv boli': [ michael@0: 1.1667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'microsoft new tai lue': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'nyala': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'microsoft phagspa': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'plantagenet cherokee': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'raavi': [ michael@0: 1.0833, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'segoe script': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'segoe ui': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'segoe ui semibold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'segoe ui light': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'segoe ui symbol': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'shruti': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'simsun': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'nsimsun': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'simsun-extb': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'sylfaen': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'microsoft tai le': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'times new roman': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman baltic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman ce': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman cyr': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman greek': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman tur': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'tunga': [ michael@0: 1.0833, michael@0: 0.75, michael@0: 0 michael@0: ], michael@0: 'vrinda': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'shonar bangla': [ michael@0: 0.8333, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'microsoft yi baiti': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'tahoma': [ michael@0: 1, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'microsoft sans serif': [ michael@0: 1.0833, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'angsana new': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'aparajita': [ michael@0: 0.75, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'cordia new': [ michael@0: 0.9167, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'ebrima': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'gisha': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kokila': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'leelawadee': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'microsoft uighur': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'moolboran': [ michael@0: 0.6667, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'symbol': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'utsaah': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'vijaya': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'wingdings': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'andalus': [ michael@0: 1.3333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'arabic typesetting': [ michael@0: 0.8333, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'simplified arabic': [ michael@0: 1.3333, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'simplified arabic fixed': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'sakkal majalla': [ michael@0: 0.9167, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'traditional arabic': [ michael@0: 1.3333, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'aharoni': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'david': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'frankruehl': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'fangsong': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'simhei': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'kaiti': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'browallia new': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'lucida sans unicode': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial black': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'calibri': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cambria': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cambria math': [ michael@0: 3.0833, michael@0: 2.5, michael@0: 0 michael@0: ], michael@0: 'candara': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'comic sans ms': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'consolas': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'constantia': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'corbel': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'franklin gothic medium': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'gabriola': [ michael@0: 1.1667, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'georgia': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'palatino linotype': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'segoe print': [ michael@0: 1.25, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'trebuchet ms': [ michael@0: 1.0833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'verdana': [ michael@0: 1, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'webdings': [ michael@0: 1.0833, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'lucida bright': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'lucida sans': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'lucida sans typewriter': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gentium basic': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu serif condensed': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arimo': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu sans condensed': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu sans': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu sans light': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'opensymbol': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'gentium book basic': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu sans mono': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'dejavu serif': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'calibri light': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ] michael@0: }; michael@0: var DEVICE_FONT_METRICS_MAC = { michael@0: 'al bayan plain': [ michael@0: 1, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'al bayan bold': [ michael@0: 1, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'american typewriter': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'american typewriter bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'american typewriter condensed': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'american typewriter condensed bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'american typewriter condensed light': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'american typewriter light': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'andale mono': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'apple symbols': [ michael@0: 0.6667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial hebrew': [ michael@0: 0.75, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'arial hebrew bold': [ michael@0: 0.75, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'arial': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial narrow': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial narrow bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial narrow bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial narrow italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial rounded mt bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'arial unicode ms': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'avenir black': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir black oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir book': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir book oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir heavy': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir heavy oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir light': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir light oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir medium': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir medium oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir oblique': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir roman': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next bold': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next bold italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next demi bold': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next demi bold italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next heavy': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next heavy italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next medium': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next medium italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next regular': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next ultra light': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next ultra light italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed bold': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed bold italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed demi bold': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed demi bold italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed heavy': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed heavy italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed medium': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed medium italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed regular': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed ultra light': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'avenir next condensed ultra light italic': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'ayuthaya': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'baghdad': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'bangla mn': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'bangla mn bold': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'bangla sangam mn': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'bangla sangam mn bold': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'baskerville': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'baskerville bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'baskerville bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'baskerville italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'baskerville semibold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'baskerville semibold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'big caslon medium': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'brush script mt italic': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'chalkboard': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'chalkboard bold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'chalkboard se bold': [ michael@0: 1.1667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'chalkboard se light': [ michael@0: 1.1667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'chalkboard se regular': [ michael@0: 1.1667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'chalkduster': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'charcoal cy': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cochin': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cochin bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cochin bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'cochin italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'comic sans ms': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'comic sans ms bold': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'copperplate': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'copperplate bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'copperplate light': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'corsiva hebrew': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'corsiva hebrew bold': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'courier': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier bold oblique': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier oblique': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'courier new bold italic': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'courier new bold': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'courier new italic': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'courier new': [ michael@0: 0.8333, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'biaukai': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'damascus': [ michael@0: 0.5833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'damascus bold': [ michael@0: 0.5833, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'decotype naskh': [ michael@0: 1.1667, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'devanagari mt': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'devanagari mt bold': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'devanagari sangam mn': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'devanagari sangam mn bold': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'didot': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'didot bold': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'didot italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'euphemia ucas': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'euphemia ucas bold': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'euphemia ucas italic': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'futura condensed extrabold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'futura condensed medium': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'futura medium': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'futura medium italic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gb18030 bitmap': [ michael@0: 1, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'geeza pro': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'geeza pro bold': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'geneva': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'geneva cy': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'georgia': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'georgia bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'georgia bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'georgia italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans light': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gill sans light italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gujarati mt': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'gujarati mt bold': [ michael@0: 0.9167, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'gujarati sangam mn': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'gujarati sangam mn bold': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'gurmukhi mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gurmukhi mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gurmukhi sangam mn': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'gurmukhi sangam mn bold': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'helvetica': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica bold oblique': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica light': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica light oblique': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica oblique': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue bold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue bold italic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue condensed black': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue condensed bold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue light': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue light italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue medium': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue ultralight': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'helvetica neue ultralight italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'herculanum': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic pro w3': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic pro w6': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic pron w3': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic pron w6': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic std w8': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino kaku gothic stdn w8': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino maru gothic pro w4': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino maru gothic pron w4': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino mincho pro w3': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino mincho pro w6': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino mincho pron w3': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino mincho pron w6': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino sans gb w3': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hiragino sans gb w6': [ michael@0: 0.9167, michael@0: 0.0833, michael@0: 0 michael@0: ], michael@0: 'hoefler text black': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'hoefler text black italic': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'hoefler text italic': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'hoefler text ornaments': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'hoefler text': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'impact': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'inaimathi': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'headlinea regular': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'pilgi regular': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gungseo regular': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'pcmyungjo regular': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kailasa regular': [ michael@0: 1.0833, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'kannada mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kannada mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kannada sangam mn': [ michael@0: 1, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'kannada sangam mn bold': [ michael@0: 1, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'kefa bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kefa regular': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'khmer mn': [ michael@0: 1, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'khmer mn bold': [ michael@0: 1, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'khmer sangam mn': [ michael@0: 1.0833, michael@0: 0.6667, michael@0: 0 michael@0: ], michael@0: 'kokonor regular': [ michael@0: 1.0833, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'krungthep': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'kufistandardgk': [ michael@0: 0.9167, michael@0: 0.5, michael@0: 0 michael@0: ], michael@0: 'lao mn': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'lao mn bold': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'lao sangam mn': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'apple ligothic medium': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'lihei pro': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'lisong pro': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'lucida grande': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'lucida grande bold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'malayalam mn': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'malayalam mn bold': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'malayalam sangam mn': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'malayalam sangam mn bold': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'marion bold': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'marion italic': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'marion regular': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'marker felt thin': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'marker felt wide': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'menlo bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'menlo bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'menlo italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'menlo regular': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'microsoft sans serif': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'monaco': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'gurmukhi mt': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'mshtakan': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'mshtakan bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'mshtakan boldoblique': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'mshtakan oblique': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'myanmar mn': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'myanmar mn bold': [ michael@0: 1, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'myanmar sangam mn': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'nadeem': [ michael@0: 0.9167, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'nanum brush script': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanumgothic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanumgothic bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanumgothic extrabold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanummyeongjo': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanummyeongjo bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanummyeongjo extrabold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'nanum pen script': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'optima bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'optima bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'optima extrablack': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'optima italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'optima regular': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'oriya mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'oriya mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'oriya sangam mn': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'oriya sangam mn bold': [ michael@0: 0.8333, michael@0: 0.4167, michael@0: 0 michael@0: ], michael@0: 'osaka': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'osaka-mono': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'palatino bold': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'palatino bold italic': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'palatino italic': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'palatino': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'papyrus': [ michael@0: 0.9167, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'papyrus condensed': [ michael@0: 0.9167, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'plantagenet cherokee': [ michael@0: 0.6667, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'raanana': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'raanana bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'hei regular': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'kai regular': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'stfangsong': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'stheiti': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'heiti sc light': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'heiti sc medium': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'heiti tc light': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'heiti tc medium': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'stkaiti': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'kaiti sc black': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kaiti sc bold': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'kaiti sc regular': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'stsong': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'songti sc black': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'songti sc bold': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'songti sc light': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'songti sc regular': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'stxihei': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'sathu': [ michael@0: 0.9167, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'silom': [ michael@0: 1, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'sinhala mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'sinhala mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'sinhala sangam mn': [ michael@0: 1.1667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'sinhala sangam mn bold': [ michael@0: 1.1667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'skia regular': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'symbol': [ michael@0: 0.6667, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'tahoma negreta': [ michael@0: 1, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'tamil mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'tamil mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'tamil sangam mn': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'tamil sangam mn bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'telugu mn': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'telugu mn bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'telugu sangam mn': [ michael@0: 1, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'telugu sangam mn bold': [ michael@0: 1, michael@0: 0.5833, michael@0: 0 michael@0: ], michael@0: 'thonburi': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'thonburi bold': [ michael@0: 1.0833, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times bold': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times bold italic': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times italic': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times roman': [ michael@0: 0.75, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'times new roman': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'trebuchet ms bold italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'trebuchet ms': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'trebuchet ms bold': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'trebuchet ms italic': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'verdana': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'verdana bold': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'verdana bold italic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'verdana italic': [ michael@0: 1, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'webdings': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'wingdings 2': [ michael@0: 0.8333, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'wingdings 3': [ michael@0: 0.9167, michael@0: 0.25, michael@0: 0 michael@0: ], michael@0: 'yuppy sc regular': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'yuppy tc regular': [ michael@0: 1.0833, michael@0: 0.3333, michael@0: 0 michael@0: ], michael@0: 'zapf dingbats': [ michael@0: 0.8333, michael@0: 0.1667, michael@0: 0 michael@0: ], michael@0: 'zapfino': [ michael@0: 1.9167, michael@0: 1.5, michael@0: 0 michael@0: ] michael@0: }; michael@0: var DEVICE_FONT_METRICS_LINUX = { michael@0: 'kacstfarsi': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'meera': [ michael@0: 0.682, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'freemono': [ michael@0: 0.8023, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'undotum': [ michael@0: 1.0029, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'loma': [ michael@0: 1.1634, michael@0: 0.4814, michael@0: 0 michael@0: ], michael@0: 'century schoolbook l': [ michael@0: 1.0029, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'kacsttitlel': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'undinaru': [ michael@0: 1.0029, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'ungungseo': [ michael@0: 1.0029, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'garuda': [ michael@0: 1.3238, michael@0: 0.6017, michael@0: 0 michael@0: ], michael@0: 'rekha': [ michael@0: 1.1232, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'purisa': [ michael@0: 1.1232, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'dejavu sans mono': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'vemana2000': [ michael@0: 0.8825, michael@0: 0.8424, michael@0: 0 michael@0: ], michael@0: 'kacstoffice': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'umpush': [ michael@0: 1.2837, michael@0: 0.682, michael@0: 0 michael@0: ], michael@0: 'opensymbol': [ michael@0: 0.8023, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'sawasdee': [ michael@0: 1.1232, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'urw palladio l': [ michael@0: 1.0029, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'freeserif': [ michael@0: 0.9227, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'kacstdigital': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'ubuntu condensed': [ michael@0: 0.9628, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'unpilgi': [ michael@0: 1.0029, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'mry_kacstqurn': [ michael@0: 1.4442, michael@0: 0.7221, michael@0: 0 michael@0: ], michael@0: 'urw gothic l': [ michael@0: 1.0029, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'dingbats': [ michael@0: 0.8424, michael@0: 0.1605, michael@0: 0 michael@0: ], michael@0: 'urw chancery l': [ michael@0: 1.0029, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'phetsarath ot': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'tlwg typist': [ michael@0: 0.8825, michael@0: 0.4012, michael@0: 0 michael@0: ], michael@0: 'kacstletter': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'utkal': [ michael@0: 1.2035, michael@0: 0.6418, michael@0: 0 michael@0: ], michael@0: 'dejavu sans light': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'norasi': [ michael@0: 1.2436, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'dejavu serif condensed': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'kacstone': [ michael@0: 1.2436, michael@0: 0.6418, michael@0: 0 michael@0: ], michael@0: 'liberation sans narrow': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'symbol': [ michael@0: 1.043, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'nanummyeongjo': [ michael@0: 0.9227, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'untitled1': [ michael@0: 0.682, michael@0: 0.5616, michael@0: 0 michael@0: ], michael@0: 'lohit gujarati': [ michael@0: 0.9628, michael@0: 0.4012, michael@0: 0 michael@0: ], michael@0: 'liberation mono': [ michael@0: 0.8424, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'kacstart': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'mallige': [ michael@0: 1.0029, michael@0: 0.682, michael@0: 0 michael@0: ], michael@0: 'bitstream charter': [ michael@0: 1.0029, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'nanumgothic': [ michael@0: 0.9227, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'liberation serif': [ michael@0: 0.9227, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'dejavu sans condensed': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'ubuntu': [ michael@0: 0.9628, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'courier 10 pitch': [ michael@0: 0.8825, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'nimbus sans l': [ michael@0: 0.9628, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'takaopgothic': [ michael@0: 0.8825, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'wenquanyi micro hei mono': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'dejavu sans': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'kedage': [ michael@0: 1.0029, michael@0: 0.682, michael@0: 0 michael@0: ], michael@0: 'kinnari': [ michael@0: 1.3238, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'tlwgmono': [ michael@0: 0.8825, michael@0: 0.4012, michael@0: 0 michael@0: ], michael@0: 'standard symbols l': [ michael@0: 1.043, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'lohit punjabi': [ michael@0: 1.2035, michael@0: 0.682, michael@0: 0 michael@0: ], michael@0: 'nimbus mono l': [ michael@0: 0.8424, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'rachana': [ michael@0: 0.682, michael@0: 0.5616, michael@0: 0 michael@0: ], michael@0: 'waree': [ michael@0: 1.2436, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'kacstposter': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'khmer os': [ michael@0: 1.2837, michael@0: 0.7622, michael@0: 0 michael@0: ], michael@0: 'freesans': [ michael@0: 1.0029, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'gargi': [ michael@0: 0.9628, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'nimbus roman no9 l': [ michael@0: 0.9628, michael@0: 0.3209, michael@0: 0 michael@0: ], michael@0: 'dejavu serif': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'wenquanyi micro hei': [ michael@0: 0.9628, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'ubuntu light': [ michael@0: 0.9628, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'tlwgtypewriter': [ michael@0: 0.9227, michael@0: 0.4012, michael@0: 0 michael@0: ], michael@0: 'kacstpen': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'tlwg typo': [ michael@0: 0.8825, michael@0: 0.4012, michael@0: 0 michael@0: ], michael@0: 'mukti narrow': [ michael@0: 1.2837, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'ubuntu mono': [ michael@0: 0.8424, michael@0: 0.2006, michael@0: 0 michael@0: ], michael@0: 'lohit bengali': [ michael@0: 1.0029, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'liberation sans': [ michael@0: 0.9227, michael@0: 0.2407, michael@0: 0 michael@0: ], michael@0: 'unbatang': [ michael@0: 1.0029, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'kacstdecorative': [ michael@0: 1.1232, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'khmer os system': [ michael@0: 1.2436, michael@0: 0.6017, michael@0: 0 michael@0: ], michael@0: 'saab': [ michael@0: 1.0029, michael@0: 0.682, michael@0: 0 michael@0: ], michael@0: 'kacsttitle': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'mukti narrow bold': [ michael@0: 1.2837, michael@0: 0.4413, michael@0: 0 michael@0: ], michael@0: 'lohit hindi': [ michael@0: 1.0029, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'kacstqurn': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'urw bookman l': [ michael@0: 0.9628, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'kacstnaskh': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'kacstscreen': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ], michael@0: 'pothana2000': [ michael@0: 0.8825, michael@0: 0.8424, michael@0: 0 michael@0: ], michael@0: 'ungraphic': [ michael@0: 1.0029, michael@0: 0.2808, michael@0: 0 michael@0: ], michael@0: 'lohit tamil': [ michael@0: 0.8825, michael@0: 0.361, michael@0: 0 michael@0: ], michael@0: 'kacstbook': [ michael@0: 1.0831, michael@0: 0.5215, michael@0: 0 michael@0: ] michael@0: }; michael@0: DEVICE_FONT_METRICS_MAC.__proto__ = DEVICE_FONT_METRICS_WIN; michael@0: DEVICE_FONT_METRICS_LINUX.__proto__ = DEVICE_FONT_METRICS_MAC; michael@0: } michael@0: var StaticTextDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.text.StaticText', michael@0: initialize: function () { michael@0: var s = this.symbol; michael@0: if (s) { michael@0: this.draw = s.draw; michael@0: } michael@0: }, michael@0: get text() { michael@0: return this._text; michael@0: }, michael@0: set text(val) { michael@0: this._text = val; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: text: desc(def, 'text') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var StyleSheetDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.StyleSheet', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: _update: function _update() { michael@0: somewhatImplemented('StyleSheet._update'); michael@0: }, michael@0: _parseCSSInternal: function _parseCSSInternal(cssText) { michael@0: somewhatImplemented('StyleSheet._parseCSSInternal'); michael@0: return null; michael@0: }, michael@0: _parseCSSFontFamily: function _parseCSSFontFamily(fontFamily) { michael@0: notImplemented('StyleSheet._parseCSSFontFamily'); michael@0: }, michael@0: _parseColor: function _parseColor(color) { michael@0: notImplemented('StyleSheet._parseColor'); michael@0: }, michael@0: _styles: { michael@0: get: function _styles() { michael@0: return this.__styles; michael@0: }, michael@0: set: function _styles(styles) { michael@0: somewhatImplemented('StyleSheet._styles'); michael@0: this.__styles = styles; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextFieldDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.text.TextField', michael@0: initialize: function () { michael@0: this._bbox = { michael@0: xMin: 0, michael@0: yMin: 0, michael@0: xMax: 2000, michael@0: yMax: 2000 michael@0: }; michael@0: var initialFormat = { michael@0: align: 'LEFT', michael@0: face: 'serif', michael@0: size: 12, michael@0: letterspacing: 0, michael@0: kerning: 0, michael@0: color: 0, michael@0: leading: 0 michael@0: }; michael@0: this._content = new TextFieldContent(initialFormat); michael@0: this._type = 'dynamic'; michael@0: this._embedFonts = false; michael@0: this._selectable = true; michael@0: this._autoSize = 'none'; michael@0: this._scrollV = 1; michael@0: this._maxScrollV = 1; michael@0: this._bottomScrollV = 1; michael@0: this._drawingOffsetH = 0; michael@0: this._background = false; michael@0: this._border = false; michael@0: this._backgroundColor = 16777215; michael@0: this._backgroundColorStr = '#ffffff'; michael@0: this._borderColor = 0; michael@0: this._borderColorStr = '#000000'; michael@0: var s = this.symbol; michael@0: if (!s) { michael@0: this._currentTransform.tx -= 40; michael@0: this._currentTransform.ty -= 40; michael@0: this._content.resolveFont(initialFormat, false); michael@0: this.text = ''; michael@0: return; michael@0: } michael@0: var tag = s.tag; michael@0: var bbox = tag.bbox; michael@0: this._currentTransform.tx += bbox.xMin; michael@0: this._currentTransform.ty += bbox.yMin; michael@0: this._bbox.xMax = bbox.xMax - bbox.xMin; michael@0: this._bbox.yMax = bbox.yMax - bbox.yMin; michael@0: if (tag.hasLayout) { michael@0: initialFormat.size = tag.fontHeight / 20; michael@0: initialFormat.leading = (tag.leading | 0) / 20; michael@0: } michael@0: if (tag.hasColor) { michael@0: initialFormat.color = rgbaObjToStr(tag.color); michael@0: } michael@0: if (tag.hasFont) { michael@0: var font = FontDefinition.getFontByUniqueName(tag.font); michael@0: initialFormat.font = font; michael@0: initialFormat.face = font._fontName; michael@0: initialFormat.bold = font.symbol.bold; michael@0: initialFormat.italic = font.symbol.italic; michael@0: initialFormat.str = this._content.makeFormatString(initialFormat); michael@0: } michael@0: this._content.multiline = !(!tag.multiline); michael@0: this._content.wordWrap = !(!tag.wordWrap); michael@0: this._embedFonts = !(!tag.useOutlines); michael@0: this._selectable = !tag.noSelect; michael@0: this._border = !(!tag.border); michael@0: switch (tag.align) { michael@0: case 1: michael@0: initialFormat.align = 'right'; michael@0: break; michael@0: case 2: michael@0: initialFormat.align = 'center'; michael@0: break; michael@0: case 3: michael@0: initialFormat.align = 'justified'; michael@0: break; michael@0: default: michael@0: } michael@0: if (tag.initialText) { michael@0: if (tag.html) { michael@0: this.htmlText = tag.initialText; michael@0: } else { michael@0: this.text = tag.initialText; michael@0: } michael@0: } else { michael@0: this.text = ''; michael@0: } michael@0: }, michael@0: _getAS2Object: function () { michael@0: if (!this.$as2Object) { michael@0: new avm1lib.AS2TextField(this); michael@0: } michael@0: return this.$as2Object; michael@0: }, michael@0: replaceText: function (begin, end, str) { michael@0: var text = this._content.text; michael@0: this.text = text.substring(0, begin) + str + text.substring(end); michael@0: }, michael@0: draw: function (ctx, ratio, colorTransform) { michael@0: this.ensureDimensions(); michael@0: var bounds = this._bbox; michael@0: var width = bounds.xMax / 20; michael@0: var height = bounds.yMax / 20; michael@0: if (width <= 0 || height <= 0) { michael@0: return; michael@0: } michael@0: ctx.save(); michael@0: ctx.beginPath(); michael@0: ctx.rect(0, 0, width + 1, height + 1); michael@0: ctx.clip(); michael@0: if (this._background) { michael@0: colorTransform.setFillStyle(ctx, this._backgroundColorStr); michael@0: ctx.fill(); michael@0: } michael@0: if (this._border) { michael@0: colorTransform.setStrokeStyle(ctx, this._borderColorStr); michael@0: ctx.lineCap = 'square'; michael@0: ctx.lineWidth = 1; michael@0: ctx.strokeRect(0.5, 0.5, width | 0, height | 0); michael@0: } michael@0: ctx.closePath(); michael@0: if (this._content.lines.length === 0) { michael@0: ctx.restore(); michael@0: return; michael@0: } michael@0: ctx.translate(2, 2); michael@0: ctx.save(); michael@0: colorTransform.setAlpha(ctx); michael@0: var runs = this._content._textRuns; michael@0: var offsetY = this._content.lines[this._scrollV - 1].y; michael@0: for (var i = 0; i < runs.length; i++) { michael@0: var run = runs[i]; michael@0: if (run.type === 'f') { michael@0: ctx.restore(); michael@0: ctx.font = run.format.str; michael@0: colorTransform.setFillStyle(ctx, run.format.color); michael@0: ctx.save(); michael@0: colorTransform.setAlpha(ctx); michael@0: } else { michael@0: if (run.y < offsetY) { michael@0: continue; michael@0: } michael@0: ctx.fillText(run.text, run.x - this._drawingOffsetH, run.y - offsetY); michael@0: } michael@0: } michael@0: ctx.restore(); michael@0: ctx.restore(); michael@0: }, michael@0: invalidateDimensions: function () { michael@0: this._invalidate(); michael@0: this._invalidateBounds(); michael@0: this._dimensionsValid = false; michael@0: }, michael@0: ensureDimensions: function () { michael@0: if (this._dimensionsValid) { michael@0: return; michael@0: } michael@0: var bounds = this._bbox; michael@0: var combinedAlign = this._content.calculateMetrics(bounds, this._embedFonts); michael@0: this._scrollV = 1; michael@0: this._maxScrollV = 1; michael@0: this._bottomScrollV = 1; michael@0: var autoSize = this._autoSize; michael@0: if (autoSize === 'none') { michael@0: var maxVisibleY = (bounds.yMax - 80) / 20; michael@0: if (this._content.textHeight > maxVisibleY) { michael@0: var lines = this._content.lines; michael@0: for (var i = 0; i < lines.length; i++) { michael@0: var line = lines[i]; michael@0: if (line.y + line.height > maxVisibleY) { michael@0: this._maxScrollV = i + 1; michael@0: this._bottomScrollV = i === 0 ? 1 : i; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: var width = Math.max(bounds.xMax / 20 - 4, 1); michael@0: var targetWidth = this._content.textWidth; michael@0: var align = combinedAlign; michael@0: var diffX = 0; michael@0: if (align !== 'mixed') { michael@0: switch (autoSize) { michael@0: case 'left': michael@0: break; michael@0: case 'center': michael@0: diffX = width - targetWidth >> 1; michael@0: break; michael@0: case 'right': michael@0: diffX = width - targetWidth; michael@0: } michael@0: if (align === 'left') { michael@0: this._drawingOffsetH = 0; michael@0: } else { michael@0: var offset; michael@0: switch (autoSize) { michael@0: case 'left': michael@0: offset = width - targetWidth; michael@0: break; michael@0: case 'center': michael@0: offset = diffX << 1; michael@0: break; michael@0: case 'right': michael@0: offset = diffX; michael@0: break; michael@0: } michael@0: if (align === 'center') { michael@0: offset >>= 1; michael@0: } michael@0: this._drawingOffsetH = offset; michael@0: } michael@0: this._invalidateTransform(); michael@0: this._currentTransform.tx += diffX * 20 | 0; michael@0: bounds.xMax = (targetWidth * 20 | 0) + 80; michael@0: } michael@0: bounds.yMax = (this._content.textHeight * 20 | 0) + 80; michael@0: console.log(bounds.yMax); michael@0: this._invalidateBounds(); michael@0: } michael@0: this._dimensionsValid = true; michael@0: }, michael@0: get text() { michael@0: return this._content.text; michael@0: }, michael@0: set text(val) { michael@0: this._content.text = val; michael@0: this.invalidateDimensions(); michael@0: }, michael@0: get htmlText() { michael@0: return this._content.htmlText; michael@0: }, michael@0: set htmlText(val) { michael@0: this._content.htmlText = val; michael@0: this.invalidateDimensions(); michael@0: }, michael@0: get defaultTextFormat() { michael@0: var format = this._content.defaultTextFormat; michael@0: return new flash.text.TextFormat().fromObject(format); michael@0: }, michael@0: set defaultTextFormat(val) { michael@0: this._content.defaultTextFormat = val.toObject(); michael@0: this.invalidateDimensions(); michael@0: }, michael@0: getTextFormat: function (beginIndex, endIndex) { michael@0: return this.defaultTextFormat; michael@0: }, michael@0: setTextFormat: function (format, beginIndex, endIndex) { michael@0: this.defaultTextFormat = format; michael@0: if (this.text === this.htmlText) { michael@0: this.text = this.text; michael@0: } michael@0: this.invalidateDimensions(); michael@0: }, michael@0: get x() { michael@0: this.ensureDimensions(); michael@0: return this._currentTransform.tx; michael@0: }, michael@0: set x(val) { michael@0: if (val === this._currentTransform.tx) { michael@0: return; michael@0: } michael@0: this._invalidate(); michael@0: this._invalidateBounds(); michael@0: this._invalidateTransform(); michael@0: this._currentTransform.tx = val; michael@0: }, michael@0: get width() { michael@0: this.ensureDimensions(); michael@0: return this._bbox.xMax; michael@0: }, michael@0: set width(value) { michael@0: if (value < 0) { michael@0: return; michael@0: } michael@0: this._bbox.xMax = value; michael@0: this.invalidateDimensions(); michael@0: }, michael@0: get height() { michael@0: this.ensureDimensions(); michael@0: return this._bbox.yMax; michael@0: }, michael@0: set height(value) { michael@0: if (value < 0) { michael@0: return; michael@0: } michael@0: this._bbox.yMax = value; michael@0: this._invalidate(); michael@0: }, michael@0: _getContentBounds: function () { michael@0: this.ensureDimensions(); michael@0: return this._bbox; michael@0: }, michael@0: _getRegion: function getRegion(targetCoordSpace) { michael@0: return this._getTransformedRect(this._getContentBounds(), targetCoordSpace); michael@0: }, michael@0: getLineMetrics: function (lineIndex) { michael@0: this.ensureDimensions(); michael@0: if (lineIndex < 0 || lineIndex >= this._content.lines.length) { michael@0: throwError('RangeError', Errors.ParamRangeError); michael@0: } michael@0: var line = this._content.lines[lineIndex]; michael@0: var format = line.largestFormat; michael@0: var metrics = format.font._metrics; michael@0: var size = format.size; michael@0: var ascent = metrics.ascent * size + 0.49999 | 0; michael@0: var descent = metrics.descent * size + 0.49999 | 0; michael@0: var leading = metrics.leading * size + 0.49999 + line.leading | 0; michael@0: return new flash.text.TextLineMetrics(line.x + 2, line.width, line.height, ascent, descent, leading); michael@0: }, michael@0: getCharBoundaries: function getCharBoundaries(index) { michael@0: somewhatImplemented('TextField.getCharBoundaries'); michael@0: return new flash.geom.Rectangle(0, 0, 0, 0); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: text: desc(def, 'text'), michael@0: defaultTextFormat: desc(def, 'defaultTextFormat'), michael@0: draw: def.draw, michael@0: htmlText: desc(def, 'htmlText'), michael@0: replaceText: def.replaceText, michael@0: getTextFormat: def.getTextFormat, michael@0: setTextFormat: def.setTextFormat, michael@0: getCharBoundaries: def.getCharBoundaries, michael@0: autoSize: { michael@0: get: function autoSize() { michael@0: return this._autoSize; michael@0: }, michael@0: set: function autoSize(value) { michael@0: if (this._autoSize === value) { michael@0: return; michael@0: } michael@0: this._autoSize = value; michael@0: this.invalidateDimensions(); michael@0: } michael@0: }, michael@0: multiline: { michael@0: get: function multiline() { michael@0: return this._content.multiline; michael@0: }, michael@0: set: function multiline(value) { michael@0: if (this._content.multiline === value) { michael@0: return; michael@0: } michael@0: this._content.multiline = value; michael@0: this.invalidateDimensions(); michael@0: } michael@0: }, michael@0: textColor: { michael@0: get: function textColor() { michael@0: return this._content.textColor; michael@0: }, michael@0: set: function textColor(value) { michael@0: if (this._content.textColor === value) { michael@0: return; michael@0: } michael@0: this._content.textColor = value; michael@0: this._invalidate(); michael@0: } michael@0: }, michael@0: selectable: { michael@0: get: function selectable() { michael@0: return this._selectable; michael@0: }, michael@0: set: function selectable(value) { michael@0: somewhatImplemented('TextField.selectable'); michael@0: this._selectable = value; michael@0: } michael@0: }, michael@0: wordWrap: { michael@0: get: function wordWrap() { michael@0: return this._content.wordWrap; michael@0: }, michael@0: set: function wordWrap(value) { michael@0: if (this._content.wordWrap === value) { michael@0: return; michael@0: } michael@0: this._content.wordWrap = value; michael@0: this.invalidateDimensions(); michael@0: } michael@0: }, michael@0: textHeight: { michael@0: get: function textHeight() { michael@0: this.ensureDimensions(); michael@0: return this._content.textHeight; michael@0: } michael@0: }, michael@0: textWidth: { michael@0: get: function textWidth() { michael@0: this.ensureDimensions(); michael@0: return this._content.textWidth; michael@0: } michael@0: }, michael@0: length: { michael@0: get: function length() { michael@0: return this.text.length; michael@0: } michael@0: }, michael@0: numLines: { michael@0: get: function numLines() { michael@0: this.ensureDimensions(); michael@0: return this._content.lines.length; michael@0: } michael@0: }, michael@0: getLineMetrics: function (lineIndex) { michael@0: return this.getLineMetrics(lineIndex); michael@0: }, michael@0: setSelection: function (beginIndex, endIndex) { michael@0: somewhatImplemented('TextField.setSelection'); michael@0: }, michael@0: scrollV: { michael@0: get: function scrollV() { michael@0: return this._scrollV; michael@0: }, michael@0: set: function scrollV(value) { michael@0: this.ensureDimensions(); michael@0: value = Math.max(1, Math.min(this._maxScrollV, value)); michael@0: this._scrollV = value; michael@0: } michael@0: }, michael@0: bottomScrollV: { michael@0: get: function bottomScrollV() { michael@0: this.ensureDimensions(); michael@0: if (this._scrollV === 1) { michael@0: return this._bottomScrollV; michael@0: } michael@0: var maxVisibleY = (this._bbox.yMax - 80) / 20; michael@0: var lines = this._content.lines; michael@0: var offsetY = lines[this._scrollV - 1].y; michael@0: for (var i = this._bottomScrollV; i < lines.length; i++) { michael@0: var line = lines[i]; michael@0: if (line.y + line.height + offsetY > maxVisibleY) { michael@0: return i + 1; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: maxScrollV: { michael@0: get: function maxScrollV() { michael@0: this.ensureDimensions(); michael@0: return this._maxScrollV; michael@0: } michael@0: }, michael@0: maxScrollH: { michael@0: get: function maxScrollH() { michael@0: this.ensureDimensions(); michael@0: return Math.max(this._content.textWidth - this._bbox.xMax / 20 + 4, 0); michael@0: } michael@0: }, michael@0: background: { michael@0: get: function background() { michael@0: return this._background; michael@0: }, michael@0: set: function background(value) { michael@0: if (this._background === value) { michael@0: return; michael@0: } michael@0: this._background = value; michael@0: this._invalidate(); michael@0: } michael@0: }, michael@0: backgroundColor: { michael@0: get: function backgroundColor() { michael@0: return this._backgroundColor; michael@0: }, michael@0: set: function backgroundColor(value) { michael@0: if (this._backgroundColor === value) { michael@0: return; michael@0: } michael@0: this._backgroundColor = value; michael@0: this._backgroundColorStr = rgbIntAlphaToStr(value, 1); michael@0: if (this._background) { michael@0: this._invalidate(); michael@0: } michael@0: } michael@0: }, michael@0: border: { michael@0: get: function border() { michael@0: return this._border; michael@0: }, michael@0: set: function border(value) { michael@0: if (this._border === value) { michael@0: return; michael@0: } michael@0: this._border = value; michael@0: this._invalidate(); michael@0: } michael@0: }, michael@0: borderColor: { michael@0: get: function borderColor() { michael@0: return this._borderColor; michael@0: }, michael@0: set: function borderColor(value) { michael@0: if (this._borderColor === value) { michael@0: return; michael@0: } michael@0: this._borderColor = value; michael@0: this._borderColorStr = rgbIntAlphaToStr(value, 1); michael@0: if (this._border) { michael@0: this._invalidate(); michael@0: } michael@0: } michael@0: }, michael@0: type: { michael@0: get: function borderColor() { michael@0: return this._type; michael@0: }, michael@0: set: function borderColor(value) { michael@0: somewhatImplemented('TextField.type'); michael@0: this._type = value; michael@0: } michael@0: }, michael@0: embedFonts: { michael@0: get: function embedFonts() { michael@0: return this._embedFonts; michael@0: }, michael@0: set: function embedFonts(value) { michael@0: this.invalidateDimensions(); michael@0: this._embedFonts = value; michael@0: } michael@0: }, michael@0: condenseWhite: { michael@0: get: function condenseWhite() { michael@0: return this._content.condenseWhite; michael@0: }, michael@0: set: function condenseWhite(value) { michael@0: somewhatImplemented('TextField.condenseWhite'); michael@0: this._content.condenseWhite = value; michael@0: } michael@0: }, michael@0: sharpness: { michael@0: get: function sharpness() { michael@0: return this._sharpness; michael@0: }, michael@0: set: function sharpness(value) { michael@0: somewhatImplemented('TextField.sharpness'); michael@0: this._sharpness = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: function TextFieldContent(initialFormat) { michael@0: this.defaultTextFormat = initialFormat; michael@0: this.textWidth = 0; michael@0: this.textHeight = 0; michael@0: this.condenseWhite = false; michael@0: this.wordWrap = false; michael@0: this.multiline = false; michael@0: this.textColor = null; michael@0: this._text = ''; michael@0: this._htmlText = ''; michael@0: this._createTrunk(); michael@0: this._textRuns = null; michael@0: this._htmlParser = document.createElement('p'); michael@0: this._measureCtx = document.createElement('canvas').getContext('2d'); michael@0: } michael@0: TextFieldContent.knownNodeTypes = { michael@0: 'BR': true, michael@0: 'LI': true, michael@0: 'P': true, michael@0: 'B': true, michael@0: 'I': true, michael@0: 'FONT': true, michael@0: 'TEXTFORMAT': true, michael@0: 'U': true, michael@0: 'A': true, michael@0: 'IMG': true, michael@0: 'SPAN': true michael@0: }; michael@0: TextFieldContent.WRAP_OPPORTUNITIES = { michael@0: ' ': true, michael@0: '.': true, michael@0: '-': true, michael@0: '\t': true michael@0: }; michael@0: TextFieldContent.TextLine = function (y) { michael@0: this.x = 0; michael@0: this.width = 0; michael@0: this.y = y; michael@0: this.height = 0; michael@0: this.leading = 0; michael@0: this.runs = []; michael@0: this.largestFormat = null; michael@0: }; michael@0: TextFieldContent.prototype = { michael@0: get text() { michael@0: return this._text; michael@0: }, michael@0: set text(val) { michael@0: val = val + ''; michael@0: if (this._text === val) { michael@0: return; michael@0: } michael@0: var lines = []; michael@0: var lineOffset = 0; michael@0: for (var index = 0; index < val.length;) { michael@0: var char = val[index]; michael@0: if (char === '\r' || char === '\n') { michael@0: lines.push(val.substring(lineOffset, index)); michael@0: lineOffset = index; michael@0: if (char === '\r' && val[index + 1] === '\n') { michael@0: index++; michael@0: } michael@0: } michael@0: index++; michael@0: } michael@0: lines.push(val.substring(lineOffset, index)); michael@0: this._createTrunk(); michael@0: this._text = val; michael@0: this._htmlText = val; michael@0: this._tree.children[0].children[0] = { michael@0: type: 'plain-text', michael@0: lines: lines michael@0: }; michael@0: }, michael@0: get htmlText() { michael@0: return this._htmlText; michael@0: }, michael@0: set htmlText(val) { michael@0: if (this._htmlText === val) { michael@0: return; michael@0: } michael@0: this.defaultTextFormat.bold = false; michael@0: this.defaultTextFormat.italic = false; michael@0: this._parseHtml(val); michael@0: }, michael@0: calculateMetrics: function (bounds, embedFonts) { michael@0: var initialFormat = this.defaultTextFormat; michael@0: this.resolveFont(initialFormat, embedFonts); michael@0: this.lines = []; michael@0: this._textRuns = [ michael@0: { michael@0: type: 'f', michael@0: format: initialFormat michael@0: } michael@0: ]; michael@0: var width = Math.max(bounds.xMax / 20 - 4, 1); michael@0: var height = Math.max(bounds.yMax / 20 - 4, 1); michael@0: var state = { michael@0: ctx: this._measureCtx, michael@0: w: width, michael@0: h: height, michael@0: maxLineWidth: 0, michael@0: formats: [ michael@0: initialFormat michael@0: ], michael@0: currentFormat: initialFormat, michael@0: line: new TextFieldContent.TextLine(0), michael@0: wordWrap: this.wordWrap, michael@0: combinedAlign: null, michael@0: textColor: this.textColor, michael@0: embedFonts: embedFonts michael@0: }; michael@0: this._collectRuns(state, this._tree); michael@0: this._finishLine(state, false); michael@0: this.textWidth = state.maxLineWidth | 0; michael@0: this.textHeight = state.line.y | 0; michael@0: return state.combinedAlign; michael@0: }, michael@0: makeFormatString: function (format) { michael@0: var boldItalic = ''; michael@0: if (format.italic) { michael@0: boldItalic += 'italic'; michael@0: } michael@0: if (format.bold) { michael@0: boldItalic += ' bold'; michael@0: } michael@0: return boldItalic + ' ' + format.size + 'px ' + (format.font._uniqueName || format.font._fontName); michael@0: }, michael@0: resolveFont: function (format, embedded) { michael@0: var face = format.face.toLowerCase(); michael@0: if (face === '_sans') { michael@0: face = 'sans-serif'; michael@0: } else if (face === '_serif') { michael@0: face = 'serif'; michael@0: } else if (face === '_typewriter') { michael@0: face = 'monospace'; michael@0: } michael@0: var style; michael@0: if (format.bold) { michael@0: if (format.italic) { michael@0: style = 'boldItalic'; michael@0: } else { michael@0: style = 'bold'; michael@0: } michael@0: } else if (format.italic) { michael@0: style = 'italic'; michael@0: } else { michael@0: style = 'regular'; michael@0: } michael@0: var font = FontDefinition.getFont(face, style, embedded); michael@0: format.font = font; michael@0: }, michael@0: _parseHtml: function (val) { michael@0: this._htmlParser.innerHTML = val; michael@0: var rootElement = this._htmlParser.childNodes.length !== 1 ? this._htmlParser : this._htmlParser.childNodes[0]; michael@0: this._text = ''; michael@0: this._htmlText = val; michael@0: this._createTrunk(); michael@0: if (rootElement.nodeType === 3) { michael@0: this._convertNode(rootElement, this._tree.children[0].children); michael@0: } michael@0: var initialNodeList = [ michael@0: rootElement michael@0: ]; michael@0: var attributes; michael@0: var format; michael@0: var key; michael@0: if (initialNodeList.length == 1 && rootElement.localName.toUpperCase() == 'P') { michael@0: attributes = this._extractAttributes(rootElement); michael@0: format = this._tree.format; michael@0: for (key in attributes) { michael@0: format[key] = attributes[key]; michael@0: } michael@0: initialNodeList = rootElement.childNodes; michael@0: rootElement = rootElement.childNodes[0]; michael@0: } michael@0: if (initialNodeList.length == 1 && rootElement.localName.toUpperCase() == 'FONT') { michael@0: attributes = this._extractAttributes(rootElement); michael@0: format = this._tree.children[0].format; michael@0: for (key in attributes) { michael@0: format[key] = attributes[key]; michael@0: } michael@0: initialNodeList = rootElement.childNodes; michael@0: } michael@0: this._convertNodeList(initialNodeList, this._tree.children[0].children); michael@0: }, michael@0: _createTrunk: function () { michael@0: var initialFormat = this.defaultTextFormat; michael@0: this._tree = { michael@0: type: 'SPAN', michael@0: format: { michael@0: ALIGN: initialFormat.align michael@0: }, michael@0: children: [] michael@0: }; michael@0: var fontAttributes = { michael@0: FACE: initialFormat.face, michael@0: LETTERSPACING: initialFormat.letterSpacing, michael@0: KERNING: initialFormat.kerning, michael@0: LEADING: initialFormat.leading, michael@0: COLOR: initialFormat.color michael@0: }; michael@0: this._tree.children[0] = { michael@0: type: 'FONT', michael@0: format: fontAttributes, michael@0: children: [] michael@0: }; michael@0: }, michael@0: _convertNode: function (input, destinationList) { michael@0: if (!(input.nodeType === 1 || input.nodeType === 3) || input.prefix) { michael@0: return; michael@0: } michael@0: var node; michael@0: if (input.nodeType === 3) { michael@0: var text = input.textContent; michael@0: node = { michael@0: type: 'text', michael@0: text: text, michael@0: format: null, michael@0: children: null michael@0: }; michael@0: this._text += text; michael@0: destinationList.push(node); michael@0: return; michael@0: } michael@0: var nodeType = input.localName.toUpperCase(); michael@0: if (!TextFieldContent.knownNodeTypes[nodeType] || this.multiline === false && (nodeType === 'P' || nodeType === 'BR')) { michael@0: if (nodeType === 'SBR') { michael@0: destinationList.push({ michael@0: type: 'BR', michael@0: text: null, michael@0: format: null, michael@0: children: null michael@0: }); michael@0: } michael@0: this._convertNodeList(input.childNodes, destinationList); michael@0: return; michael@0: } michael@0: node = { michael@0: type: nodeType, michael@0: text: null, michael@0: format: this._extractAttributes(input), michael@0: children: [] michael@0: }; michael@0: this._convertNodeList(input.childNodes, node.children); michael@0: destinationList.push(node); michael@0: }, michael@0: _convertNodeList: function (from, to) { michael@0: var childCount = from.length; michael@0: for (var i = 0; i < childCount; i++) { michael@0: this._convertNode(from[i], to); michael@0: } michael@0: }, michael@0: _extractAttributes: function (node) { michael@0: var attributesList = node.attributes; michael@0: var attributesMap = {}; michael@0: for (var i = 0; i < attributesList.length; i++) { michael@0: var attr = attributesList[i]; michael@0: if (attr.prefix) { michael@0: continue; michael@0: } michael@0: attributesMap[attr.localName.toUpperCase()] = attr.value; michael@0: } michael@0: return attributesMap; michael@0: }, michael@0: _collectRuns: function (state, node) { michael@0: var formatNode = false; michael@0: var blockNode = false; michael@0: switch (node.type) { michael@0: case 'plain-text': michael@0: var lines = node.lines; michael@0: for (var i = 0; i < lines.length; i++) { michael@0: this._addRunsForText(state, lines[i]); michael@0: if (i < lines.length - 1) { michael@0: this._finishLine(state, true); michael@0: } michael@0: } michael@0: return; michael@0: case 'text': michael@0: this._addRunsForText(state, node.text); michael@0: return; michael@0: case 'BR': michael@0: this._finishLine(state, true); michael@0: return; michael@0: case 'LI': michael@0: case 'P': michael@0: this._finishLine(state, false); michael@0: this._pushFormat(state, node); michael@0: blockNode = true; michael@0: break; michael@0: case 'B': michael@0: case 'I': michael@0: case 'FONT': michael@0: case 'TEXTFORMAT': michael@0: this._pushFormat(state, node); michael@0: formatNode = true; michael@0: break; michael@0: case 'U': michael@0: case 'A': michael@0: case 'IMG': michael@0: case 'SPAN': michael@0: default: michael@0: } michael@0: for (var i = 0; i < node.children.length; i++) { michael@0: var child = node.children[i]; michael@0: this._collectRuns(state, child); michael@0: } michael@0: if (formatNode) { michael@0: this._popFormat(state); michael@0: } michael@0: if (blockNode) { michael@0: this._finishLine(state, true); michael@0: } michael@0: }, michael@0: _addRunsForText: function (state, text) { michael@0: if (!text) { michael@0: return; michael@0: } michael@0: if (!state.wordWrap) { michael@0: this._addTextRun(state, text, state.ctx.measureText(text).width); michael@0: return; michael@0: } michael@0: while (text.length) { michael@0: var width = state.ctx.measureText(text).width; michael@0: var availableWidth = state.w - state.line.width; michael@0: if (availableWidth <= 0) { michael@0: this._finishLine(state, false); michael@0: availableWidth = state.w - state.line.width; michael@0: } michael@0: if (width <= availableWidth) { michael@0: this._addTextRun(state, text, width); michael@0: break; michael@0: } else { michael@0: var offset = text.length / width * availableWidth | 0; michael@0: while (state.ctx.measureText(text.substr(0, offset)).width < availableWidth && offset < text.length) { michael@0: offset++; michael@0: } michael@0: var wrapOffset = offset; michael@0: while (wrapOffset > -1) { michael@0: if (TextFieldContent.WRAP_OPPORTUNITIES[text[wrapOffset]]) { michael@0: wrapOffset++; michael@0: break; michael@0: } michael@0: wrapOffset--; michael@0: } michael@0: if (wrapOffset === -1) { michael@0: if (state.line.width > 0) { michael@0: this._finishLine(state, false); michael@0: continue; michael@0: } michael@0: while (state.ctx.measureText(text.substr(0, offset)).width > availableWidth) { michael@0: offset--; michael@0: } michael@0: if (offset === 0) { michael@0: offset = 1; michael@0: } michael@0: wrapOffset = offset; michael@0: } michael@0: var runText = text.substr(0, wrapOffset); michael@0: width = state.ctx.measureText(runText).width; michael@0: this._addTextRun(state, runText, width); michael@0: if (state.wordWrap) { michael@0: this._finishLine(state, false); michael@0: } michael@0: text = text.substr(wrapOffset); michael@0: } michael@0: } michael@0: }, michael@0: _addTextRun: function (state, text, width) { michael@0: if (text.length === 0) { michael@0: return; michael@0: } michael@0: var line = state.line; michael@0: var format = state.currentFormat; michael@0: var size = format.size; michael@0: var run = { michael@0: type: 't', michael@0: text: text, michael@0: x: line.width michael@0: }; michael@0: this._textRuns.push(run); michael@0: state.line.runs.push(run); michael@0: line.width += width | 0; michael@0: if (line.leading === 0 && format.leading > line.leading) { michael@0: line.leading = format.leading; michael@0: } michael@0: if (!line.largestFormat || size > line.largestFormat.size) { michael@0: line.largestFormat = format; michael@0: } michael@0: }, michael@0: _finishLine: function (state, forceNewline) { michael@0: var line = state.line; michael@0: if (line.runs.length === 0) { michael@0: if (forceNewline) { michael@0: var format = state.currentFormat; michael@0: state.line.y += format.font._metrics.height * format.size + format.leading | 0; michael@0: } michael@0: return; michael@0: } michael@0: var runs = line.runs; michael@0: var format = line.largestFormat; michael@0: var baselinePos = line.y + format.font._metrics.ascent * format.size; michael@0: for (var i = runs.length; i--;) { michael@0: runs[i].y = baselinePos; michael@0: } michael@0: var align = (state.currentFormat.align || '').toLowerCase(); michael@0: if (state.combinedAlign === null) { michael@0: state.combinedAlign = align; michael@0: } else if (state.combinedAlign !== align) { michael@0: state.combinedAlign = 'mixed'; michael@0: } michael@0: if (align === 'center' || align === 'right') { michael@0: var offset = Math.max(state.w - line.width, 0); michael@0: if (align === 'center') { michael@0: offset >>= 1; michael@0: } michael@0: for (i = runs.length; i--;) { michael@0: runs[i].x += offset; michael@0: } michael@0: } michael@0: line.height = format.font._metrics.height * format.size + line.leading | 0; michael@0: state.maxLineWidth = Math.max(state.maxLineWidth, line.width); michael@0: this.lines.push(line); michael@0: state.line = new TextFieldContent.TextLine(line.y + line.height); michael@0: }, michael@0: _pushFormat: function (state, node) { michael@0: var attributes = node.format; michael@0: var format = Object.create(state.formats[state.formats.length - 1]); michael@0: var fontChanged = false; michael@0: switch (node.type) { michael@0: case 'P': michael@0: if (attributes.ALIGN === format.align) { michael@0: return; michael@0: } michael@0: format.align = attributes.ALIGN; michael@0: break; michael@0: case 'B': michael@0: format.bold = true; michael@0: fontChanged = true; michael@0: break; michael@0: case 'I': michael@0: format.italic = true; michael@0: fontChanged = true; michael@0: break; michael@0: case 'FONT': michael@0: if (attributes.COLOR !== undefined) { michael@0: format.color = attributes.COLOR; michael@0: } michael@0: if (attributes.FACE !== undefined) { michael@0: format.face = attributes.FACE; michael@0: fontChanged = true; michael@0: } michael@0: if (attributes.SIZE !== undefined) { michael@0: format.size = parseFloat(attributes.SIZE); michael@0: } michael@0: if (attributes.LETTERSPACING !== undefined) { michael@0: format.letterspacing = parseFloat(attributes.LETTERSPACING); michael@0: } michael@0: if (attributes.KERNING !== undefined) { michael@0: format.kerning = attributes.KERNING && true; michael@0: } michael@0: case 'TEXTFORMAT': michael@0: if (attributes.LEADING !== undefined) { michael@0: format.leading = parseFloat(attributes.LEADING); michael@0: } michael@0: if (attributes.INDENT !== undefined) { michael@0: state.line.x = attributes.INDENT; michael@0: state.line.width += attributes.INDENT | 0; michael@0: } michael@0: break; michael@0: default: michael@0: warning('Unknown format node encountered: ' + node.type); michael@0: return; michael@0: } michael@0: if (state.textColor !== null) { michael@0: format.color = rgbIntAlphaToStr(state.textColor, 1); michael@0: } michael@0: if (fontChanged) { michael@0: this.resolveFont(format, state.embedFonts); michael@0: } michael@0: format.str = this.makeFormatString(format); michael@0: state.formats.push(format); michael@0: this._textRuns.push({ michael@0: type: 'f', michael@0: format: format michael@0: }); michael@0: state.currentFormat = format; michael@0: state.ctx.font = format.str; michael@0: }, michael@0: _popFormat: function (state) { michael@0: state.formats.pop(); michael@0: var format = state.currentFormat = state.formats[state.formats.length - 1]; michael@0: this._textRuns.push({ michael@0: type: 'f', michael@0: format: format michael@0: }); michael@0: state.ctx.font = state.str; michael@0: } michael@0: }; michael@0: var TextFormatDefinition = function () { michael@0: var measureTextField; michael@0: return { michael@0: __class__: 'flash.text.TextFormat', michael@0: initialize: function () { michael@0: }, michael@0: fromObject: function (obj) { michael@0: this._font = obj.face || null; michael@0: this._size = typeof obj.size === 'number' ? obj.size : null; michael@0: this._color = typeof obj.color === 'number' ? obj.color : null; michael@0: this._bold = typeof obj.bold === 'boolean' ? obj.bold : null; michael@0: this._italic = typeof obj.italic === 'boolean' ? obj.italic : null; michael@0: this._underline = typeof obj.underline === 'boolean' ? obj.underline : null; michael@0: this._url = obj.url || null; michael@0: this._target = obj.target || null; michael@0: this._align = obj.align || null; michael@0: this._leftMargin = typeof obj.leftMargin === 'number' ? obj.leftMargin : null; michael@0: this._rightMargin = typeof obj.rightMargin === 'number' ? obj.rightMargin : null; michael@0: this._indent = typeof obj.indent === 'number' ? obj.indent : null; michael@0: this._leading = typeof obj.leading === 'number' ? obj.leading : null; michael@0: return this; michael@0: }, michael@0: toObject: function () { michael@0: return { michael@0: face: this._font || 'serif', michael@0: size: this._size || 12, michael@0: color: this._color || 0, michael@0: bold: this._bold || false, michael@0: italic: this._italic || false, michael@0: underline: this._underline || false, michael@0: url: this._url, michael@0: target: this._target, michael@0: align: this._align || 'left', michael@0: leftMargin: this._leftMargin || 0, michael@0: rightMargin: this._rightMargin || 0, michael@0: indent: this._indent || 0, michael@0: leading: this._leading || 0 michael@0: }; michael@0: }, michael@0: as2GetTextExtent: function (text, width) { michael@0: if (!measureTextField) { michael@0: measureTextField = new flash.text.TextField(); michael@0: measureTextField._multiline = true; michael@0: } michael@0: if (!isNaN(width) && width > 0) { michael@0: measureTextField.width = width + 4; michael@0: measureTextField._wordWrap = true; michael@0: } else { michael@0: measureTextField._wordWrap = false; michael@0: } michael@0: measureTextField.defaultTextFormat = this; michael@0: measureTextField.text = text; michael@0: measureTextField.ensureDimensions(); michael@0: var result = {}; michael@0: var textWidth = measureTextField._textWidth; michael@0: var textHeight = measureTextField._textHeight; michael@0: result.asSetPublicProperty('width', textWidth); michael@0: result.asSetPublicProperty('height', textHeight); michael@0: result.asSetPublicProperty('textFieldWidth', textWidth + 4); michael@0: result.asSetPublicProperty('textFieldHeight', textHeight + 4); michael@0: var metrics = measureTextField.getLineMetrics(0); michael@0: result.asSetPublicProperty('ascent', metrics.asGetPublicProperty('ascent')); michael@0: result.asSetPublicProperty('descent', metrics.asGetPublicProperty('descent')); michael@0: return result; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: align: { michael@0: get: function align() { michael@0: return this._align; michael@0: }, michael@0: set: function align(value) { michael@0: this._align = value; michael@0: } michael@0: }, michael@0: blockIndent: { michael@0: get: function blockIndent() { michael@0: return this._blockIndent; michael@0: }, michael@0: set: function blockIndent(value) { michael@0: this._blockIndent = value; michael@0: } michael@0: }, michael@0: bold: { michael@0: get: function bold() { michael@0: return this._bold; michael@0: }, michael@0: set: function bold(value) { michael@0: this._bold = value; michael@0: } michael@0: }, michael@0: bullet: { michael@0: get: function bullet() { michael@0: return this._bullet; michael@0: }, michael@0: set: function bullet(value) { michael@0: this._bullet = value; michael@0: } michael@0: }, michael@0: color: { michael@0: get: function color() { michael@0: return this._color; michael@0: }, michael@0: set: function color(value) { michael@0: this._color = value; michael@0: } michael@0: }, michael@0: display: { michael@0: get: function display() { michael@0: return this._display; michael@0: }, michael@0: set: function display(value) { michael@0: this._display = value; michael@0: } michael@0: }, michael@0: font: { michael@0: get: function font() { michael@0: return this._font; michael@0: }, michael@0: set: function font(value) { michael@0: this._font = value; michael@0: } michael@0: }, michael@0: indent: { michael@0: get: function indent() { michael@0: return this._indent; michael@0: }, michael@0: set: function indent(value) { michael@0: this._indent = value; michael@0: } michael@0: }, michael@0: italic: { michael@0: get: function italic() { michael@0: return this._italic; michael@0: }, michael@0: set: function italic(value) { michael@0: this._italic = value; michael@0: } michael@0: }, michael@0: kerning: { michael@0: get: function kerning() { michael@0: return this._kerning; michael@0: }, michael@0: set: function kerning(value) { michael@0: this._kerning = value; michael@0: } michael@0: }, michael@0: leading: { michael@0: get: function leading() { michael@0: return this._leading; michael@0: }, michael@0: set: function leading(value) { michael@0: this._leading = value; michael@0: } michael@0: }, michael@0: leftMargin: { michael@0: get: function leftMargin() { michael@0: return this._leftMargin; michael@0: }, michael@0: set: function leftMargin(value) { michael@0: this._leftMargin = value; michael@0: } michael@0: }, michael@0: letterSpacing: { michael@0: get: function letterSpacing() { michael@0: return this._letterSpacing; michael@0: }, michael@0: set: function letterSpacing(value) { michael@0: this._letterSpacing = value; michael@0: } michael@0: }, michael@0: rightMargin: { michael@0: get: function rightMargin() { michael@0: return this._rightMargin; michael@0: }, michael@0: set: function rightMargin(value) { michael@0: this._rightMargin = value; michael@0: } michael@0: }, michael@0: size: { michael@0: get: function size() { michael@0: return this._size; michael@0: }, michael@0: set: function size(value) { michael@0: this._size = value; michael@0: } michael@0: }, michael@0: tabStops: { michael@0: get: function tabStops() { michael@0: return this._tabStops; michael@0: }, michael@0: set: function tabStops(value) { michael@0: this._tabStops = value; michael@0: } michael@0: }, michael@0: target: { michael@0: get: function target() { michael@0: return this._target; michael@0: }, michael@0: set: function target(value) { michael@0: this._target = value; michael@0: } michael@0: }, michael@0: underline: { michael@0: get: function underline() { michael@0: return this._underline; michael@0: }, michael@0: set: function underline(value) { michael@0: this._underline = value; michael@0: } michael@0: }, michael@0: url: { michael@0: get: function url() { michael@0: return this._url; michael@0: }, michael@0: set: function url(value) { michael@0: this._url = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ContentElementDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.ContentElement', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: textBlock: { michael@0: get: function textBlock() { michael@0: notImplemented('ContentElement.textBlock'); michael@0: return this._textBlock; michael@0: } michael@0: }, michael@0: textBlockBeginIndex: { michael@0: get: function textBlockBeginIndex() { michael@0: notImplemented('ContentElement.textBlockBeginIndex'); michael@0: return this._textBlockBeginIndex; michael@0: } michael@0: }, michael@0: elementFormat: { michael@0: get: function elementFormat() { michael@0: return this._elementFormat; michael@0: }, michael@0: set: function elementFormat(value) { michael@0: somewhatImplemented('ContentElement.elementFormat'); michael@0: this._elementFormat = value; michael@0: } michael@0: }, michael@0: eventMirror: { michael@0: get: function eventMirror() { michael@0: return this._eventMirror; michael@0: }, michael@0: set: function eventMirror(value) { michael@0: somewhatImplemented('ContentElement.eventMirror'); michael@0: this._eventMirror = value; michael@0: } michael@0: }, michael@0: groupElement: { michael@0: get: function groupElement() { michael@0: notImplemented('ContentElement.groupElement'); michael@0: return this._groupElement; michael@0: } michael@0: }, michael@0: rawText: { michael@0: get: function rawText() { michael@0: notImplemented('ContentElement.rawText'); michael@0: return this._rawText; michael@0: } michael@0: }, michael@0: text: { michael@0: get: function text() { michael@0: notImplemented('ContentElement.text'); michael@0: return this._text; michael@0: } michael@0: }, michael@0: textRotation: { michael@0: get: function textRotation() { michael@0: return this._textRotation; michael@0: }, michael@0: set: function textRotation(value) { michael@0: somewhatImplemented('ContentElement.textRotation'); michael@0: this._textRotation = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ElementFormatDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.ElementFormat', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: getFontMetrics: function getFontMetrics() { michael@0: notImplemented('ElementFormat.getFontMetrics'); michael@0: }, michael@0: alignmentBaseline: { michael@0: get: function alignmentBaseline() { michael@0: return this._alignmentBaseline; michael@0: }, michael@0: set: function alignmentBaseline(alignmentBaseline) { michael@0: somewhatImplemented('ElementFormat.alignmentBaseline'); michael@0: this._alignmentBaseline = alignmentBaseline; michael@0: } michael@0: }, michael@0: alpha: { michael@0: get: function alpha() { michael@0: return this._alpha; michael@0: }, michael@0: set: function alpha(value) { michael@0: somewhatImplemented('ElementFormat.alpha'); michael@0: this._alpha = value; michael@0: } michael@0: }, michael@0: baselineShift: { michael@0: get: function baselineShift() { michael@0: return this._baselineShift; michael@0: }, michael@0: set: function baselineShift(value) { michael@0: somewhatImplemented('ElementFormat.baselineShift'); michael@0: this._baselineShift = value; michael@0: } michael@0: }, michael@0: breakOpportunity: { michael@0: get: function breakOpportunity() { michael@0: return this._breakOpportunity; michael@0: }, michael@0: set: function breakOpportunity(opportunityType) { michael@0: somewhatImplemented('ElementFormat.breakOpportunity'); michael@0: this._breakOpportunity = opportunityType; michael@0: } michael@0: }, michael@0: color: { michael@0: get: function color() { michael@0: return this._color; michael@0: }, michael@0: set: function color(value) { michael@0: somewhatImplemented('ElementFormat.color'); michael@0: this._color = value; michael@0: } michael@0: }, michael@0: dominantBaseline: { michael@0: get: function dominantBaseline() { michael@0: return this._dominantBaseline; michael@0: }, michael@0: set: function dominantBaseline(dominantBaseline) { michael@0: somewhatImplemented('ElementFormat.dominantBaseline'); michael@0: this._dominantBaseline = dominantBaseline; michael@0: } michael@0: }, michael@0: fontDescription: { michael@0: get: function fontDescription() { michael@0: return this._fontDescription; michael@0: }, michael@0: set: function fontDescription(value) { michael@0: somewhatImplemented('ElementFormat.fontDescription'); michael@0: this._fontDescription = value; michael@0: } michael@0: }, michael@0: digitCase: { michael@0: get: function digitCase() { michael@0: return this._digitCase; michael@0: }, michael@0: set: function digitCase(digitCaseType) { michael@0: somewhatImplemented('ElementFormat.digitCase'); michael@0: this._digitCase = digitCaseType; michael@0: } michael@0: }, michael@0: digitWidth: { michael@0: get: function digitWidth() { michael@0: return this._digitWidth; michael@0: }, michael@0: set: function digitWidth(digitWidthType) { michael@0: somewhatImplemented('ElementFormat.digitWidth'); michael@0: this._digitWidth = digitWidthType; michael@0: } michael@0: }, michael@0: ligatureLevel: { michael@0: get: function ligatureLevel() { michael@0: return this._ligatureLevel; michael@0: }, michael@0: set: function ligatureLevel(ligatureLevelType) { michael@0: somewhatImplemented('ElementFormat.ligatureLevel'); michael@0: this._ligatureLevel = ligatureLevelType; michael@0: } michael@0: }, michael@0: fontSize: { michael@0: get: function fontSize() { michael@0: return this._fontSize; michael@0: }, michael@0: set: function fontSize(value) { michael@0: somewhatImplemented('ElementFormat.fontSize'); michael@0: this._fontSize = value; michael@0: } michael@0: }, michael@0: kerning: { michael@0: get: function kerning() { michael@0: return this._kerning; michael@0: }, michael@0: set: function kerning(value) { michael@0: somewhatImplemented('ElementFormat.kerning'); michael@0: this._kerning = value; michael@0: } michael@0: }, michael@0: locale: { michael@0: get: function locale() { michael@0: return this._locale; michael@0: }, michael@0: set: function locale(value) { michael@0: somewhatImplemented('ElementFormat.locale'); michael@0: this._locale = value; michael@0: } michael@0: }, michael@0: textRotation: { michael@0: get: function textRotation() { michael@0: return this._textRotation; michael@0: }, michael@0: set: function textRotation(value) { michael@0: somewhatImplemented('ElementFormat.textRotation'); michael@0: this._textRotation = value; michael@0: } michael@0: }, michael@0: trackingRight: { michael@0: get: function trackingRight() { michael@0: return this._trackingRight; michael@0: }, michael@0: set: function trackingRight(value) { michael@0: somewhatImplemented('ElementFormat.trackingRight'); michael@0: this._trackingRight = value; michael@0: } michael@0: }, michael@0: trackingLeft: { michael@0: get: function trackingLeft() { michael@0: return this._trackingLeft; michael@0: }, michael@0: set: function trackingLeft(value) { michael@0: somewhatImplemented('ElementFormat.trackingLeft'); michael@0: this._trackingLeft = value; michael@0: } michael@0: }, michael@0: typographicCase: { michael@0: get: function typographicCase() { michael@0: return this._typographicCase; michael@0: }, michael@0: set: function typographicCase(typographicCaseType) { michael@0: somewhatImplemented('ElementFormat.typographicCase'); michael@0: this._typographicCase = typographicCaseType; michael@0: } michael@0: }, michael@0: locked: { michael@0: get: function locked() { michael@0: notImplemented('ElementFormat.locked'); michael@0: return this._locked; michael@0: }, michael@0: set: function locked(value) { michael@0: notImplemented('ElementFormat.locked'); michael@0: this._locked = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var FontDescriptionDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.FontDescription', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: isFontCompatible: function isFontCompatible(fontName, fontWeight, fontPosture) { michael@0: notImplemented('FontDescription.isFontCompatible'); michael@0: }, michael@0: isDeviceFontCompatible: function isDeviceFontCompatible(fontName, fontWeight, fontPosture) { michael@0: notImplemented('FontDescription.isDeviceFontCompatible'); michael@0: } michael@0: }, michael@0: instance: { michael@0: renderingMode: { michael@0: get: function renderingMode() { michael@0: return this._renderingMode; michael@0: }, michael@0: set: function renderingMode(value) { michael@0: somewhatImplemented('FontDescription.renderingMode'); michael@0: this._renderingMode = value; michael@0: } michael@0: }, michael@0: fontLookup: { michael@0: get: function fontLookup() { michael@0: return this._fontLookup; michael@0: }, michael@0: set: function fontLookup(value) { michael@0: somewhatImplemented('FontDescription.fontLookup'); michael@0: this._fontLookup = value; michael@0: } michael@0: }, michael@0: fontName: { michael@0: get: function fontName() { michael@0: return this._fontName; michael@0: }, michael@0: set: function fontName(value) { michael@0: somewhatImplemented('FontDescription.fontName'); michael@0: this._fontName = value; michael@0: } michael@0: }, michael@0: fontPosture: { michael@0: get: function fontPosture() { michael@0: return this._fontPosture; michael@0: }, michael@0: set: function fontPosture(value) { michael@0: somewhatImplemented('FontDescription.fontPosture'); michael@0: this._fontPosture = value; michael@0: } michael@0: }, michael@0: fontWeight: { michael@0: get: function fontWeight() { michael@0: return this._fontWeight; michael@0: }, michael@0: set: function fontWeight(value) { michael@0: somewhatImplemented('FontDescription.fontWeight'); michael@0: this._fontWeight = value; michael@0: } michael@0: }, michael@0: cffHinting: { michael@0: get: function cffHinting() { michael@0: return this._cffHinting; michael@0: }, michael@0: set: function cffHinting(value) { michael@0: somewhatImplemented('FontDescription.cffHinting'); michael@0: this._cffHinting = value; michael@0: } michael@0: }, michael@0: locked: { michael@0: get: function locked() { michael@0: notImplemented('FontDescription.locked'); michael@0: return this._locked; michael@0: }, michael@0: set: function locked(value) { michael@0: notImplemented('FontDescription.locked'); michael@0: this._locked = value; michael@0: } michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: static: {}, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var GroupElementDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.GroupElement', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: getElementAt: function getElementAt(index) { michael@0: notImplemented('GroupElement.getElementAt'); michael@0: }, michael@0: setElements: function setElements(value) { michael@0: somewhatImplemented('GroupElement.setElements'); michael@0: this._elements = value; michael@0: }, michael@0: groupElements: function groupElements(beginIndex, endIndex) { michael@0: notImplemented('GroupElement.groupElements'); michael@0: }, michael@0: ungroupElements: function ungroupElements(groupIndex) { michael@0: notImplemented('GroupElement.ungroupElements'); michael@0: }, michael@0: mergeTextElements: function mergeTextElements(beginIndex, endIndex) { michael@0: notImplemented('GroupElement.mergeTextElements'); michael@0: }, michael@0: splitTextElement: function splitTextElement(elementIndex, splitIndex) { michael@0: notImplemented('GroupElement.splitTextElement'); michael@0: }, michael@0: replaceElements: function replaceElements(beginIndex, endIndex, newElements) { michael@0: notImplemented('GroupElement.replaceElements'); michael@0: }, michael@0: getElementAtCharIndex: function getElementAtCharIndex(charIndex) { michael@0: notImplemented('GroupElement.getElementAtCharIndex'); michael@0: }, michael@0: elementCount: { michael@0: get: function elementCount() { michael@0: notImplemented('GroupElement.elementCount'); michael@0: return this._elementCount; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var SpaceJustifierDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.SpaceJustifier', michael@0: initialize: function () { michael@0: this._letterSpacing = false; michael@0: this._optimumSpacing = 1; michael@0: this._minimumSpacing = 0.5; michael@0: this._maximumSpacing = 1.5; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: cloneSpacing: function cloneSpacing(justifier) { michael@0: somewhatImplemented('SpaceJustifier.cloneSpacing'); michael@0: justifier._optimumSpacing = this._optimumSpacing; michael@0: justifier._minimumSpacing = this._minimumSpacing; michael@0: justifier._maximumSpacing = this._maximumSpacing; michael@0: }, michael@0: letterSpacing: { michael@0: get: function letterSpacing() { michael@0: return this._letterSpacing; michael@0: }, michael@0: set: function letterSpacing(value) { michael@0: somewhatImplemented('SpaceJustifier.letterSpacing'); michael@0: this._letterSpacing = value; michael@0: } michael@0: }, michael@0: minimumSpacing: { michael@0: get: function minimumSpacing() { michael@0: return this._minimumSpacing; michael@0: }, michael@0: set: function minimumSpacing(value) { michael@0: somewhatImplemented('SpaceJustifier.minimumSpacing'); michael@0: this._minimumSpacing = value; michael@0: } michael@0: }, michael@0: optimumSpacing: { michael@0: get: function optimumSpacing() { michael@0: return this._optimumSpacing; michael@0: }, michael@0: set: function optimumSpacing(value) { michael@0: somewhatImplemented('SpaceJustifier.optimumSpacing'); michael@0: this._optimumSpacing = value; michael@0: } michael@0: }, michael@0: maximumSpacing: { michael@0: get: function maximumSpacing() { michael@0: return this._maximumSpacing; michael@0: }, michael@0: set: function maximumSpacing(value) { michael@0: somewhatImplemented('SpaceJustifier.maximumSpacing'); michael@0: this._maximumSpacing = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextBlockDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.TextBlock', michael@0: initialize: function () { michael@0: this._firstLine = null; michael@0: this._lastLine = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: getTextJustifier: function getTextJustifier() { michael@0: return this._textJustifier; michael@0: }, michael@0: setTextJustifier: function setTextJustifier(value) { michael@0: somewhatImplemented('TextBlock.setTextJustifier'); michael@0: this._textJustifier = value; michael@0: }, michael@0: getTabStops: function getTabStops() { michael@0: return this._tabStops; michael@0: }, michael@0: setTabStops: function setTabStops(value) { michael@0: somewhatImplemented('TextBlock.setTabStops'); michael@0: this._tabStops = value; michael@0: }, michael@0: findNextAtomBoundary: function findNextAtomBoundary(afterCharIndex) { michael@0: notImplemented('TextBlock.findNextAtomBoundary'); michael@0: }, michael@0: findPreviousAtomBoundary: function findPreviousAtomBoundary(beforeCharIndex) { michael@0: notImplemented('TextBlock.findPreviousAtomBoundary'); michael@0: }, michael@0: findNextWordBoundary: function findNextWordBoundary(afterCharIndex) { michael@0: notImplemented('TextBlock.findNextWordBoundary'); michael@0: }, michael@0: findPreviousWordBoundary: function findPreviousWordBoundary(beforeCharIndex) { michael@0: notImplemented('TextBlock.findPreviousWordBoundary'); michael@0: }, michael@0: getTextLineAtCharIndex: function getTextLineAtCharIndex(charIndex) { michael@0: notImplemented('TextBlock.getTextLineAtCharIndex'); michael@0: }, michael@0: DoCreateTextLine: function DoCreateTextLine(previousLine, width, lineOffset, fitSomething, reuseLine) { michael@0: somewhatImplemented('TextBlock.DoCreateTextLine'); michael@0: if (previousLine) { michael@0: return null; michael@0: } michael@0: var textLine = new flash.text.engine.TextLine(); michael@0: textLine._textBlock = this; michael@0: textLine._specifiedWidth = width; michael@0: textLine._rawTextLength = 0; michael@0: textLine._textWidth = 0; michael@0: textLine._textHeight = 0; michael@0: textLine._ascent = 0; michael@0: textLine._descent = 0; michael@0: textLine._unjustifiedTextWidth = 0; michael@0: textLine._validity = 'valid'; michael@0: textLine._previousLine = null; michael@0: textLine._nextLine = null; michael@0: this._firstLine = textLine; michael@0: this._lastLine = textLine; michael@0: return textLine; michael@0: }, michael@0: releaseLineCreationData: function releaseLineCreationData() { michael@0: notImplemented('TextBlock.releaseLineCreationData'); michael@0: }, michael@0: releaseLines: function releaseLines(firstLine, lastLine) { michael@0: notImplemented('TextBlock.releaseLines'); michael@0: }, michael@0: dump: function dump() { michael@0: notImplemented('TextBlock.dump'); michael@0: }, michael@0: applyNonLinearFontScaling: { michael@0: get: function applyNonLinearFontScaling() { michael@0: return this._applyNonLinearFontScaling; michael@0: }, michael@0: set: function applyNonLinearFontScaling(value) { michael@0: somewhatImplemented('TextBlock.applyNonLinearFontScaling'); michael@0: this._applyNonLinearFontScaling = value; michael@0: } michael@0: }, michael@0: baselineFontDescription: { michael@0: get: function baselineFontDescription() { michael@0: return this._baselineFontDescription; michael@0: }, michael@0: set: function baselineFontDescription(value) { michael@0: somewhatImplemented('TextBlock.baselineFontDescription'); michael@0: this._baselineFontDescription = value; michael@0: } michael@0: }, michael@0: baselineFontSize: { michael@0: get: function baselineFontSize() { michael@0: return this._baselineFontSize; michael@0: }, michael@0: set: function baselineFontSize(value) { michael@0: somewhatImplemented('TextBlock.baselineFontSize'); michael@0: this._baselineFontSize = value; michael@0: } michael@0: }, michael@0: baselineZero: { michael@0: get: function baselineZero() { michael@0: return this._baselineZero; michael@0: }, michael@0: set: function baselineZero(value) { michael@0: somewhatImplemented('TextBlock.baselineZero'); michael@0: this._baselineZero = value; michael@0: } michael@0: }, michael@0: content: { michael@0: get: function content() { michael@0: return this._content; michael@0: }, michael@0: set: function content(value) { michael@0: somewhatImplemented('TextBlock.content'); michael@0: this._content = value; michael@0: } michael@0: }, michael@0: bidiLevel: { michael@0: get: function bidiLevel() { michael@0: return this._bidiLevel; michael@0: }, michael@0: set: function bidiLevel(value) { michael@0: somewhatImplemented('TextBlock.bidiLevel'); michael@0: this._bidiLevel = value; michael@0: } michael@0: }, michael@0: firstInvalidLine: { michael@0: get: function firstInvalidLine() { michael@0: notImplemented('TextBlock.firstInvalidLine'); michael@0: return this._firstInvalidLine; michael@0: } michael@0: }, michael@0: firstLine: { michael@0: get: function firstLine() { michael@0: somewhatImplemented('TextBlock.firstLine'); michael@0: return this._firstLine; michael@0: } michael@0: }, michael@0: lastLine: { michael@0: get: function lastLine() { michael@0: somewhatImplemented('TextBlock.lastLine'); michael@0: return this._lastLine; michael@0: } michael@0: }, michael@0: textLineCreationResult: { michael@0: get: function textLineCreationResult() { michael@0: notImplemented('TextBlock.textLineCreationResult'); michael@0: return this._textLineCreationResult; michael@0: } michael@0: }, michael@0: lineRotation: { michael@0: get: function lineRotation() { michael@0: return this._lineRotation; michael@0: }, michael@0: set: function lineRotation(value) { michael@0: somewhatImplemented('TextBlock.lineRotation'); michael@0: this._lineRotation = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextElementDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.TextElement', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: replaceText: function replaceText(beginIndex, endIndex, newText) { michael@0: somewhatImplemented('TextElement.replaceText'); michael@0: var text = this._text || ''; michael@0: this._text = text.slice(0, beginIndex) + newText + text.slice(endIndex); michael@0: }, michael@0: text: { michael@0: set: function text(value) { michael@0: somewhatImplemented('TextElement.text'); michael@0: this._text = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextJustifierDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.TextJustifier', michael@0: initialize: function () { michael@0: this._locale = null; michael@0: this._lineJustification = null; michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: setLocale: function setLocale(value) { michael@0: somewhatImplemented('TextJustifier.setLocale'); michael@0: this._locale = value; michael@0: }, michael@0: locale: { michael@0: get: function locale() { michael@0: return this._locale; michael@0: } michael@0: }, michael@0: lineJustification: { michael@0: get: function lineJustification() { michael@0: return this._lineJustification; michael@0: }, michael@0: set: function lineJustification(value) { michael@0: somewhatImplemented('TextJustifier.lineJustification'); michael@0: this._lineJustification = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var TextLineDefinition = function () { michael@0: return { michael@0: __class__: 'flash.text.engine.TextLine', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: getAtomIndexAtPoint: function getAtomIndexAtPoint(stageX, stageY) { michael@0: notImplemented('TextLine.getAtomIndexAtPoint'); michael@0: }, michael@0: getAtomIndexAtCharIndex: function getAtomIndexAtCharIndex(charIndex) { michael@0: notImplemented('TextLine.getAtomIndexAtCharIndex'); michael@0: }, michael@0: getAtomBounds: function getAtomBounds(atomIndex) { michael@0: notImplemented('TextLine.getAtomBounds'); michael@0: }, michael@0: getAtomBidiLevel: function getAtomBidiLevel(atomIndex) { michael@0: notImplemented('TextLine.getAtomBidiLevel'); michael@0: }, michael@0: getAtomTextRotation: function getAtomTextRotation(atomIndex) { michael@0: notImplemented('TextLine.getAtomTextRotation'); michael@0: }, michael@0: getAtomTextBlockBeginIndex: function getAtomTextBlockBeginIndex(atomIndex) { michael@0: notImplemented('TextLine.getAtomTextBlockBeginIndex'); michael@0: }, michael@0: getAtomTextBlockEndIndex: function getAtomTextBlockEndIndex(atomIndex) { michael@0: notImplemented('TextLine.getAtomTextBlockEndIndex'); michael@0: }, michael@0: getAtomCenter: function getAtomCenter(atomIndex) { michael@0: notImplemented('TextLine.getAtomCenter'); michael@0: }, michael@0: getAtomWordBoundaryOnLeft: function getAtomWordBoundaryOnLeft(atomIndex) { michael@0: notImplemented('TextLine.getAtomWordBoundaryOnLeft'); michael@0: }, michael@0: getAtomGraphic: function getAtomGraphic(atomIndex) { michael@0: notImplemented('TextLine.getAtomGraphic'); michael@0: }, michael@0: getBaselinePosition: function getBaselinePosition(baseline) { michael@0: notImplemented('TextLine.getBaselinePosition'); michael@0: }, michael@0: dump: function dump() { michael@0: notImplemented('TextLine.dump'); michael@0: }, michael@0: textBlock: { michael@0: get: function textBlock() { michael@0: notImplemented('TextLine.textBlock'); michael@0: return this._textBlock; michael@0: } michael@0: }, michael@0: hasGraphicElement: { michael@0: get: function hasGraphicElement() { michael@0: notImplemented('TextLine.hasGraphicElement'); michael@0: return this._hasGraphicElement; michael@0: } michael@0: }, michael@0: hasTabs: { michael@0: get: function hasTabs() { michael@0: notImplemented('TextLine.hasTabs'); michael@0: return this._hasTabs; michael@0: } michael@0: }, michael@0: nextLine: { michael@0: get: function nextLine() { michael@0: somewhatImplemented('TextLine.nextLine'); michael@0: return this._nextLine; michael@0: } michael@0: }, michael@0: previousLine: { michael@0: get: function previousLine() { michael@0: somewhatImplemented('TextLine.previousLine'); michael@0: return this._previousLine; michael@0: } michael@0: }, michael@0: ascent: { michael@0: get: function ascent() { michael@0: somewhatImplemented('TextLine.ascent'); michael@0: return this._ascent; michael@0: } michael@0: }, michael@0: descent: { michael@0: get: function descent() { michael@0: somewhatImplemented('TextLine.descent'); michael@0: return this._descent; michael@0: } michael@0: }, michael@0: textHeight: { michael@0: get: function textHeight() { michael@0: somewhatImplemented('TextLine.textHeight'); michael@0: return this._textHeight; michael@0: } michael@0: }, michael@0: textWidth: { michael@0: get: function textWidth() { michael@0: somewhatImplemented('TextLine.textWidth'); michael@0: return this._textWidth; michael@0: } michael@0: }, michael@0: totalAscent: { michael@0: get: function totalAscent() { michael@0: notImplemented('TextLine.totalAscent'); michael@0: return this._totalAscent; michael@0: } michael@0: }, michael@0: totalDescent: { michael@0: get: function totalDescent() { michael@0: notImplemented('TextLine.totalDescent'); michael@0: return this._totalDescent; michael@0: } michael@0: }, michael@0: totalHeight: { michael@0: get: function totalHeight() { michael@0: notImplemented('TextLine.totalHeight'); michael@0: return this._totalHeight; michael@0: } michael@0: }, michael@0: textBlockBeginIndex: { michael@0: get: function textBlockBeginIndex() { michael@0: notImplemented('TextLine.textBlockBeginIndex'); michael@0: return this._textBlockBeginIndex; michael@0: } michael@0: }, michael@0: rawTextLength: { michael@0: get: function rawTextLength() { michael@0: somewhatImplemented('TextLine.rawTextLength'); michael@0: return this._rawTextLength; michael@0: } michael@0: }, michael@0: specifiedWidth: { michael@0: get: function specifiedWidth() { michael@0: somewhatImplemented('TextLine.specifiedWidth'); michael@0: return this._specifiedWidth; michael@0: } michael@0: }, michael@0: unjustifiedTextWidth: { michael@0: get: function unjustifiedTextWidth() { michael@0: somewhatImplemented('TextLine.unjustifiedTextWidth'); michael@0: return this._unjustifiedTextWidth; michael@0: } michael@0: }, michael@0: validity: { michael@0: get: function validity() { michael@0: return this._validity; michael@0: }, michael@0: set: function validity(value) { michael@0: somewhatImplemented('TextLine.validity'); michael@0: this._validity = value; michael@0: } michael@0: }, michael@0: atomCount: { michael@0: get: function atomCount() { michael@0: notImplemented('TextLine.atomCount'); michael@0: return this._atomCount; michael@0: } michael@0: }, michael@0: mirrorRegions: { michael@0: get: function mirrorRegions() { michael@0: notImplemented('TextLine.mirrorRegions'); michael@0: return this._mirrorRegions; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var ContextMenuDefinition = function () { michael@0: return { michael@0: __class__: 'flash.ui.ContextMenu', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: _checkSupported: function _checkSupported() { michael@0: notImplemented('ContextMenu._checkSupported'); michael@0: } michael@0: }, michael@0: instance: { michael@0: cloneLinkAndClipboardProperties: function cloneLinkAndClipboardProperties(c) { michael@0: notImplemented('ContextMenu.cloneLinkAndClipboardProperties'); michael@0: }, michael@0: builtInItems: { michael@0: get: function builtInItems() { michael@0: somewhatImplemented('ContextMenu.builtInItems'); michael@0: return this._builtInItems; michael@0: }, michael@0: set: function builtInItems(value) { michael@0: somewhatImplemented('ContextMenu.builtInItems'); michael@0: this._builtInItems = value; michael@0: } michael@0: }, michael@0: customItems: { michael@0: get: function customItems() { michael@0: somewhatImplemented('ContextMenu.customItems'); michael@0: return this._customItems; michael@0: }, michael@0: set: function customItems(value) { michael@0: somewhatImplemented('ContextMenu.customItems'); michael@0: this._customItems = value; michael@0: } michael@0: }, michael@0: link: { michael@0: get: function link() { michael@0: notImplemented('ContextMenu.link'); michael@0: return this._link; michael@0: }, michael@0: set: function link(value) { michael@0: notImplemented('ContextMenu.link'); michael@0: this._link = value; michael@0: } michael@0: }, michael@0: clipboardMenu: { michael@0: get: function clipboardMenu() { michael@0: notImplemented('ContextMenu.clipboardMenu'); michael@0: return this._clipboardMenu; michael@0: }, michael@0: set: function clipboardMenu(value) { michael@0: notImplemented('ContextMenu.clipboardMenu'); michael@0: this._clipboardMenu = value; michael@0: } michael@0: }, michael@0: clipboardItems: { michael@0: get: function clipboardItems() { michael@0: notImplemented('ContextMenu.clipboardItems'); michael@0: return this._clipboardItems; michael@0: }, michael@0: set: function clipboardItems(value) { michael@0: notImplemented('ContextMenu.clipboardItems'); michael@0: this._clipboardItems = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var ContextMenuItemDefinition = function () { michael@0: return { michael@0: __class__: 'flash.ui.ContextMenuItem', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: caption: { michael@0: get: function caption() { michael@0: somewhatImplemented('ContextMenuItem.caption'); michael@0: return this._caption; michael@0: }, michael@0: set: function caption(value) { michael@0: somewhatImplemented('ContextMenuItem.caption'); michael@0: this._caption = value; michael@0: } michael@0: }, michael@0: separatorBefore: { michael@0: get: function separatorBefore() { michael@0: somewhatImplemented('ContextMenuItem.separatorBefore'); michael@0: return this._separatorBefore; michael@0: }, michael@0: set: function separatorBefore(value) { michael@0: somewhatImplemented('ContextMenuItem.separatorBefore'); michael@0: this._separatorBefore = value; michael@0: } michael@0: }, michael@0: visible: { michael@0: get: function visible() { michael@0: somewhatImplemented('ContextMenuItem.visible'); michael@0: return this._visible; michael@0: }, michael@0: set: function visible(value) { michael@0: somewhatImplemented('ContextMenuItem.visible'); michael@0: this._visible = value; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: var ShumwayKeyboardListener = { michael@0: _lastKeyCode: 0, michael@0: _captureKeyPress: false, michael@0: _charCodeMap: [], michael@0: focus: null, michael@0: handleEvent: function (domEvt) { michael@0: var keyCode = domEvt.keyCode; michael@0: if (domEvt.type === 'keydown') { michael@0: this._lastKeyCode = keyCode; michael@0: this._captureKeyPress = keyCode === 8 || keyCode === 9 || keyCode === 13 || keyCode === 32 || keyCode >= 48 && keyCode <= 90 || keyCode > 145; michael@0: if (this._captureKeyPress) { michael@0: return; michael@0: } michael@0: this._charCodeMap[keyCode] = 0; michael@0: } else if (domEvt.type === 'keypress') { michael@0: if (this._captureKeyPress) { michael@0: keyCode = this._lastKeyCode; michael@0: this._charCodeMap[keyCode] = domEvt.charCode; michael@0: } else { michael@0: return; michael@0: } michael@0: } michael@0: if (this.focus) { michael@0: this.focus._dispatchEvent(new flash.events.KeyboardEvent(domEvt.type === 'keyup' ? 'keyUp' : 'keyDown', true, false, domEvt.type === 'keyup' ? this._charCodeMap[keyCode] : domEvt.charCode, domEvt.type === 'keyup' ? domEvt.keyCode : this._lastKeyCode, domEvt.keyLocation, domEvt.ctrlKey, domEvt.altKey, domEvt.shiftKey)); michael@0: } michael@0: } michael@0: }; michael@0: window.addEventListener('keydown', ShumwayKeyboardListener); michael@0: window.addEventListener('keypress', ShumwayKeyboardListener); michael@0: window.addEventListener('keyup', ShumwayKeyboardListener); michael@0: var KeyboardDefinition = function () { michael@0: var def = { michael@0: get capsLock() { michael@0: return false; michael@0: }, michael@0: get hasVirtualKeyboard() { michael@0: return false; michael@0: }, michael@0: get numLock() { michael@0: return false; michael@0: }, michael@0: get physicalKeyboardType() { michael@0: return 'alphanumeric'; michael@0: }, michael@0: get isAccessible() { michael@0: return true; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: script: { michael@0: static: scriptProperties('public', [ michael@0: 'A', michael@0: 'ALTERNATE', michael@0: 'AUDIO', michael@0: 'B', michael@0: 'BACK', michael@0: 'BACKQUOTE', michael@0: 'BACKSLASH', michael@0: 'BACKSPACE', michael@0: 'BLUE', michael@0: 'C', michael@0: 'CAPS_LOCK', michael@0: 'CHANNEL_DOWN', michael@0: 'CHANNEL_UP', michael@0: 'COMMA', michael@0: 'COMMAND', michael@0: 'CONTROL', michael@0: 'D', michael@0: 'DELETE', michael@0: 'DOWN', michael@0: 'DVR', michael@0: 'E', michael@0: 'END', michael@0: 'ENTER', michael@0: 'EQUAL', michael@0: 'ESCAPE', michael@0: 'EXIT', michael@0: 'F', michael@0: 'F1', michael@0: 'F10', michael@0: 'F11', michael@0: 'F12', michael@0: 'F13', michael@0: 'F14', michael@0: 'F15', michael@0: 'F2', michael@0: 'F3', michael@0: 'F4', michael@0: 'F5', michael@0: 'F6', michael@0: 'F7', michael@0: 'F8', michael@0: 'F9', michael@0: 'FAST_FORWARD', michael@0: 'G', michael@0: 'GREEN', michael@0: 'GUIDE', michael@0: 'H', michael@0: 'HELP', michael@0: 'HOME', michael@0: 'I', michael@0: 'INFO', michael@0: 'INPUT', michael@0: 'INSERT', michael@0: 'J', michael@0: 'K', michael@0: 'KEYNAME_BEGIN', michael@0: 'KEYNAME_BREAK', michael@0: 'KEYNAME_CLEARDISPLAY', michael@0: 'KEYNAME_CLEARLINE', michael@0: 'KEYNAME_DELETE', michael@0: 'KEYNAME_DELETECHAR', michael@0: 'KEYNAME_DELETELINE', michael@0: 'KEYNAME_DOWNARROW', michael@0: 'KEYNAME_END', michael@0: 'KEYNAME_EXECUTE', michael@0: 'KEYNAME_F1', michael@0: 'KEYNAME_F10', michael@0: 'KEYNAME_F11', michael@0: 'KEYNAME_F12', michael@0: 'KEYNAME_F13', michael@0: 'KEYNAME_F14', michael@0: 'KEYNAME_F15', michael@0: 'KEYNAME_F16', michael@0: 'KEYNAME_F17', michael@0: 'KEYNAME_F18', michael@0: 'KEYNAME_F19', michael@0: 'KEYNAME_F2', michael@0: 'KEYNAME_F20', michael@0: 'KEYNAME_F21', michael@0: 'KEYNAME_F22', michael@0: 'KEYNAME_F23', michael@0: 'KEYNAME_F24', michael@0: 'KEYNAME_F25', michael@0: 'KEYNAME_F26', michael@0: 'KEYNAME_F27', michael@0: 'KEYNAME_F28', michael@0: 'KEYNAME_F29', michael@0: 'KEYNAME_F3', michael@0: 'KEYNAME_F30', michael@0: 'KEYNAME_F31', michael@0: 'KEYNAME_F32', michael@0: 'KEYNAME_F33', michael@0: 'KEYNAME_F34', michael@0: 'KEYNAME_F35', michael@0: 'KEYNAME_F4', michael@0: 'KEYNAME_F5', michael@0: 'KEYNAME_F6', michael@0: 'KEYNAME_F7', michael@0: 'KEYNAME_F8', michael@0: 'KEYNAME_F9', michael@0: 'KEYNAME_FIND', michael@0: 'KEYNAME_HELP', michael@0: 'KEYNAME_HOME', michael@0: 'KEYNAME_INSERT', michael@0: 'KEYNAME_INSERTCHAR', michael@0: 'KEYNAME_INSERTLINE', michael@0: 'KEYNAME_LEFTARROW', michael@0: 'KEYNAME_MENU', michael@0: 'KEYNAME_MODESWITCH', michael@0: 'KEYNAME_NEXT', michael@0: 'KEYNAME_PAGEDOWN', michael@0: 'KEYNAME_PAGEUP', michael@0: 'KEYNAME_PAUSE', michael@0: 'KEYNAME_PREV', michael@0: 'KEYNAME_PRINT', michael@0: 'KEYNAME_PRINTSCREEN', michael@0: 'KEYNAME_REDO', michael@0: 'KEYNAME_RESET', michael@0: 'KEYNAME_RIGHTARROW', michael@0: 'KEYNAME_SCROLLLOCK', michael@0: 'KEYNAME_SELECT', michael@0: 'KEYNAME_STOP', michael@0: 'KEYNAME_SYSREQ', michael@0: 'KEYNAME_SYSTEM', michael@0: 'KEYNAME_UNDO', michael@0: 'KEYNAME_UPARROW', michael@0: 'KEYNAME_USER', michael@0: 'L', michael@0: 'LAST', michael@0: 'LEFT', michael@0: 'LEFTBRACKET', michael@0: 'LIVE', michael@0: 'M', michael@0: 'MASTER_SHELL', michael@0: 'MENU', michael@0: 'MINUS', michael@0: 'N', michael@0: 'NEXT', michael@0: 'NUMBER_0', michael@0: 'NUMBER_1', michael@0: 'NUMBER_2', michael@0: 'NUMBER_3', michael@0: 'NUMBER_4', michael@0: 'NUMBER_5', michael@0: 'NUMBER_6', michael@0: 'NUMBER_7', michael@0: 'NUMBER_8', michael@0: 'NUMBER_9', michael@0: 'NUMPAD', michael@0: 'NUMPAD_0', michael@0: 'NUMPAD_1', michael@0: 'NUMPAD_2', michael@0: 'NUMPAD_3', michael@0: 'NUMPAD_4', michael@0: 'NUMPAD_5', michael@0: 'NUMPAD_6', michael@0: 'NUMPAD_7', michael@0: 'NUMPAD_8', michael@0: 'NUMPAD_9', michael@0: 'NUMPAD_ADD', michael@0: 'NUMPAD_DECIMAL', michael@0: 'NUMPAD_DIVIDE', michael@0: 'NUMPAD_ENTER', michael@0: 'NUMPAD_MULTIPLY', michael@0: 'NUMPAD_SUBTRACT', michael@0: 'O', michael@0: 'P', michael@0: 'PAGE_DOWN', michael@0: 'PAGE_UP', michael@0: 'PAUSE', michael@0: 'PERIOD', michael@0: 'PLAY', michael@0: 'PREVIOUS', michael@0: 'Q', michael@0: 'QUOTE', michael@0: 'R', michael@0: 'RECORD', michael@0: 'RED', michael@0: 'REWIND', michael@0: 'RIGHT', michael@0: 'RIGHTBRACKET', michael@0: 'S', michael@0: 'SEARCH', michael@0: 'SEMICOLON', michael@0: 'SETUP', michael@0: 'SHIFT', michael@0: 'SKIP_BACKWARD', michael@0: 'SKIP_FORWARD', michael@0: 'SLASH', michael@0: 'SPACE', michael@0: 'STOP', michael@0: 'STRING_BEGIN', michael@0: 'STRING_BREAK', michael@0: 'STRING_CLEARDISPLAY', michael@0: 'STRING_CLEARLINE', michael@0: 'STRING_DELETE', michael@0: 'STRING_DELETECHAR', michael@0: 'STRING_DELETELINE', michael@0: 'STRING_DOWNARROW', michael@0: 'STRING_END', michael@0: 'STRING_EXECUTE', michael@0: 'STRING_F1', michael@0: 'STRING_F10', michael@0: 'STRING_F11', michael@0: 'STRING_F12', michael@0: 'STRING_F13', michael@0: 'STRING_F14', michael@0: 'STRING_F15', michael@0: 'STRING_F16', michael@0: 'STRING_F17', michael@0: 'STRING_F18', michael@0: 'STRING_F19', michael@0: 'STRING_F2', michael@0: 'STRING_F20', michael@0: 'STRING_F21', michael@0: 'STRING_F22', michael@0: 'STRING_F23', michael@0: 'STRING_F24', michael@0: 'STRING_F25', michael@0: 'STRING_F26', michael@0: 'STRING_F27', michael@0: 'STRING_F28', michael@0: 'STRING_F29', michael@0: 'STRING_F3', michael@0: 'STRING_F30', michael@0: 'STRING_F31', michael@0: 'STRING_F32', michael@0: 'STRING_F33', michael@0: 'STRING_F34', michael@0: 'STRING_F35', michael@0: 'STRING_F4', michael@0: 'STRING_F5', michael@0: 'STRING_F6', michael@0: 'STRING_F7', michael@0: 'STRING_F8', michael@0: 'STRING_F9', michael@0: 'STRING_FIND', michael@0: 'STRING_HELP', michael@0: 'STRING_HOME', michael@0: 'STRING_INSERT', michael@0: 'STRING_INSERTCHAR', michael@0: 'STRING_INSERTLINE', michael@0: 'STRING_LEFTARROW', michael@0: 'STRING_MENU', michael@0: 'STRING_MODESWITCH', michael@0: 'STRING_NEXT', michael@0: 'STRING_PAGEDOWN', michael@0: 'STRING_PAGEUP', michael@0: 'STRING_PAUSE', michael@0: 'STRING_PREV', michael@0: 'STRING_PRINT', michael@0: 'STRING_PRINTSCREEN', michael@0: 'STRING_REDO', michael@0: 'STRING_RESET', michael@0: 'STRING_RIGHTARROW', michael@0: 'STRING_SCROLLLOCK', michael@0: 'STRING_SELECT', michael@0: 'STRING_STOP', michael@0: 'STRING_SYSREQ', michael@0: 'STRING_SYSTEM', michael@0: 'STRING_UNDO', michael@0: 'STRING_UPARROW', michael@0: 'STRING_USER', michael@0: 'SUBTITLE', michael@0: 'T', michael@0: 'TAB', michael@0: 'U', michael@0: 'UP', michael@0: 'V', michael@0: 'VOD', michael@0: 'W', michael@0: 'X', michael@0: 'Y', michael@0: 'YELLOW', michael@0: 'Z', michael@0: 'CharCodeStrings' michael@0: ]) michael@0: }, michael@0: native: { michael@0: instance: { michael@0: capsLock: desc(def, 'capsLock'), michael@0: hasVirtualKeyboard: desc(def, 'hasVirtualKeyboard'), michael@0: numLock: desc(def, 'numLock'), michael@0: physicalKeyboardType: desc(def, 'physicalKeyboardType'), michael@0: isAccessible: desc(def, 'isAccessible') michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var MouseDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.ui.Mouse' michael@0: }; michael@0: function hide() { michael@0: } michael@0: function show() { michael@0: } michael@0: function registerCursor() { michael@0: notImplemented(); michael@0: } michael@0: function unregisterCursor() { michael@0: notImplemented(); michael@0: } michael@0: def.__glue__ = { michael@0: native: { michael@0: static: { michael@0: cursor: { michael@0: get: function () { michael@0: return 'auto'; michael@0: }, michael@0: set: function () { michael@0: notImplemented(); michael@0: } michael@0: }, michael@0: supportsCursor: { michael@0: get: function () { michael@0: return true; michael@0: } michael@0: }, michael@0: supportsNativeCursor: { michael@0: get: function () { michael@0: return true; michael@0: } michael@0: }, michael@0: hide: hide, michael@0: show: show, michael@0: registerCursor: registerCursor, michael@0: unregisterCursor: unregisterCursor michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var MouseCursorDataDefinition = function () { michael@0: return { michael@0: __class__: 'flash.ui.MouseCursorData', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: data: { michael@0: get: function data() { michael@0: notImplemented('MouseCursorData.data'); michael@0: return this._data; michael@0: }, michael@0: set: function data(data) { michael@0: notImplemented('MouseCursorData.data'); michael@0: this._data = data; michael@0: } michael@0: }, michael@0: hotSpot: { michael@0: get: function hotSpot() { michael@0: notImplemented('MouseCursorData.hotSpot'); michael@0: return this._hotSpot; michael@0: }, michael@0: set: function hotSpot(data) { michael@0: notImplemented('MouseCursorData.hotSpot'); michael@0: this._hotSpot = data; michael@0: } michael@0: }, michael@0: frameRate: { michael@0: get: function frameRate() { michael@0: notImplemented('MouseCursorData.frameRate'); michael@0: return this._frameRate; michael@0: }, michael@0: set: function frameRate(data) { michael@0: notImplemented('MouseCursorData.frameRate'); michael@0: this._frameRate = data; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: { michael@0: var DictionaryDefinition = function () { michael@0: return { michael@0: __class__: 'flash.utils.Dictionary', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: {}, michael@0: instance: { michael@0: init: function init(weakKeys) { michael@0: notImplemented('Dictionary.init'); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: var TimerDefinition = function () { michael@0: var def = { michael@0: __class__: 'flash.utils.Timer', michael@0: initialize: function () { michael@0: this._running = false; michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: running: { michael@0: get: function () { michael@0: return this._running; michael@0: } michael@0: }, michael@0: _start: function (delay, closure) { michael@0: this._running = true; michael@0: this.interval = setInterval(closure, delay); michael@0: }, michael@0: stop: function () { michael@0: this._running = false; michael@0: clearInterval(this.interval); michael@0: }, michael@0: _tick: function () { michael@0: if (!this._running) { michael@0: return; michael@0: } michael@0: this._dispatchEvent(new flash.events.TimerEvent('timer', true, false)); michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: { michael@0: var AccessibilityDefinition = function () { michael@0: return { michael@0: __class__: 'flash.accessibility.Accessibility', michael@0: initialize: function () { michael@0: }, michael@0: __glue__: { michael@0: native: { michael@0: static: { michael@0: sendEvent: function sendEvent(source, childID, eventType, nonHTML) { michael@0: notImplemented('Accessibility.sendEvent'); michael@0: }, michael@0: updateProperties: function updateProperties() { michael@0: notImplemented('Accessibility.updateProperties'); michael@0: }, michael@0: active: { michael@0: get: function active() { michael@0: somewhatImplemented('Accessibility.active'); michael@0: return false; michael@0: } michael@0: } michael@0: }, michael@0: instance: {} michael@0: } michael@0: } michael@0: }; michael@0: }.call(this); michael@0: } michael@0: { michael@0: var AS2ButtonDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2Button', michael@0: initialize: function () { michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: _as3Object: { michael@0: get: function () { michael@0: return this.$nativeObject; michael@0: } michael@0: }, michael@0: _init: function init(nativeButton) { michael@0: Object.defineProperty(this, '$nativeObject', { michael@0: value: nativeButton michael@0: }); michael@0: nativeButton.$as2Object = this; michael@0: initDefaultListeners(this); michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: } michael@0: var AS2GlobalsDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2Globals', michael@0: initialize: function () { michael@0: flash.text.TextFormat.prototype.asDefinePublicProperty('getTextExtent', { michael@0: value: TextFormatDefinition.as2GetTextExtent, michael@0: writable: false, michael@0: enumerable: false, michael@0: configurable: false michael@0: }); michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: ASSetPropFlags: function ASSetPropFlags(obj, children, flags, allowFalse) { michael@0: }, michael@0: _addToPendingScripts: function _addToPendingScripts(subject, fn, args) { michael@0: AS2Context.instance.addToPendingScripts(function () { michael@0: fn.apply(subject, args); michael@0: }); michael@0: }, michael@0: _setLevel: function _setLevel(level, loader) { michael@0: AS2Context.instance.stage._as2SetLevel(level, loader); michael@0: }, michael@0: trace: function (expression) { michael@0: var trace = avm2.applicationDomain.getProperty(Multiname.fromSimpleName('trace'), true, true); michael@0: trace(expression); michael@0: } michael@0: }, michael@0: static: { michael@0: _addInternalClasses: function _addInternalClasses(proto) { michael@0: proto.asSetPublicProperty('Object', Stubs.Object); michael@0: proto.asSetPublicProperty('Function', Stubs.Function); michael@0: proto.asSetPublicProperty('Array', Stubs.Array); michael@0: proto.asSetPublicProperty('Number', Stubs.Number); michael@0: proto.asSetPublicProperty('Math', avm2.systemDomain.getClass('Math')); michael@0: proto.asSetPublicProperty('Boolean', Stubs.Boolean); michael@0: proto.asSetPublicProperty('Date', Stubs.Date); michael@0: proto.asSetPublicProperty('RegExp', Stubs.RegExp); michael@0: proto.asSetPublicProperty('String', Stubs.String); michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var AS2MovieClipDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2MovieClip', michael@0: initialize: function () { michael@0: }, michael@0: _insertChildAtDepth: function _insertChildAtDepth(mc, depth) { michael@0: return this.$nativeObject._insertChildAtDepth(mc, depth); michael@0: }, michael@0: _duplicate: function _duplicate(name, depth, initObject) { michael@0: return this.$nativeObject._duplicate(name, depth, initObject); michael@0: }, michael@0: _constructSymbol: function constructSymbol(symbolId, name) { michael@0: var theClass = AS2Context.instance.classes && AS2Context.instance.classes[symbolId]; michael@0: var symbolProps = AS2Context.instance.assets[symbolId]; michael@0: var symbolClass = flash.display.MovieClip.class; michael@0: var mc = symbolClass.createAsSymbol(symbolProps); michael@0: mc._avm1SymbolClass = theClass; michael@0: symbolClass.instanceConstructor.call(mc); michael@0: this.$nativeObject.addChild(mc); michael@0: return mc; michael@0: }, michael@0: _gotoLabel: function (label) { michael@0: this.$nativeObject.gotoLabel(label); michael@0: }, michael@0: _callFrame: function callFrame(frame) { michael@0: this.$nativeObject._callFrame(frame); michael@0: }, michael@0: init: function init(nativeMovieClip) { michael@0: if (!nativeMovieClip) { michael@0: return; michael@0: } michael@0: Object.defineProperty(this, '$nativeObject', { michael@0: value: nativeMovieClip michael@0: }); michael@0: nativeMovieClip.$as2Object = this; michael@0: initDefaultListeners(this); michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: _as3Object: { michael@0: get: function () { michael@0: return this.$nativeObject; michael@0: } michael@0: }, michael@0: _init: def.init, michael@0: _insertChildAtDepth: def._insertChildAtDepth, michael@0: _duplicate: def._duplicate, michael@0: _constructSymbol: def._constructSymbol, michael@0: _callFrame: def._callFrame, michael@0: _gotoLabel: def._gotoLabel michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var AS2MovieClipLoaderDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2MovieClipLoader', michael@0: initialize: function () { michael@0: }, michael@0: get _bytesLoaded() { michael@0: return this.$nativeObject._contentLoaderInfo._bytesLoaded; michael@0: } michael@0: }; michael@0: var desc = Object.getOwnPropertyDescriptor; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: $nativeObject: { michael@0: get: function () { michael@0: return this.$nativeObject; michael@0: } michael@0: }, michael@0: _bytesLoaded: desc(def, '_bytesLoaded') michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var AS2TextFieldDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2TextField', michael@0: initialize: function () { michael@0: this._variable = ''; michael@0: } michael@0: }; michael@0: def.__glue__ = { michael@0: native: { michael@0: instance: { michael@0: variable: { michael@0: get: function () { michael@0: return this._variable; michael@0: }, michael@0: set: function (name) { michael@0: if (name === this._variable) { michael@0: return; michael@0: } michael@0: this._variable = name; michael@0: var instance = this.$nativeObject; michael@0: var hasPath = name.indexOf('.') >= 0 || name.indexOf(':') >= 0; michael@0: var clip; michael@0: if (hasPath) { michael@0: var targetPath = name.split(/[.:\/]/g); michael@0: name = targetPath.pop(); michael@0: if (targetPath[0] == '_root' || targetPath[0] === '') { michael@0: clip = instance.root._getAS2Object(); michael@0: targetPath.shift(); michael@0: if (targetPath[0] === '') { michael@0: targetPath.shift(); michael@0: } michael@0: } else { michael@0: clip = instance._parent._getAS2Object(); michael@0: } michael@0: while (targetPath.length > 0) { michael@0: var childName = targetPath.shift(); michael@0: clip = clip.asGetPublicProperty(childName) || clip[childName]; michael@0: if (!clip) { michael@0: throw new Error('Cannot find ' + childName + ' variable'); michael@0: } michael@0: } michael@0: } else { michael@0: clip = instance._parent._getAS2Object(); michael@0: } michael@0: if (!clip.asHasProperty(undefined, name, 0)) { michael@0: clip.asSetPublicProperty(name, instance.text); michael@0: } michael@0: instance._addEventListener('advanceFrame', function () { michael@0: instance.text = '' + clip.asGetPublicProperty(name); michael@0: }); michael@0: } michael@0: }, michael@0: _as3Object: { michael@0: get: function () { michael@0: return this.$nativeObject; michael@0: } michael@0: }, michael@0: _init: function init(nativeTextField) { michael@0: Object.defineProperty(this, '$nativeObject', { michael@0: value: nativeTextField michael@0: }); michael@0: nativeTextField.$as2Object = this; michael@0: initDefaultListeners(this); michael@0: } michael@0: } michael@0: }, michael@0: script: { michael@0: instance: Glue.ALL michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: var AS2UtilsDefinition = function () { michael@0: var def = { michael@0: __class__: 'avm1lib.AS2Utils', michael@0: initialize: function () { michael@0: } michael@0: }; michael@0: function installObjectMethods() { michael@0: var c = Stubs.Object, p = c.asGetPublicProperty('prototype'); michael@0: c.asSetPublicProperty('registerClass', function registerClass(name, theClass) { michael@0: var classes = AS2Context.instance.classes || (AS2Context.instance.classes = {}); michael@0: classes[name] = theClass; michael@0: }); michael@0: p.asDefinePublicProperty('addProperty', { michael@0: value: function addProperty(name, getter, setter) { michael@0: if (typeof name !== 'string' || name === '') { michael@0: return false; michael@0: } michael@0: if (typeof getter !== 'function') { michael@0: return false; michael@0: } michael@0: if (typeof setter !== 'function' && setter !== null) { michael@0: return false; michael@0: } michael@0: this.asDefinePublicProperty(name, { michael@0: get: getter, michael@0: set: setter || undefined, michael@0: configurable: true, michael@0: enumerable: true michael@0: }); michael@0: return true; michael@0: }, michael@0: writable: false, michael@0: enumerable: false, michael@0: configurable: false michael@0: }); michael@0: } michael@0: def.__glue__ = { michael@0: native: { michael@0: static: { michael@0: getAS2Object: function (nativeObject) { michael@0: return nativeObject && nativeObject._getAS2Object ? nativeObject._getAS2Object() : null; michael@0: }, michael@0: addProperty: function (obj, propertyName, getter, setter, enumerable) { michael@0: obj.asDefinePublicProperty(propertyName, { michael@0: get: getter, michael@0: set: setter || undefined, michael@0: enumerable: enumerable, michael@0: configurable: true michael@0: }); michael@0: }, michael@0: resolveTarget: function (target_mc) { michael@0: return AS2Context.instance.resolveTarget(target_mc); michael@0: }, michael@0: resolveLevel: function (level) { michael@0: return AS2Context.instance.resolveLevel(level); michael@0: }, michael@0: currentStage: { michael@0: get: function () { michael@0: return AS2Context.instance.stage; michael@0: } michael@0: }, michael@0: _installObjectMethods: installObjectMethods michael@0: } michael@0: } michael@0: }; michael@0: return def; michael@0: }.call(this); michael@0: function initDefaultListeners(thisArg) { michael@0: var defaultListeners = thisArg.asGetPublicProperty('$defaultListeners'); michael@0: if (!defaultListeners) { michael@0: return; michael@0: } michael@0: for (var i = 0; i < defaultListeners.length; i++) { michael@0: var p = defaultListeners[i]; michael@0: p.asGetPublicProperty('setter').call(thisArg, p.value); michael@0: } michael@0: } michael@0: function bindNativeClassDefinition(nativeName, definition) { michael@0: natives[nativeName] = function (domain, scope, instanceConstructor, baseClass) { michael@0: var c = new Class(undefined, instanceConstructor, ApplicationDomain.coerceCallable); michael@0: c.extend(baseClass); michael@0: c.linkNatives(definition); michael@0: return c; michael@0: }; michael@0: } michael@0: var Stubs = new function () { michael@0: var that = this; michael@0: var definitions = createEmptyObject(); michael@0: var DEFAULT_DEFINITION = { michael@0: __glue__: { michael@0: script: { michael@0: instance: Glue.ALL, michael@0: static: Glue.ALL michael@0: } michael@0: } michael@0: }; michael@0: this.getClassNames = function () { michael@0: return Object.keys(definitions); michael@0: }; michael@0: this.onClassCreated = function (eventType, cls) { michael@0: var classOriginalName = cls.classInfo.instanceInfo.name.getOriginalName(); michael@0: if (classOriginalName in definitions) { michael@0: cls.link(definitions[classOriginalName] || DEFAULT_DEFINITION); michael@0: } michael@0: }; michael@0: function makeStub(container, classSimpleName, shortName) { michael@0: Object.defineProperty(container, shortName, { michael@0: get: function () { michael@0: var cls = avm2.systemDomain.getClass(classSimpleName); michael@0: true; michael@0: Object.defineProperty(container, shortName, { michael@0: value: cls.instanceConstructor, michael@0: writable: false michael@0: }); michael@0: return container[shortName]; michael@0: }, michael@0: configurable: true michael@0: }); michael@0: } michael@0: [ michael@0: 'Boolean', michael@0: 'Date', michael@0: 'String', michael@0: 'Function', michael@0: 'Object', michael@0: 'Number', michael@0: 'Math', michael@0: 'Array', michael@0: 'RegExp' michael@0: ].forEach(function (classSimpleName) { michael@0: makeStub(that, classSimpleName, classSimpleName); michael@0: }); michael@0: [ michael@0: 'Error', michael@0: 'DefinitionError', michael@0: 'EvalError', michael@0: 'RangeError', michael@0: 'ReferenceError', michael@0: 'SecurityError', michael@0: 'SyntaxError', michael@0: 'TypeError', michael@0: 'URIError', michael@0: 'VerifyError', michael@0: 'UninitializedError', michael@0: 'ArgumentError' michael@0: ].forEach(function (classSimpleName) { michael@0: makeStub(that, classSimpleName, classSimpleName); michael@0: }); michael@0: function M(classSimpleName, nativeName, definition) { michael@0: return { michael@0: classSimpleName: classSimpleName, michael@0: nativeName: nativeName, michael@0: definition: definition michael@0: }; michael@0: } michael@0: [ michael@0: M('flash.display.DisplayObject', 'DisplayObjectClass', DisplayObjectDefinition), michael@0: M('flash.display.InteractiveObject', 'InteractiveObjectClass', InteractiveObjectDefinition), michael@0: M('flash.display.DisplayObjectContainer', 'ContainerClass', DisplayObjectContainerDefinition), michael@0: M('flash.display.Sprite', 'SpriteClass', SpriteDefinition), michael@0: M('flash.display.MovieClip', 'MovieClipClass', MovieClipDefinition), michael@0: M('flash.display.Shape', 'ShapeClass', ShapeDefinition), michael@0: M('flash.display.Bitmap', 'BitmapClass', BitmapDefinition), michael@0: M('flash.display.BitmapData', 'BitmapDataClass', BitmapDataDefinition), michael@0: M('flash.display.Stage', 'StageClass', StageDefinition), michael@0: M('flash.display.Loader', 'LoaderClass', LoaderDefinition), michael@0: M('flash.display.LoaderInfo', 'LoaderInfoClass', LoaderInfoDefinition), michael@0: M('flash.display.Graphics', 'GraphicsClass', GraphicsDefinition), michael@0: M('flash.display.SimpleButton', 'SimpleButtonClass', SimpleButtonDefinition), michael@0: M('flash.display.MorphShape', 'MorphShapeClass', MorphShapeDefinition), michael@0: M('flash.display.NativeMenu', 'MenuClass', NativeMenuDefinition), michael@0: M('flash.display.NativeMenuItem', 'MenuItemClass', NativeMenuItemDefinition), michael@0: M('flash.display.FrameLabel', 'FrameLabelClass', FrameLabelDefinition), michael@0: M('flash.display.Scene'), michael@0: M('flash.display.BlendMode'), michael@0: M('flash.display.Shader', 'ShaderClass', ShaderDefinition), michael@0: M('flash.display.ShaderData', 'ShaderDataClass', ShaderDataDefinition), michael@0: M('flash.filters.BevelFilter', 'BevelFilterClass', BevelFilterDefinition), michael@0: M('flash.filters.BitmapFilter', 'BitmapFilterClass', BitmapFilterDefinition), michael@0: M('flash.filters.BlurFilter', 'BlurFilterClass', BlurFilterDefinition), michael@0: M('flash.filters.ColorMatrixFilter', 'ColorMatrixFilterClass', ColorMatrixFilterDefinition), michael@0: M('flash.filters.ConvolutionFilter', 'ConvolutionFilterClass', ConvolutionFilterDefinition), michael@0: M('flash.filters.DisplacementMapFilter', 'DisplacementMapFilterClass', DisplacementMapFilterDefinition), michael@0: M('flash.filters.DropShadowFilter', 'DropShadowFilterClass', DropShadowFilterDefinition), michael@0: M('flash.filters.GlowFilter', 'GlowFilterClass', GlowFilterDefinition), michael@0: M('flash.filters.GradientBevelFilter', 'GradientBevelFilterClass', GradientBevelFilterDefinition), michael@0: M('flash.filters.GradientGlowFilter', 'GradientGlowFilterClass', GradientGlowFilterDefinition), michael@0: M('flash.filters.ShaderFilter', 'ShaderFilterClass', ShaderFilterDefinition), michael@0: M('flash.geom.Point', 'PointClass', PointDefinition), michael@0: M('flash.geom.Rectangle', 'RectangleClass', RectangleDefinition), michael@0: M('flash.geom.Matrix', 'MatrixClass', MatrixDefinition), michael@0: M('flash.geom.Matrix3D', 'Matrix3DClass', Matrix3DDefinition), michael@0: M('flash.geom.Vector3D', 'Vector3DClass', Vector3DDefinition), michael@0: M('flash.geom.Transform', 'TransformClass', TransformDefinition), michael@0: M('flash.geom.ColorTransform', 'ColorTransformClass', ColorTransformDefinition), michael@0: M('flash.events.EventDispatcher', 'EventDispatcherClass', EventDispatcherDefinition), michael@0: M('flash.events.Event', 'EventClass', EventDefinition), michael@0: M('flash.events.IOErrorEvent'), michael@0: M('flash.events.NetStatusEvent'), michael@0: M('flash.events.KeyboardEvent', 'KeyboardEventClass', KeyboardEventDefinition), michael@0: M('flash.events.MouseEvent', 'MouseEventClass', MouseEventDefinition), michael@0: M('flash.events.TextEvent', 'TextEventClass', TextEventDefinition), michael@0: M('flash.events.TimerEvent', 'TimerEventClass', TimerEventDefinition), michael@0: M('flash.events.ProgressEvent'), michael@0: M('flash.events.NetStatusEvent'), michael@0: M('flash.external.ExternalInterface', 'ExternalInterfaceClass', ExternalInterfaceDefinition), michael@0: M('flash.ui.ContextMenu', 'ContextMenuClass', ContextMenuDefinition), michael@0: M('flash.ui.ContextMenuItem', 'ContextMenuItemClass', ContextMenuItemDefinition), michael@0: M('flash.ui.Keyboard', 'KeyboardClass', KeyboardDefinition), michael@0: M('flash.ui.Mouse', 'MouseClass', MouseDefinition), michael@0: M('flash.ui.MouseCursorData', 'MouseCursorDataClass', MouseCursorDataDefinition), michael@0: M('flash.text.Font', 'FontClass', FontDefinition), michael@0: M('flash.text.TextField', 'TextFieldClass', TextFieldDefinition), michael@0: M('flash.text.StaticText', 'StaticTextClass', StaticTextDefinition), michael@0: M('flash.text.StyleSheet', 'StyleSheetClass', StyleSheetDefinition), michael@0: M('flash.text.TextFormat', 'TextFormatClass', TextFormatDefinition), michael@0: M('flash.text.TextLineMetrics'), michael@0: M('flash.text.engine.ContentElement', 'ContentElementClass', ContentElementDefinition), michael@0: M('flash.text.engine.ElementFormat', 'ElementFormatClass', ElementFormatDefinition), michael@0: M('flash.text.engine.FontDescription', 'FontDescriptionClass', FontDescriptionDefinition), michael@0: M('flash.text.engine.GroupElement', 'GroupElementClass', GroupElementDefinition), michael@0: M('flash.text.engine.SpaceJustifier', 'SpaceJustifierClass', SpaceJustifierDefinition), michael@0: M('flash.text.engine.TextBlock', 'TextBlockClass', TextBlockDefinition), michael@0: M('flash.text.engine.TextElement', 'TextElementClass', TextElementDefinition), michael@0: M('flash.text.engine.TextJustifier', 'TextJustifierClass', TextJustifierDefinition), michael@0: M('flash.text.engine.TextLine', 'TextLineClass', TextLineDefinition), michael@0: M('flash.media.Sound', 'SoundClass', SoundDefinition), michael@0: M('flash.media.SoundChannel', 'SoundChannelClass', SoundChannelDefinition), michael@0: M('flash.media.SoundMixer', 'SoundMixerClass', SoundMixerDefinition), michael@0: M('flash.media.SoundTransform', 'SoundTransformClass', SoundTransformDefinition), michael@0: M('flash.media.Video', 'VideoClass', VideoDefinition), michael@0: M('flash.media.ID3Info', 'ID3InfoClass', ID3InfoDefinition), michael@0: M('flash.media.Microphone', 'MicrophoneClass', MicrophoneDefinition), michael@0: M('flash.net.FileFilter', 'FileFilterClass', FileFilterDefinition), michael@0: M('flash.net.NetConnection', 'NetConnectionClass', NetConnectionDefinition), michael@0: M('flash.net.NetStream', 'NetStreamClass', NetStreamDefinition), michael@0: M('flash.net.Responder', 'ResponderClass', ResponderDefinition), michael@0: M('flash.net.URLRequest', 'URLRequestClass', URLRequestDefinition), michael@0: M('flash.net.URLStream', 'URLStreamClass', URLStreamDefinition), michael@0: M('flash.net.URLLoader', 'URLLoaderClass', URLLoaderDefinition), michael@0: M('flash.net.SharedObject', 'SharedObjectClass', SharedObjectDefinition), michael@0: M('flash.net.ObjectEncoding', 'ObjectEncodingClass', ObjectEncodingDefinition), michael@0: M('flash.net.LocalConnection', 'LocalConnectionClass', LocalConnectionDefinition), michael@0: M('flash.net.Socket', 'SocketClass', SocketDefinition), michael@0: M('flash.net.URLVariables'), michael@0: M('packageInternal flash.system.FSCommand', 'FSCommandClass', FSCommandDefinition), michael@0: M('flash.system.Capabilities', 'CapabilitiesClass', CapabilitiesDefinition), michael@0: M('flash.system.System', 'SystemClass', SystemDefinition), michael@0: M('flash.system.Security', 'SecurityClass', SecurityDefinition), michael@0: M('flash.system.SecurityDomain', 'SecurityDomainClass', SecurityDomainDefinition), michael@0: M('flash.system.ApplicationDomain', 'ApplicationDomainClass', ApplicationDomainDefinition), michael@0: M('flash.accessibility.Accessibility', 'AccessibilityClass', AccessibilityDefinition), michael@0: M('flash.utils.Timer', 'TimerClass', TimerDefinition), michael@0: M('avm1lib.AS2Utils', 'AS2Utils', AS2UtilsDefinition), michael@0: M('avm1lib.AS2Broadcaster'), michael@0: M('avm1lib.AS2Key'), michael@0: M('avm1lib.AS2Mouse'), michael@0: M('avm1lib.AS2MovieClip', 'AS2MovieClip', AS2MovieClipDefinition), michael@0: M('avm1lib.AS2Button', 'AS2Button', AS2ButtonDefinition), michael@0: M('avm1lib.AS2TextField', 'AS2TextField', AS2TextFieldDefinition), michael@0: M('avm1lib.AS2Stage'), michael@0: M('avm1lib.AS2System'), michael@0: M('avm1lib.AS2Color'), michael@0: M('avm1lib.AS2Globals', 'AS2Globals', AS2GlobalsDefinition), michael@0: M('avm1lib.AS2MovieClipLoader', 'AS2MovieClipLoader', AS2MovieClipLoaderDefinition) michael@0: ].forEach(function (m) { michael@0: var className = Multiname.fromSimpleName(m.classSimpleName); michael@0: var path = className.getOriginalName().split('.'); michael@0: var container = this; michael@0: for (var i = 0, j = path.length - 1; i < j; i++) { michael@0: if (!container[path[i]]) { michael@0: container[path[i]] = {}; michael@0: } michael@0: container = container[path[i]]; michael@0: } michael@0: makeStub(container, m.classSimpleName, path[path.length - 1]); michael@0: if (m.nativeName) { michael@0: bindNativeClassDefinition(m.nativeName, m.definition); michael@0: } michael@0: definitions[className.getOriginalName()] = m.definition; michael@0: }); michael@0: }(); michael@0: natives['FlashUtilScript::getAliasName'] = function (domain, scope, instanceConstructor, baseClass) { michael@0: return function getAliasName(value) { michael@0: return value.debugName; michael@0: }; michael@0: }; michael@0: natives['FlashUtilScript::getDefinitionByName'] = natives.getDefinitionByName; michael@0: natives['FlashUtilScript::getTimer'] = function GetTimerMethod(domain, scope, instanceConstructor, baseClass) { michael@0: var start = Date.now(); michael@0: return function getTimer() { michael@0: return Date.now() - start; michael@0: }; michael@0: }; michael@0: natives['FlashUtilScript::escapeMultiByte'] = function EscapeMultiByteMethod(domain, scope, instanceConstructor, baseClass) { michael@0: return escape; michael@0: }; michael@0: natives['FlashUtilScript::unescapeMultiByte'] = function UnescapeMultiByteMethod(domain, scope, instanceConstructor, baseClass) { michael@0: return unescape; michael@0: }; michael@0: natives['FlashNetScript::navigateToURL'] = function GetNavigateToURLMethod(domain, scope, instanceConstructor, baseClass) { michael@0: return function navigateToURL(request, window_) { michael@0: if (request === null || request === undefined) { michael@0: throwError('TypeError', Errors.NullPointerError, 'request'); michael@0: } michael@0: var RequestClass = avm2.systemDomain.getClass('flash.net.URLRequest'); michael@0: if (!RequestClass.isInstanceOf(request)) { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, request, 'flash.net.URLRequest'); michael@0: } michael@0: var url = request.url; michael@0: if (/^fscommand:/i.test(url)) { michael@0: var fscommand = avm2.applicationDomain.getProperty(Multiname.fromSimpleName('flash.system.fscommand'), true, true); michael@0: fscommand.call(null, url.substring('fscommand:'.length), window_); michael@0: return; michael@0: } michael@0: var targetWindow = window_ || '_parent'; michael@0: window.open(FileLoadingService.resolveUrl(url), targetWindow); michael@0: }; michael@0: }; michael@0: natives['FlashNetScript::sendToURL'] = function GetSendToURLMethod(domain, scope, instanceConstructor, baseClass) { michael@0: return function sendToURL(request) { michael@0: if (request === null || request === undefined) { michael@0: throwError('TypeError', Errors.NullPointerError, 'request'); michael@0: } michael@0: var RequestClass = avm2.systemDomain.getClass('flash.net.URLRequest'); michael@0: if (!RequestClass.isInstanceOf(request)) { michael@0: throwError('TypeError', Errors.CheckTypeFailedError, request, 'flash.net.URLRequest'); michael@0: } michael@0: var session = FileLoadingService.createSession(); michael@0: session.onprogress = function () { michael@0: }; michael@0: session.open(request); michael@0: }; michael@0: }; michael@0: natives['Toplevel::registerClassAlias'] = function GetRegisterClassAliasMethod(domain, scope, instance, baseClass) { michael@0: return function registerClassAlias(aliasName, classObject) { michael@0: if (!aliasName) { michael@0: throwError('TypeError', Errors.NullPointerError, 'aliasName'); michael@0: } michael@0: if (!classObject) { michael@0: throwError('TypeError', Errors.NullPointerError, 'classObject'); michael@0: } michael@0: AMFUtils.aliasesCache.classes.set(classObject, aliasName); michael@0: AMFUtils.aliasesCache.names[aliasName] = classObject; michael@0: }; michael@0: }; michael@0: natives['Toplevel::getClassByAlias'] = function GetGetClassByAliasMethod(domain, scope, instance, baseClass) { michael@0: return function getClassByAlias(aliasName) { michael@0: if (!aliasName) { michael@0: throwError('TypeError', Errors.NullPointerError, 'aliasName'); michael@0: } michael@0: var classObject = AMFUtils.aliasesCache.names[aliasName]; michael@0: if (!classObject) { michael@0: throwError('ReferenceError', Errors.ClassNotFoundError, aliasName); michael@0: } michael@0: return classObject; michael@0: }; michael@0: };